mirror of
https://git.sr.ht/~emerson/reflectionircd
synced 2025-08-05 16:59:10 +00:00
123 lines
3.7 KiB
TypeScript
123 lines
3.7 KiB
TypeScript
![]() |
export class IRCMessage {
|
||
|
constructor(
|
||
|
public tags: Map<string, string>,
|
||
|
public prefix: string,
|
||
|
public command: string,
|
||
|
public params: string[],
|
||
|
) {}
|
||
|
toString() {
|
||
|
let messageString = '';
|
||
|
if (this.tags.size !== 0) {
|
||
|
let tagArray = [];
|
||
|
for (const [key, value] of this.tags) {
|
||
|
if (value === '') {
|
||
|
tagArray.push(key);
|
||
|
}
|
||
|
else {
|
||
|
tagArray.push(`${key}=${encodeTag(value)}`);
|
||
|
}
|
||
|
}
|
||
|
messageString = `@${tagArray.join(";")} `;
|
||
|
}
|
||
|
|
||
|
if (this.prefix) {
|
||
|
messageString = `${messageString}:${this.prefix} `;
|
||
|
}
|
||
|
|
||
|
messageString = `${messageString}${this.command}`;
|
||
|
|
||
|
const params = this.params.slice();
|
||
|
|
||
|
let lastParam = params.pop();
|
||
|
if (lastParam) {
|
||
|
if (lastParam.indexOf(' ') !== -1) {
|
||
|
lastParam = `:${lastParam}`;
|
||
|
}
|
||
|
params.push(lastParam);
|
||
|
}
|
||
|
messageString = `${messageString} ${params.join(' ')}`;
|
||
|
return messageString;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function decodeTag(value: string): string {
|
||
|
const tagDecodeMap = new Map([
|
||
|
['\\:', ';'],
|
||
|
['\\s', ' '],
|
||
|
['\\\\', '\\'],
|
||
|
['\\r', '\r'],
|
||
|
['\\n', '\n'],
|
||
|
['\\', ''],
|
||
|
]);
|
||
|
return value.replace(/\\:|\\s|\\\\|\\r|\\n|\\/gi, t => tagDecodeMap.get(t) || '')
|
||
|
}
|
||
|
|
||
|
function encodeTag(value: string): string {
|
||
|
const tagEncodeMap = new Map([
|
||
|
[';', '\\:'],
|
||
|
[' ', '\\s'],
|
||
|
['\\', '\\\\'],
|
||
|
['\r', '\\r'],
|
||
|
['\n', '\\n'],
|
||
|
]);
|
||
|
return value.replace(/;| |\\|\r|\n/gi, t => tagEncodeMap.get(t) || '');
|
||
|
}
|
||
|
|
||
|
function addToTags(key: string): boolean {
|
||
|
const tagsToPass = [
|
||
|
'batch',
|
||
|
'label',
|
||
|
]
|
||
|
return (tagsToPass.includes(key) || key.startsWith('+'));
|
||
|
}
|
||
|
|
||
|
export function parseIRCMessage(rawLine: string) {
|
||
|
console.log(`RAW: ${rawLine}`);
|
||
|
let restOfMessage = rawLine;
|
||
|
let parsedTags: Map<string, string> = new Map();
|
||
|
let prefix = '';
|
||
|
let command = '';
|
||
|
let params: string[] = [];
|
||
|
if (rawLine.startsWith('@')) {
|
||
|
const tags = restOfMessage.substr(0, restOfMessage.indexOf(' '));
|
||
|
restOfMessage = restOfMessage.substr(restOfMessage.indexOf(' ')+1);
|
||
|
|
||
|
for (const tag in tags.split(';')) {
|
||
|
const valueSplit = tag.indexOf('=');
|
||
|
if (valueSplit === -1 && addToTags(tag)) {
|
||
|
parsedTags.set(tag, '');
|
||
|
continue;
|
||
|
}
|
||
|
const key = tag.substr(0, valueSplit);
|
||
|
const value = tag.substr(valueSplit);
|
||
|
if (addToTags(key))
|
||
|
parsedTags.set(key, decodeTag(value));
|
||
|
}
|
||
|
}
|
||
|
if (restOfMessage.startsWith(':')) {
|
||
|
prefix = restOfMessage.substr(0, restOfMessage.indexOf(' '));
|
||
|
restOfMessage = restOfMessage.substr(restOfMessage.indexOf(' ')+1);
|
||
|
}
|
||
|
|
||
|
if (restOfMessage.indexOf(' ') === -1) {
|
||
|
command = restOfMessage;
|
||
|
console.log(parsedTags, prefix, command, params);
|
||
|
return new IRCMessage(parsedTags, prefix, command, params);
|
||
|
}
|
||
|
|
||
|
command = restOfMessage.substr(0, restOfMessage.indexOf(' '));
|
||
|
restOfMessage = restOfMessage.substr(restOfMessage.indexOf(' ') + 1);
|
||
|
|
||
|
let lastParam = '';
|
||
|
if (restOfMessage.indexOf(' :') !== -1) {
|
||
|
lastParam = restOfMessage.substr(restOfMessage.indexOf(' :') + 2);
|
||
|
restOfMessage = restOfMessage.substr(0, restOfMessage.indexOf(' :'));
|
||
|
}
|
||
|
|
||
|
params = restOfMessage.split(' ');
|
||
|
if (lastParam !== '') {
|
||
|
params.push(lastParam);
|
||
|
}
|
||
|
console.log(parsedTags, prefix, command, params);
|
||
|
return new IRCMessage(parsedTags, prefix, command, params);
|
||
|
}
|