mami/src/mami.js/sockchat/handlers.js
flash cf71bab92d Rewrote connection handling.
This has been in the works for over a month and might break things because it's a very radical change.
If it causes you to be unable to join chat, report it on the forum or try joining using the legacy chat on https://sockchat.flashii.net.
2024-04-17 15:42:50 +00:00

376 lines
12 KiB
JavaScript

#include animate.js
#include channels.js
#include messages.js
#include parsing.js
#include users.js
#include ui/baka.jsx
#include ui/emotes.js
#include ui/markup.js
#include ui/menus.js
#include ui/messages.jsx
const MamiSockChatHandlers = function(ctx, client, setLoadingOverlay, sockChatReconnect, pingIndicator, pingToggle) {
if(typeof ctx !== 'object' || ctx === null)
throw 'ctx must be an non-null object';
if(typeof client !== 'object' || client === null)
throw 'client must be an non-null object';
if(typeof setLoadingOverlay !== 'function')
throw 'setLoadingOverlay must be a function';
if(typeof sockChatReconnect !== 'function')
throw 'sockChatReconnect must be a function';
if(typeof pingIndicator !== 'object' || pingIndicator === null)
throw 'pingIndicator must be an non-null object';
if(!(pingToggle instanceof Element))
throw 'pingToggle must be an instance of Element';
const handlers = {};
let dumpEvents = false;
handlers['conn:open'] = ev => {
if(dumpEvents) console.log('conn:open', ev.detail);
setLoadingOverlay('spinner', 'Connecting...', 'Authenticating...', true);
};
let legacyUmiConnectFired = false;
handlers['conn:ready'] = ev => {
if(dumpEvents) console.log('conn:ready');
client.authenticate().then(() => {
if(!legacyUmiConnectFired) {
legacyUmiConnectFired = true;
ctx.globalEvents.dispatch('umi:connect');
}
});
};
handlers['conn:lost'] = ev => {
if(dumpEvents) console.log('conn:lost', ev.detail);
if(ctx.conMan.isActive || ctx.isUnloading || ev.detail.wasKicked)
return;
sockChatRestarting = ev.detail.isRestarting;
sockChatReconnect();
};
handlers['ping:send'] = () => {
if(dumpEvents) console.log('ping:send');
};
handlers['ping:long'] = ev => {
if(dumpEvents) console.log('ping:long', ev.detail);
sockChatReconnect();
};
handlers['ping:recv'] = ev => {
if(dumpEvents) console.log('ping:recv', ev.detail);
let strength = 3;
if(ev.detail.diff >= 800) --strength;
if(ev.detail.diff >= 400) --strength;
if(ev.detail.diff >= 200) --strength;
pingToggle.title = `${ev.detail.diff.toLocaleString()}ms`;
pingIndicator.setStrength(strength);
};
handlers['session:start'] = ev => {
if(dumpEvents) console.log('session:start', ev.detail);
sockChatRestarting = false;
const userInfo = new MamiUserInfo(
ev.detail.user.id,
ev.detail.user.name,
ev.detail.user.colour,
new MamiUserStatusInfo(ev.detail.user.status.isAway, ev.detail.user.status.message),
new MamiUserPermsInfo(
ev.detail.user.perms.rank, ev.detail.user.perms.kick,
ev.detail.user.perms.nick, ev.detail.user.perms.chan,
),
);
Umi.User.setCurrentUser(userInfo);
Umi.Users.Add(userInfo);
Umi.UI.Markup.Reset();
Umi.UI.Emoticons.Init();
Umi.Parsing.Init();
if(ctx.views.count() > 1)
ctx.views.pop(ctx => MamiAnimate({
async: true,
duration: 120,
easing: 'inOutSine',
start: () => {
ctx.toElem.style.zIndex = '100';
ctx.fromElem.style.pointerEvents = 'none';
ctx.fromElem.style.zIndex = '200';
},
update: t => {
ctx.fromElem.style.transform = `scale(${1 + (.25 * t)})`;
ctx.fromElem.style.opacity = 1 - (1 * t).toString();
},
end: () => {
ctx.toElem.style.zIndex = null;
},
}));
};
handlers['session:fail'] = ev => {
if(dumpEvents) console.log('session:fail', ev.detail);
if(ev.detail.baka !== undefined) {
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views);
return;
}
if(ev.detail.session.needsAuth) {
location.assign(futami.get('login'));
return;
}
setLoadingOverlay('cross', 'Failed!', ev.detail.session.outOfConnections ? 'Too many active connections.' : 'Unspecified reason.');
};
handlers['session:term'] = ev => {
if(dumpEvents) console.log('session:term', ev.detail);
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views);
};
handlers['user:add'] = ev => {
if(dumpEvents) console.log('user:add', ev.detail);
if(ev.detail.user.self)
return;
const userInfo = new MamiUserInfo(
ev.detail.user.id,
ev.detail.user.name,
ev.detail.user.colour,
new MamiUserStatusInfo(ev.detail.user.status.isAway, ev.detail.user.status.message),
new MamiUserPermsInfo(
ev.detail.user.perms.rank, ev.detail.user.perms.kick,
ev.detail.user.perms.nick, ev.detail.user.perms.chan,
),
);
Umi.Users.Add(userInfo);
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
ev.detail.msg.id, ev.detail.msg.time, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: ev.detail.msg.botInfo.type,
args: ev.detail.msg.botInfo.args,
target: userInfo,
}
));
};
handlers['user:remove'] = ev => {
if(dumpEvents) console.log('user:remove', ev.detail);
const userInfo = Umi.Users.Get(ev.detail.user.id);
if(userInfo === null)
return;
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
ev.detail.msg.id,
ev.detail.msg.time,
undefined,
'',
ev.detail.msg.channel,
false,
{
isError: false,
type: ev.detail.msg.botInfo.type,
args: ev.detail.msg.botInfo.args,
target: userInfo,
},
));
Umi.Users.Remove(userInfo);
};
handlers['user:update'] = ev => {
if(dumpEvents) console.log('user:update', ev.detail);
const userInfo = Umi.Users.Get(ev.detail.user.id);
userInfo.name = ev.detail.user.name;
userInfo.colour = ev.detail.user.colour;
userInfo.avatarChangeTime = Date.now();
userInfo.status = new MamiUserStatusInfo(ev.detail.user.status.isAway, ev.detail.user.status.message);
userInfo.perms = new MamiUserPermsInfo(
ev.detail.user.perms.rank, ev.detail.user.perms.kick,
ev.detail.user.perms.nick, ev.detail.user.perms.chan,
);
Umi.Users.Update(userInfo.id, userInfo);
};
handlers['user:clear'] = () => {
if(dumpEvents) console.log('user:clear');
const self = Umi.User.getCurrentUser();
Umi.Users.Clear();
if(self !== undefined)
Umi.Users.Add(self);
};
handlers['chan:add'] = ev => {
if(dumpEvents) console.log('chan:add', ev.detail);
Umi.Channels.Add(new MamiChannelInfo(
ev.detail.channel.name,
ev.detail.channel.hasPassword,
ev.detail.channel.isTemporary,
));
};
handlers['chan:remove'] = ev => {
if(dumpEvents) console.log('chan:remove', ev.detail);
Umi.Channels.Remove(Umi.Channels.Get(ev.detail.channel.name));
};
handlers['chan:update'] = ev => {
if(dumpEvents) console.log('chan:update', ev.detail);
const chanInfo = Umi.Channels.Get(ev.detail.channel.previousName);
chanInfo.name = ev.detail.channel.name;
chanInfo.hasPassword = ev.detail.channel.hasPassword;
chanInfo.isTemporary = ev.detail.channel.isTemporary;
Umi.Channels.Update(ev.detail.channel.previousName, chanInfo);
};
handlers['chan:clear'] = () => {
if(dumpEvents) console.log('chan:clear');
Umi.Channels.Clear();
};
handlers['chan:focus'] = ev => {
if(dumpEvents) console.log('chan:focus', ev.detail);
Umi.Channels.Switch(Umi.Channels.Get(ev.detail.channel.name));
};
handlers['chan:join'] = ev => {
if(dumpEvents) console.log('chan:join', ev.detail);
const userInfo = new MamiUserInfo(
ev.detail.user.id,
ev.detail.user.name,
ev.detail.user.colour,
new MamiUserStatusInfo(ev.detail.user.status.isAway, ev.detail.user.status.message),
new MamiUserPermsInfo(
ev.detail.user.perms.rank, ev.detail.user.perms.kick,
ev.detail.user.perms.nick, ev.detail.user.perms.chan,
)
);
Umi.Users.Add(userInfo);
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
ev.detail.msg.id, null, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: leave.msg.botInfo.type,
args: [ userInfo.name ],
target: userInfo,
},
));
};
handlers['chan:leave'] = ev => {
if(dumpEvents) console.log('chan:leave', ev.detail);
if(ev.detail.user.self)
return;
const userInfo = Umi.Users.Get(ev.detail.user.id);
if(userInfo === null)
return;
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
ev.detail.msg.id, null, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: ev.detail.msg.botInfo.type,
args: [ userInfo.name ],
target: userInfo,
},
));
Umi.Users.Remove(userInfo);
};
handlers['msg:add'] = ev => {
if(dumpEvents) console.log('msg:add', ev.detail);
const senderInfo = ev.detail.msg.sender;
const userInfo = senderInfo.name === undefined
? Umi.Users.Get(senderInfo.id)
: new MamiUserInfo(
senderInfo.id,
senderInfo.name,
senderInfo.colour,
new MamiUserStatusInfo(senderInfo.status.isAway, senderInfo.status.message),
new MamiUserPermsInfo(
senderInfo.perms.rank, senderInfo.perms.kick,
senderInfo.perms.nick, senderInfo.perms.chan,
)
);
// hack
let channelName = ev.detail.msg.channel;
if(channelName !== undefined && channelName.startsWith('@~')) {
const chanUserInfo = Umi.Users.Get(channelName.substring(2));
if(chanUserInfo !== null)
channelName = `@${chanUserInfo.name}`;
}
// also hack
if(ev.detail.msg.flags.isPM) {
if(Umi.Channels.Get(channelName) === null)
Umi.Channels.Add(new MamiChannelInfo(channelName, false, true, true));
// this should be raised for other channels too, but that is not possible yet
Umi.UI.Menus.Attention('channels');
}
Umi.Messages.Add(new Umi.Message(
ev.detail.msg.id,
ev.detail.msg.time,
userInfo,
ev.detail.msg.text,
channelName,
false,
ev.detail.msg.botInfo,
ev.detail.msg.flags.isAction,
ev.detail.msg.silent,
));
};
handlers['msg:remove'] = ev => {
if(dumpEvents) console.log('msg:remove', ev.detail);
Umi.Messages.Remove(Umi.Messages.Get(ev.detail.msg.id));
};
handlers['msg:clear'] = () => {
if(dumpEvents) console.log('msg:clear');
Umi.UI.Messages.RemoveAll();
};
return {
setDumpEvents: state => {
dumpEvents = !!state;
},
register: () => {
for(const name in handlers)
client.watch(name, handlers[name]);
},
unregister: () => {
for(const name in handlers)
client.unwatch(name, handlers[name]);
},
};
};