reflectionircd/src/Message.ts
2022-03-30 07:15:10 -04:00

123 lines
No EOL
3.8 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',
'reflectionircd.chat/delete-message',
'reflectionircd.chat/edit-message',
'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.substring(1, restOfMessage.indexOf(' '));
restOfMessage = restOfMessage.substring(restOfMessage.indexOf(' ')+1);
for (const tag of tags.split(';')) {
const valueSplit = tag.indexOf('=');
if (valueSplit === -1 && addToTags(tag)) {
parsedTags.set(tag, '');
continue;
}
const key = tag.substring(0, valueSplit);
const value = tag.substring(valueSplit+1);
if (addToTags(key))
parsedTags.set(key, decodeTag(value));
}
}
if (restOfMessage.startsWith(':')) {
prefix = restOfMessage.substring(0, restOfMessage.indexOf(' '));
restOfMessage = restOfMessage.substring(restOfMessage.indexOf(' ')+1);
}
if (restOfMessage.indexOf(' ') === -1) {
command = restOfMessage;
return new IRCMessage(parsedTags, prefix, command, params);
}
command = restOfMessage.substring(0, restOfMessage.indexOf(' '));
restOfMessage = restOfMessage.substring(restOfMessage.indexOf(' ') + 1);
let lastParam = '';
if (restOfMessage.indexOf(' :') !== -1) {
lastParam = restOfMessage.substring(restOfMessage.indexOf(' :') + 2);
restOfMessage = restOfMessage.substring(0, restOfMessage.indexOf(' :'));
}
params = restOfMessage.split(' ');
if (lastParam !== '') {
params.push(lastParam);
}
//console.log(parsedTags, prefix, command, params);
return new IRCMessage(parsedTags, prefix, command, params);
}