#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]); }, }; };