Made packet handlers more readable.

This commit is contained in:
flash 2024-02-24 02:25:20 +00:00
parent 5b5ca888a4
commit 49f00b00d8

View file

@ -48,6 +48,8 @@ Umi.Protocol.SockChat.Protocol = function() {
let selfUserId, selfChannelName, selfPseudoChannelName;
let lastPing, lastPong, pingTimer, pingWatcher;
const handlers = {};
const stopPingWatcher = () => {
if(pingWatcher !== undefined) {
clearTimeout(pingWatcher);
@ -64,18 +66,16 @@ Umi.Protocol.SockChat.Protocol = function() {
}, 2000);
};
const send = (opcode, data) => {
if(sock === undefined)
return;
const send = (...args) => {
if(args.length < 1)
throw 'you must specify at least one argument as an opcode';
let msg = opcode;
if(data)
msg += `\t${data.join("\t")}`;
const pack = args.join("\t");
if(dumpPackets)
console.log(msg);
console.log(pack);
sock.send(msg);
sock?.send(pack);
};
const onSendPing = () => {
@ -90,7 +90,7 @@ Umi.Protocol.SockChat.Protocol = function() {
};
const sendAuth = args => {
if(selfUserId === undefined)
send('1', args);
send('1', ...args);
};
const sendMessage = text => {
if(selfUserId === undefined)
@ -99,7 +99,7 @@ Umi.Protocol.SockChat.Protocol = function() {
if(text.substring(0, 1) !== '/' && selfPseudoChannelName !== undefined)
text = `/msg ${selfPseudoChannelName} ${text}`;
send('2', [selfUserId, text]);
send('2', selfUserId, text);
};
const startKeepAlive = () => sock?.sendInterval(`0\t${selfUserId}`, futami.get('ping') * 1000);
@ -165,365 +165,398 @@ Umi.Protocol.SockChat.Protocol = function() {
};
const onMessage = ev => {
const data = ev.data.split("\t");
const args = ev.data.split("\t");
let handler = handlers;
if(dumpPackets)
console.log(data);
console.log(args);
switch(data[0]) {
case '0': // ping
lastPong = Date.now();
watchers.call('ping:recv', {
ping: lastPing,
pong: lastPong,
diff: lastPong - lastPing,
});
for(;;) {
handler = handler[args.shift()];
if(handler === undefined)
break;
case '1': // join
if(data[1] !== 'y' && data[1] !== 'n') {
watchers.call('user:add', {
msg: {
id: data[6],
time: new Date(parseInt(data[1]) * 1000),
channel: selfChannelName,
botInfo: {
type: 'join',
args: [data[3]],
},
},
user: {
id: data[2],
self: data[2] === selfUserId,
name: data[3],
colour: parseUserColour(data[4]),
perms: parseUserPerms(data[5]),
permsRaw: data[5],
},
});
} else {
if(data[1] == 'y') {
selfUserId = data[2];
selfChannelName = data[6];
watchers.call('session:start', {
wasConnected: wasConnected,
session: { success: true },
ctx: {
maxMsgLength: parseInt(data[7]),
},
user: {
id: selfUserId,
self: true,
name: data[3],
colour: parseUserColour(data[4]),
perms: parseUserPerms(data[5]),
permsRaw: data[5],
},
channel: {
name: selfChannelName,
},
});
startKeepAlive();
wasConnected = true;
} else {
wasKicked = true;
const failInfo = {
session: {
success: false,
reason: data[2],
needsAuth: data[2] === 'authfail',
},
};
if(data[3] !== undefined)
failInfo.baka = {
type: 'join',
perma: data[3] === '-1',
until: data[3] === '-1' ? undefined : new Date(parseInt(data[3]) * 1000),
};
watchers.call('session:fail', failInfo);
}
}
break;
case '2': // message
let mText = unfuckText(data[3]);
let mChannelName = selfChannelName;
if(data[5][4] !== '0') {
if(data[2] === selfUserId) {
const mTextParts = mText.split(' ');
mChannelName = `@${mTextParts.shift()}`;
mText = mTextParts.join(' ');
} else {
mChannelName = `@~${data[2]}`;
}
}
const msgInfo = {
msg: {
id: data[4],
time: new Date(parseInt(data[1]) * 1000),
channel: mChannelName,
sender: { id: data[2], },
flags: parseMsgFlags(data[5]),
flagsRaw: data[5],
isBot: data[2] === '-1',
text: mText,
},
};
if(msgInfo.msg.isBot) {
const botParts = data[3].split("\f");
msgInfo.msg.botInfo = {
isError: botParts[0] === '1',
type: botParts[1],
args: botParts.slice(2),
};
}
watchers.call('msg:add', msgInfo);
break;
case '3': // leave
watchers.call('user:remove', {
leave: { type: data[3] },
msg: {
id: data[5],
time: new Date(parseInt(data[4]) * 1000),
channel: selfChannelName,
botInfo: {
type: data[3],
args: [data[2]],
},
},
user: {
id: data[1],
self: data[1] === selfUserId,
name: data[2],
},
});
break;
case '4': // channel
switch(data[1]) {
case '0':
watchers.call('chan:add', {
channel: {
name: data[2],
hasPassword: data[3] !== '0',
isTemporary: data[4] !== '0',
},
});
break;
case '1':
watchers.call('chan:update', {
channel: {
previousName: data[2],
name: data[3],
hasPassword: data[4] !== '0',
isTemporary: data[5] !== '0',
},
});
break;
case '2':
watchers.call('chan:remove', {
channel: { name: data[2] },
});
break;
}
break;
case '5': // user move
switch(data[1]) {
case '0':
watchers.call('chan:join', {
user: {
id: data[2],
self: data[2] === selfUserId,
name: data[3],
colour: parseUserColour(data[4]),
perms: parseUserPerms(data[5]),
permsRaw: data[5],
},
msg: {
id: data[6],
channel: selfChannelName,
botInfo: {
type: 'jchan',
args: [data[3]],
},
},
});
break;
case '1':
watchers.call('chan:leave', {
user: {
id: data[2],
self: data[2] === selfUserId,
},
msg: {
id: data[3],
channel: selfChannelName,
botInfo: {
type: 'lchan',
args: [data[2]],
},
},
});
break;
case '2':
selfChannelName = data[2];
watchers.call('chan:focus', {
channel: { name: selfChannelName },
});
break;
}
break;
case '6': // message delete
watchers.call('msg:remove', {
msg: {
id: data[1],
channel: selfChannelName,
},
});
break;
case '7': // context populate
switch(data[1]) {
case '0': // users
const cpuamount = parseInt(data[2]);
for(let i = 0; i < cpuamount; ++i) {
const cpuoffset = 3 + 5 * i;
watchers.call('user:add', {
user: {
id: data[cpuoffset],
self: data[cpuoffset] === selfUserId,
name: data[cpuoffset + 1],
colour: parseUserColour(data[cpuoffset + 2]),
perms: parseUserPerms(data[cpuoffset + 3]),
permsRaw: data[cpuoffset + 3],
hidden: data[cpuoffset + 4] !== '0',
},
});
}
break;
case '1': // message
const cmMsgInfo = {
msg: {
id: data[8],
time: new Date(parseInt(data[2]) * 1000),
channel: selfChannelName,
sender: {
id: data[3],
name: data[4],
colour: parseUserColour(data[5]),
perms: parseUserColour(data[6]),
permsRaw: data[6],
},
isBot: data[3] === '-1',
silent: data[9] === '0',
flags: parseMsgFlags(data[10]),
flagsRaw: data[10],
text: unfuckText(data[7]),
},
};
const cmMsgIdFirst = cmMsgInfo.msg.id.charCodeAt(0);
if(cmMsgIdFirst < 48 || cmMsgIdFirst > 57)
cmMsgInfo.msg.id = (Math.round(Number.MIN_SAFE_INTEGER * Math.random())).toString();
if(cmMsgInfo.msg.isBot) {
const cmBotParts = data[7].split("\f");
cmMsgInfo.msg.botInfo = {
isError: cmBotParts[0] === '1',
type: cmBotParts[1],
args: cmBotParts.slice(2),
};
}
watchers.call('msg:add', cmMsgInfo);
break;
case '2': // channels
const ecpamount = parseInt(data[2]);
for(let i = 0; i < ecpamount; ++i) {
const ecpoffset = 3 + 3 * i;
watchers.call('chan:add', {
channel: {
name: data[ecpoffset],
hasPassword: data[ecpoffset + 1] !== '0',
isTemporary: data[ecpoffset + 2] !== '0',
isCurrent: data[ecpoffset] === selfChannelName,
},
});
}
watchers.call('chan:focus', {
channel: { name: selfChannelName },
});
break;
}
break;
case '8': // context clear
if(data[1] === '0' || data[1] === '3' || data[1] === '4')
watchers.call('msg:clear');
if(data[1] === '1' || data[1] === '3' || data[1] === '4')
watchers.call('user:clear');
if(data[1] === '2' || data[1] === '4')
watchers.call('chan:clear');
break;
case '9': // baka
noReconnect = true;
wasKicked = true;
const bakaInfo = {
session: { success: false },
baka: {
type: data[1] === '0' ? 'kick' : 'ban',
},
};
if(bakaInfo.baka.type === 'ban') {
bakaInfo.baka.perma = data[2] === '-1';
bakaInfo.baka.until = data[2] === '-1' ? undefined : new Date(parseInt(data[2]) * 1000);
}
watchers.call('session:term', bakaInfo);
break;
case '10': // user update
watchers.call('user:update', {
user: {
id: data[1],
self: data[1] === selfUserId,
name: data[2],
colour: parseUserColour(data[3]),
perms: parseUserPerms(data[4]),
permsRaw: data[4],
},
});
if(typeof handler === 'function') {
handler(...args);
break;
}
}
};
// pong handler
handlers['0'] = () => {
lastPong = Date.now();
watchers.call('ping:recv', {
ping: lastPing,
pong: lastPong,
diff: lastPong - lastPing,
});
};
// join/auth
handlers['1'] = (successOrTimeStamp, userIdOrReason, userNameOrExpiry, userColour, userPerms, chanNameOrMsgId, maxLength) => {
if(successOrTimeStamp === 'y') {
selfUserId = userIdOrReason;
selfChannelName = chanNameOrMsgId;
watchers.call('session:start', {
wasConnected: wasConnected,
session: { success: true },
ctx: {
maxMsgLength: parseInt(maxLength),
},
user: {
id: selfUserId,
self: true,
name: userNameOrExpiry,
colour: parseUserColour(userColour),
perms: parseUserPerms(userPerms),
permsRaw: userPerms,
},
channel: {
name: selfChannelName,
},
});
startKeepAlive();
wasConnected = true;
return;
}
if(successOrTimeStamp === 'n') {
wasKicked = true;
const failInfo = {
session: {
success: false,
reason: userIdOrReason,
needsAuth: userIdOrReason === 'authfail',
},
};
if(userNameOrExpiry !== undefined)
failInfo.baka = {
type: 'join',
perma: userNameOrExpiry === '-1',
until: userNameOrExpiry === '-1' ? undefined : new Date(parseInt(userNameOrExpiry) * 1000),
};
watchers.call('session:fail', failInfo);
return;
}
watchers.call('user:add', {
msg: {
id: chanNameOrMsgId,
time: new Date(parseInt(successOrTimeStamp) * 1000),
channel: selfChannelName,
botInfo: {
type: 'join',
args: [userNameOrExpiry],
},
},
user: {
id: userIdOrReason,
self: userIdOrReason === selfUserId,
name: userNameOrExpiry,
colour: parseUserColour(userColour),
perms: parseUserPerms(userPerms),
permsRaw: userPerms,
},
});
};
// message add
handlers['2'] = (timeStamp, userId, msgText, msgId, msgFlags) => {
let mText = unfuckText(msgText);
let mChannelName = selfChannelName;
if(msgFlags[4] !== '0') {
if(userId === selfUserId) {
const mTextParts = mText.split(' ');
mChannelName = `@${mTextParts.shift()}`;
mText = mTextParts.join(' ');
} else {
mChannelName = `@~${userId}`;
}
}
const msgInfo = {
msg: {
id: msgId,
time: new Date(parseInt(timeStamp) * 1000),
channel: mChannelName,
sender: {
id: userId,
self: userId === selfUserId,
},
flags: parseMsgFlags(msgFlags),
flagsRaw: msgFlags,
isBot: userId === '-1',
text: mText,
},
};
if(msgInfo.msg.isBot) {
const botParts = msgText.split("\f");
msgInfo.msg.botInfo = {
isError: botParts[0] === '1',
type: botParts[1],
args: botParts.slice(2),
};
}
watchers.call('msg:add', msgInfo);
};
// user leave
handlers['3'] = (userId, userName, reason, timeStamp, msgId) => {
watchers.call('user:remove', {
leave: { type: reason },
msg: {
id: msgId,
time: new Date(parseInt(timeStamp) * 1000),
channel: selfChannelName,
botInfo: {
type: reason,
args: [userName],
},
},
user: {
id: userId,
self: userId === selfUserId,
name: userName,
},
});
};
// channel add/upd/del
handlers['4'] = {};
// channel add
handlers['4']['0'] = (name, hasPass, isTemp) => {
watchers.call('chan:add', {
channel: {
name: name,
hasPassword: hasPass !== '0',
isTemporary: isTemp !== '0',
},
});
};
// channel update
handlers['4']['1'] = (prevName, name, hasPass, isTemp) => {
watchers.call('chan:update', {
channel: {
previousName: prevName,
name: name,
hasPassword: hasPass !== '0',
isTemporary: isTemp !== '0',
},
});
};
// channel remove
handlers['4']['2'] = name => {
watchers.call('chan:remove', {
channel: { name: name },
});
};
// user channel move
handlers['5'] = {};
// user join channel
handlers['5']['0'] = (userId, userName, userColour, userPerms, msgId) => {
watchers.call('chan:join', {
user: {
id: userId,
self: userId === selfUserId,
name: userName,
colour: parseUserColour(userColour),
perms: parseUserPerms(userPerms),
permsRaw: userPerms,
},
msg: {
id: msgId,
channel: selfChannelName,
botInfo: {
type: 'jchan',
args: [userName],
},
},
});
};
// user leave channel
handlers['5']['1'] = (userId, msgId) => {
watchers.call('chan:leave', {
user: {
id: userId,
self: userId === selfUserId,
},
msg: {
id: msgId,
channel: selfChannelName,
botInfo: {
type: 'lchan',
args: [userId],
},
},
});
};
// user forced switch channel
handlers['5']['2'] = name => {
selfChannelName = name;
watchers.call('chan:focus', {
channel: { name: selfChannelName },
});
};
// message delete
handlers['6'] = msgId => {
watchers.call('msg:remove', {
msg: {
id: msgId,
channel: selfChannelName,
},
});
};
// context populate
handlers['7'] = {};
// existing users
handlers['7']['0'] = (count, ...args) => {
count = parseInt(count);
for(let i = 0; i < count; ++i) {
const offset = 5 * i;
watchers.call('user:add', {
user: {
id: args[offset],
self: args[offset] === selfUserId,
name: args[offset + 1],
colour: parseUserColour(args[offset + 2]),
perms: parseUserPerms(args[offset + 3]),
permsRaw: args[offset + 3],
hidden: args[offset + 4] !== '0',
},
});
}
};
// existing message
handlers['7']['1'] = (timeStamp, userId, userName, userColour, userPerms, msgText, msgId, msgNotify, msgFlags) => {
const info = {
msg: {
id: msgId,
time: new Date(parseInt(timeStamp) * 1000),
channel: selfChannelName,
sender: {
id: userId,
self: userId === selfUserId,
name: userName,
colour: parseUserColour(userColour),
perms: parseUserColour(userPerms),
permsRaw: userPerms,
},
isBot: userId === '-1',
silent: msgNotify === '0',
flags: parseMsgFlags(msgFlags),
flagsRaw: msgFlags,
text: unfuckText(msgText),
},
};
const msgIdFirst = info.msg.id.charCodeAt(0);
if(msgIdFirst < 48 || msgIdFirst > 57)
info.msg.id = (Math.round(Number.MIN_SAFE_INTEGER * Math.random())).toString();
if(info.msg.isBot) {
const botParts = msgText.split("\f");
info.msg.botInfo = {
isError: botParts[0] === '1',
type: botParts[1],
args: botParts.slice(2),
};
}
watchers.call('msg:add', info);
};
// existing channels
handlers['7']['2'] = (count, ...args) => {
count = parseInt(count);
for(let i = 0; i < count; ++i) {
const offset = 3 * i;
watchers.call('chan:add', {
channel: {
name: args[offset],
hasPassword: args[offset + 1] !== '0',
isTemporary: args[offset + 2] !== '0',
isCurrent: args[offset] === selfChannelName,
},
});
}
watchers.call('chan:focus', {
channel: { name: selfChannelName },
});
};
// context clear
handlers['8'] = mode => {
if(mode === '0' || mode === '3' || mode === '4')
watchers.call('msg:clear');
if(mode === '1' || mode === '3' || mode === '4')
watchers.call('user:clear');
if(mode === '2' || mode === '4')
watchers.call('chan:clear');
};
// baka (ban/kick)
handlers['9'] = (type, expiry) => {
noReconnect = true;
wasKicked = true;
const bakaInfo = {
session: { success: false },
baka: {
type: type === '0' ? 'kick' : 'ban',
},
};
if(bakaInfo.baka.type === 'ban') {
bakaInfo.baka.perma = expiry === '-1';
bakaInfo.baka.until = expiry === '-1' ? undefined : new Date(parseInt(expiry) * 1000);
}
watchers.call('session:term', bakaInfo);
};
// user update
handlers['10'] = (userId, userName, userColour, userPerms) => {
watchers.call('user:update', {
user: {
id: userId,
self: userId === selfUserId,
name: userName,
colour: parseUserColour(userColour),
perms: parseUserPerms(userPerms),
permsRaw: userPerms,
},
});
};
const beginConnecting = () => {
sock?.close();