Moved all/most UI code out of the Sock Chat protocol handler.
This commit is contained in:
parent
ec7ca22811
commit
5b5ca888a4
11 changed files with 855 additions and 450 deletions
|
@ -1,8 +1,8 @@
|
||||||
const MamiColour = (() => {
|
const MamiColour = (() => {
|
||||||
const readThres = 168,
|
const readThres = 168;
|
||||||
lumiRed = .299,
|
const lumiRed = .299;
|
||||||
lumiGreen = .587,
|
const lumiGreen = .587;
|
||||||
lumiBlue = .114;
|
const lumiBlue = .114;
|
||||||
|
|
||||||
const pub = {};
|
const pub = {};
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ const MamiColour = (() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const weighted = (raw1, raw2, weight) => {
|
const weighted = (raw1, raw2, weight) => {
|
||||||
const rgb1 = extractRGB(raw1),
|
const rgb1 = extractRGB(raw1);
|
||||||
rgb2 = extractRGB(raw2);
|
const rgb2 = extractRGB(raw2);
|
||||||
return (weightedNumber(rgb1[0], rgb2[0], weight) << 16)
|
return (weightedNumber(rgb1[0], rgb2[0], weight) << 16)
|
||||||
| (weightedNumber(rgb1[1], rgb2[1], weight) << 8)
|
| (weightedNumber(rgb1[1], rgb2[1], weight) << 8)
|
||||||
| weightedNumber(rgb1[2], rgb2[2], weight);
|
| weightedNumber(rgb1[2], rgb2[2], weight);
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
|
|
||||||
#include animate.js
|
#include animate.js
|
||||||
|
#include channel.js
|
||||||
|
#include channels.js
|
||||||
#include common.js
|
#include common.js
|
||||||
#include context.js
|
#include context.js
|
||||||
#include emotes.js
|
#include emotes.js
|
||||||
|
#include message.js
|
||||||
#include messages.js
|
#include messages.js
|
||||||
#include mszauth.js
|
#include mszauth.js
|
||||||
|
#include parsing.js
|
||||||
#include server.js
|
#include server.js
|
||||||
#include txtrigs.js
|
#include txtrigs.js
|
||||||
|
#include user.js
|
||||||
|
#include users.js
|
||||||
#include utility.js
|
#include utility.js
|
||||||
#include weeb.js
|
#include weeb.js
|
||||||
#include audio/autoplay.js
|
#include audio/autoplay.js
|
||||||
|
@ -21,10 +27,12 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
#include sound/umisound.js
|
#include sound/umisound.js
|
||||||
#include ui/chat-layout.js
|
#include ui/chat-layout.js
|
||||||
#include ui/hooks.js
|
#include ui/hooks.js
|
||||||
|
#include ui/emotes.js
|
||||||
#include ui/input-menus.js
|
#include ui/input-menus.js
|
||||||
#include ui/loading-overlay.jsx
|
#include ui/loading-overlay.jsx
|
||||||
#include ui/markup.js
|
#include ui/markup.js
|
||||||
#include ui/menus.js
|
#include ui/menus.js
|
||||||
|
#include ui/messages.jsx
|
||||||
#include ui/view.js
|
#include ui/view.js
|
||||||
#include ui/settings.jsx
|
#include ui/settings.jsx
|
||||||
#include ui/toggles.js
|
#include ui/toggles.js
|
||||||
|
@ -109,6 +117,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
settings.define('osuKeysV2', ['no', 'yes', 'rng'], 'no');
|
settings.define('osuKeysV2', ['no', 'yes', 'rng'], 'no');
|
||||||
settings.define('explosionRadius', 'number', 20);
|
settings.define('explosionRadius', 'number', 20);
|
||||||
settings.define('dumpPackets', 'boolean', FUTAMI_DEBUG);
|
settings.define('dumpPackets', 'boolean', FUTAMI_DEBUG);
|
||||||
|
settings.define('dumpEvents', 'boolean', FUTAMI_DEBUG);
|
||||||
settings.define('neverUseWorker', 'boolean', false, false, true);
|
settings.define('neverUseWorker', 'boolean', false, false, true);
|
||||||
settings.define('forceUseWorker', 'boolean', false, false, true);
|
settings.define('forceUseWorker', 'boolean', false, false, true);
|
||||||
settings.define('marqueeAllNames', 'boolean', false);
|
settings.define('marqueeAllNames', 'boolean', false);
|
||||||
|
@ -244,7 +253,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
return 'minecraft:door:open';
|
return 'minecraft:door:open';
|
||||||
if(v === 'old')
|
if(v === 'old')
|
||||||
return 'minecraft:door:open-old';
|
return 'minecraft:door:open-old';
|
||||||
return mami.sound.pack.getEventSound('join');
|
return soundCtx.pack.getEventSound('join');
|
||||||
})());
|
})());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -445,7 +454,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
insertText = `[video]${fileInfo.url}[/video]`;
|
insertText = `[video]${fileInfo.url}[/video]`;
|
||||||
uploadEntry.setThumbnail(fileInfo.thumb);
|
uploadEntry.setThumbnail(fileInfo.thumb);
|
||||||
} else
|
} else
|
||||||
insertText = location.protocol + fileInfo.url;
|
insertText = location.Umi.Servercol + fileInfo.url;
|
||||||
|
|
||||||
if(settings.get('eepromAutoInsert'))
|
if(settings.get('eepromAutoInsert'))
|
||||||
Umi.UI.Markup.InsertRaw(insertText, '');
|
Umi.UI.Markup.InsertRaw(insertText, '');
|
||||||
|
@ -521,8 +530,386 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// really not sure about all the watchers for the protocol just kinda being Listed here but we'll see i guess
|
||||||
loadingOverlay.setMessage('Connecting...');
|
loadingOverlay.setMessage('Connecting...');
|
||||||
Umi.Server.open(views, settings);
|
|
||||||
|
const getLoadingOverlay = async (icon, header, message) => {
|
||||||
|
const currentView = views.current();
|
||||||
|
|
||||||
|
if('setIcon' in currentView) {
|
||||||
|
currentView.setIcon(icon);
|
||||||
|
currentView.setHeader(header);
|
||||||
|
currentView.setMessage(message);
|
||||||
|
return currentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = new Umi.UI.LoadingOverlay(icon, header, message);
|
||||||
|
await views.push(loading);
|
||||||
|
|
||||||
|
return loading;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wsCloseReasons = {
|
||||||
|
'_1000': 'The connection has been ended.',
|
||||||
|
'_1001': 'Something went wrong on the server side.',
|
||||||
|
'_1002': 'Your client sent broken data to the server.',
|
||||||
|
'_1003': 'Your client sent data to the server that it does not understand.',
|
||||||
|
'_1005': 'No additional information was provided.',
|
||||||
|
'_1006': 'You lost connection unexpectedly!',
|
||||||
|
'_1007': 'Your client sent broken data to the server.',
|
||||||
|
'_1008': 'Your client did something the server did not agree with.',
|
||||||
|
'_1009': 'Your client sent too much data to the server at once.',
|
||||||
|
'_1011': 'Something went wrong on the server side.',
|
||||||
|
'_1012': 'The server is restarting, reconnecting soon...',
|
||||||
|
'_1013': 'You cannot connect to the server right now, try again later.',
|
||||||
|
'_1015': 'Your client and the server could not establish a secure connection.',
|
||||||
|
};
|
||||||
|
|
||||||
|
let dumpEvents = false;
|
||||||
|
settings.watch('dumpEvents', value => dumpEvents = value);
|
||||||
|
settings.watch('dumpPackets', value => Umi.Server.setDumpPackets(value));
|
||||||
|
|
||||||
|
Umi.Server.watch('conn:init', init => {
|
||||||
|
if(dumpEvents) console.log('conn:init', init);
|
||||||
|
|
||||||
|
let message = 'Connecting to server...';
|
||||||
|
if(init.attempt > 2)
|
||||||
|
message += ` (Attempt ${connectAttempts})`;
|
||||||
|
|
||||||
|
getLoadingOverlay('spinner', 'Loading...', message);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('conn:ready', ready => {
|
||||||
|
if(dumpEvents) console.log('conn:ready', ready);
|
||||||
|
|
||||||
|
getLoadingOverlay('spinner', 'Loading...', 'Authenticating...');
|
||||||
|
});
|
||||||
|
Umi.Server.watch('conn:lost', lost => {
|
||||||
|
if(dumpEvents) console.log('conn:lost', lost);
|
||||||
|
|
||||||
|
getLoadingOverlay(
|
||||||
|
'unlink', 'Disconnected!',
|
||||||
|
wsCloseReasons[`_${lost.code}`] ?? `Something caused an unexpected connection loss. (${lost.code})`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('conn:error', error => {
|
||||||
|
console.error('conn:error', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
Umi.Server.watch('ping:send', send => {
|
||||||
|
if(dumpEvents) console.log('ping:send', send);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('ping:long', long => {
|
||||||
|
if(dumpEvents) console.log('ping:long', long);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('ping:recv', recv => {
|
||||||
|
if(dumpEvents) console.log('ping:recv', recv);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const playBannedSfx = async () => {
|
||||||
|
await soundCtx.library.play('touhou:pichuun');
|
||||||
|
};
|
||||||
|
const playBannedBgm = async preload => {
|
||||||
|
const name = 'touhou:th10score';
|
||||||
|
|
||||||
|
if(preload) {
|
||||||
|
await soundCtx.library.loadBuffer(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = await soundCtx.library.loadSource(name);
|
||||||
|
source.setLoop(true, 10.512, 38.074);
|
||||||
|
await source.play();
|
||||||
|
};
|
||||||
|
const displayBanMessage = baka => {
|
||||||
|
let message;
|
||||||
|
if(baka.perma)
|
||||||
|
message = 'You have been banned till the end of time, please try again in a different dimension.';
|
||||||
|
else if(baka.until)
|
||||||
|
message = `You were banned until ${baka.until.toLocaleString()}!`;
|
||||||
|
else
|
||||||
|
message = 'You were kicked, refresh to log back in!';
|
||||||
|
|
||||||
|
const icon = baka.type === 'kick' ? 'bomb' : 'hammer';
|
||||||
|
const header = baka.type === 'kick' ? 'Kicked!' : 'Banned!';
|
||||||
|
|
||||||
|
const currentView = views.current();
|
||||||
|
|
||||||
|
if(currentView === undefined || 'setIcon' in currentView) {
|
||||||
|
playBannedBgm();
|
||||||
|
getLoadingOverlay(icon, header, message);
|
||||||
|
} else {
|
||||||
|
const currentViewElem = views.currentElement();
|
||||||
|
|
||||||
|
MamiAnimate({
|
||||||
|
duration: 550,
|
||||||
|
easing: 'outExpo',
|
||||||
|
start: () => {
|
||||||
|
playBannedBgm(true);
|
||||||
|
playBannedSfx();
|
||||||
|
},
|
||||||
|
update: t => {
|
||||||
|
currentViewElem.style.transform = `scale(${(1 - .5 * t)}, ${(1 - 1 * t)})`;
|
||||||
|
},
|
||||||
|
end: () => {
|
||||||
|
getLoadingOverlay(icon, header, message).then(() => {
|
||||||
|
playBannedBgm();
|
||||||
|
|
||||||
|
// there's currently no way to reconnect after a kick/ban so just dispose of the ui entirely
|
||||||
|
if(views.count() > 1)
|
||||||
|
views.shift();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Umi.Server.watch('session:start', start => {
|
||||||
|
if(dumpEvents) console.log('session:start', start);
|
||||||
|
|
||||||
|
const userInfo = new Umi.User(start.user.id, start.user.name, start.user.colour, start.user.permsRaw);
|
||||||
|
Umi.User.setCurrentUser(userInfo);
|
||||||
|
Umi.Users.Add(userInfo);
|
||||||
|
|
||||||
|
Umi.UI.Markup.Reset();
|
||||||
|
Umi.UI.Emoticons.Init();
|
||||||
|
Umi.Parsing.Init();
|
||||||
|
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('session:fail', fail => {
|
||||||
|
if(dumpEvents) console.log('session:fail', fail);
|
||||||
|
|
||||||
|
if(fail.baka !== undefined) {
|
||||||
|
displayBanMessage(fail.baka);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = (reason => {
|
||||||
|
if(reason === 'authfail')
|
||||||
|
return 'Authentication failed.';
|
||||||
|
if(reason === 'sockfail')
|
||||||
|
return 'Too many active connections.';
|
||||||
|
if(reason === 'userfail')
|
||||||
|
return 'Name in use.';
|
||||||
|
if(reason === 'joinfail')
|
||||||
|
return 'You are banned.';
|
||||||
|
return `Unknown reason: ${reason}`;
|
||||||
|
})(fail.session.reason);
|
||||||
|
|
||||||
|
getLoadingOverlay('cross', 'Failed!', message);
|
||||||
|
|
||||||
|
if(fail.session.needsAuth)
|
||||||
|
setTimeout(() => location.assign(futami.get('login')), 1000);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('session:term', term => {
|
||||||
|
if(dumpEvents) console.log('session:term', term);
|
||||||
|
|
||||||
|
displayBanMessage(term.baka);
|
||||||
|
});
|
||||||
|
|
||||||
|
Umi.Server.watch('user:add', add => {
|
||||||
|
if(dumpEvents) console.log('user:add', add);
|
||||||
|
|
||||||
|
if(add.user.self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const userInfo = new Umi.User(add.user.id, add.user.name, add.user.colour, add.user.permsRaw);
|
||||||
|
Umi.Users.Add(userInfo);
|
||||||
|
|
||||||
|
if(add.msg !== undefined)
|
||||||
|
Umi.Messages.Add(new Umi.Message(
|
||||||
|
add.msg.id, add.msg.time, undefined, '', add.msg.channel, false,
|
||||||
|
{
|
||||||
|
isError: false,
|
||||||
|
type: add.msg.botInfo.type,
|
||||||
|
args: add.msg.botInfo.args,
|
||||||
|
target: userInfo,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('user:remove', remove => {
|
||||||
|
if(dumpEvents) console.log('user:remove', remove);
|
||||||
|
|
||||||
|
const userInfo = Umi.Users.Get(remove.user.id);
|
||||||
|
if(userInfo === null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(remove.msg !== undefined)
|
||||||
|
Umi.Messages.Add(new Umi.Message(
|
||||||
|
remove.msg.id,
|
||||||
|
remove.msg.time,
|
||||||
|
undefined,
|
||||||
|
'',
|
||||||
|
remove.msg.channel,
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
isError: false,
|
||||||
|
type: remove.msg.botInfo.type,
|
||||||
|
args: remove.msg.botInfo.args,
|
||||||
|
target: userInfo,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
Umi.Users.Remove(userInfo);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('user:update', update => {
|
||||||
|
if(dumpEvents) console.log('user:update', update);
|
||||||
|
|
||||||
|
const userInfo = Umi.Users.Get(update.user.id);
|
||||||
|
userInfo.setName(update.user.name);
|
||||||
|
userInfo.setColour(update.user.colour);
|
||||||
|
userInfo.setPermissions(update.user.permsRaw);
|
||||||
|
Umi.Users.Update(userInfo.getId(), userInfo);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('user:clear', () => {
|
||||||
|
if(dumpEvents) console.log('user:clear');
|
||||||
|
|
||||||
|
const self = Umi.User.currentUser;
|
||||||
|
Umi.Users.Clear();
|
||||||
|
if(self !== undefined)
|
||||||
|
Umi.Users.Add(self);
|
||||||
|
});
|
||||||
|
|
||||||
|
Umi.Server.watch('chan:add', add => {
|
||||||
|
if(dumpEvents) console.log('chan:add', add);
|
||||||
|
|
||||||
|
Umi.Channels.Add(new Umi.Channel(
|
||||||
|
add.channel.name,
|
||||||
|
add.channel.hasPassword,
|
||||||
|
add.channel.isTemporary,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:remove', remove => {
|
||||||
|
if(dumpEvents) console.log('chan:remove', remove);
|
||||||
|
|
||||||
|
Umi.Channels.Remove(Umi.Channels.Get(remove.channel.name));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:update', update => {
|
||||||
|
if(dumpEvents) console.log('chan:update', update);
|
||||||
|
|
||||||
|
const chanInfo = Umi.Channels.Get(update.channel.previousName);
|
||||||
|
chanInfo.setName(update.channel.name);
|
||||||
|
chanInfo.setHasPassword(update.channel.hasPassword);
|
||||||
|
chanInfo.setTemporary(update.channel.isTemporary);
|
||||||
|
Umi.Channels.Update(update.channel.previousName, chanInfo);
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:clear', () => {
|
||||||
|
if(dumpEvents) console.log('chan:clear');
|
||||||
|
|
||||||
|
Umi.Channels.Clear();
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:focus', focus => {
|
||||||
|
if(dumpEvents) console.log('chan:focus', focus);
|
||||||
|
|
||||||
|
Umi.Channels.Switch(Umi.Channels.Get(focus.channel.name));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:join', join => {
|
||||||
|
if(dumpEvents) console.log('chan:join', join);
|
||||||
|
|
||||||
|
const userInfo = new Umi.User(join.user.id, join.user.name, join.user.colour, join.user.permsRaw);
|
||||||
|
Umi.Users.Add(userInfo);
|
||||||
|
|
||||||
|
if(join.msg !== undefined)
|
||||||
|
Umi.Messages.Add(new Umi.Message(
|
||||||
|
join.msg.id, null, undefined, '', join.msg.channel, false,
|
||||||
|
{
|
||||||
|
isError: false,
|
||||||
|
type: leave.msg.botInfo.type,
|
||||||
|
args: [ userInfo.getName() ],
|
||||||
|
target: userInfo,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('chan:leave', leave => {
|
||||||
|
if(dumpEvents) console.log('chan:leave', leave);
|
||||||
|
|
||||||
|
if(leave.user.self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const userInfo = Umi.Users.Get(leave.user.id);
|
||||||
|
if(userInfo === null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(leave.msg !== undefined)
|
||||||
|
Umi.Messages.Add(new Umi.Message(
|
||||||
|
leave.msg.id, null, undefined, '', leave.msg.channel, false,
|
||||||
|
{
|
||||||
|
isError: false,
|
||||||
|
type: leave.msg.botInfo.type,
|
||||||
|
args: [ userInfo.getName() ],
|
||||||
|
target: userInfo,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
Umi.Users.Remove(userInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
Umi.Server.watch('msg:add', add => {
|
||||||
|
if(dumpEvents) console.log('msg:add', add);
|
||||||
|
|
||||||
|
const senderInfo = add.msg.sender;
|
||||||
|
const userInfo = senderInfo.name === undefined
|
||||||
|
? Umi.Users.Get(senderInfo.id)
|
||||||
|
: new Umi.User(senderInfo.id, senderInfo.name, senderInfo.colour, senderInfo.permsRaw);
|
||||||
|
|
||||||
|
// hack
|
||||||
|
let channelName = add.msg.channel;
|
||||||
|
if(channelName !== undefined && channelName.startsWith('@~')) {
|
||||||
|
const chanUserInfo = Umi.Users.Get(channelName.substring(2));
|
||||||
|
if(chanUserInfo !== null)
|
||||||
|
channelName = `@${chanUserInfo.getName()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// also hack
|
||||||
|
if(add.msg.flags.isPM) {
|
||||||
|
if(Umi.Channels.Get(channelName) === null)
|
||||||
|
Umi.Channels.Add(new Umi.Channel(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(
|
||||||
|
add.msg.id,
|
||||||
|
add.msg.time,
|
||||||
|
userInfo,
|
||||||
|
add.msg.text,
|
||||||
|
channelName,
|
||||||
|
false,
|
||||||
|
add.msg.botInfo,
|
||||||
|
add.msg.flags.isAction,
|
||||||
|
add.msg.silent,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('msg:remove', remove => {
|
||||||
|
if(dumpEvents) console.log('msg:remove', remove);
|
||||||
|
|
||||||
|
Umi.Messages.Remove(Umi.Messages.Get(remove.msg.id));
|
||||||
|
});
|
||||||
|
Umi.Server.watch('msg:clear', () => {
|
||||||
|
if(dumpEvents) console.log('msg:clear');
|
||||||
|
|
||||||
|
Umi.UI.Messages.RemoveAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Umi.Server.open();
|
||||||
|
|
||||||
if(window.dispatchEvent)
|
if(window.dispatchEvent)
|
||||||
window.dispatchEvent(new Event('umi:connect'));
|
window.dispatchEvent(new Event('umi:connect'));
|
||||||
|
|
|
@ -5,7 +5,7 @@ Umi.Message = (() => {
|
||||||
|
|
||||||
return function(msgId, time, user, text, channel, highlight, botInfo, isAction, isLog) {
|
return function(msgId, time, user, text, channel, highlight, botInfo, isAction, isLog) {
|
||||||
msgId = (msgId || '').toString();
|
msgId = (msgId || '').toString();
|
||||||
time = time === null ? new Date() : new Date(parseInt(time || 0) * 1000);
|
time = time === null ? new Date() : (typeof time === 'object' ? time : new Date(parseInt(time || 0) * 1000));
|
||||||
user = user !== null && typeof user === 'object' ? user : chatBot;
|
user = user !== null && typeof user === 'object' ? user : chatBot;
|
||||||
text = (text || '').toString();
|
text = (text || '').toString();
|
||||||
channel = (channel || '').toString();
|
channel = (channel || '').toString();
|
||||||
|
@ -18,7 +18,10 @@ Umi.Message = (() => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getId: () => msgId,
|
getId: () => msgId,
|
||||||
getIdInt: () => msgIdInt,
|
getIdInt: () => {
|
||||||
|
const num = parseInt(msgId);
|
||||||
|
return isNaN(num) ? (Math.round(Number.MIN_SAFE_INTEGER * Math.random())) : num;
|
||||||
|
},
|
||||||
getTime: () => time,
|
getTime: () => time,
|
||||||
getUser: () => user,
|
getUser: () => user,
|
||||||
getText: () => text,
|
getText: () => text,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include channels.js
|
#include channels.js
|
||||||
#include server.js
|
|
||||||
#include ui/messages.jsx
|
#include ui/messages.jsx
|
||||||
|
|
||||||
Umi.Messages = (function() {
|
Umi.Messages = (function() {
|
||||||
|
|
|
@ -1,26 +1,3 @@
|
||||||
#include sockchat_old.js
|
#include sockchat_old.js
|
||||||
|
|
||||||
Umi.Server = (function() {
|
Umi.Server = new Umi.Protocol.SockChat.Protocol;
|
||||||
let proto = null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
open: function(...args) {
|
|
||||||
proto = new Umi.Protocol.SockChat.Protocol(...args);
|
|
||||||
proto.open();
|
|
||||||
},
|
|
||||||
close: function() {
|
|
||||||
if(!proto)
|
|
||||||
return;
|
|
||||||
proto.close();
|
|
||||||
proto = null;
|
|
||||||
},
|
|
||||||
sendMessage: function(text) {
|
|
||||||
if(!proto)
|
|
||||||
return;
|
|
||||||
text = (text || '').toString();
|
|
||||||
if(!text)
|
|
||||||
return;
|
|
||||||
proto.sendMessage(text);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
|
@ -1,149 +1,136 @@
|
||||||
#include channel.js
|
|
||||||
#include channels.js
|
|
||||||
#include common.js
|
#include common.js
|
||||||
#include message.js
|
|
||||||
#include messages.js
|
|
||||||
#include mszauth.js
|
#include mszauth.js
|
||||||
#include user.js
|
|
||||||
#include users.js
|
|
||||||
#include parsing.js
|
|
||||||
#include servers.js
|
#include servers.js
|
||||||
|
#include watcher.js
|
||||||
#include websock.js
|
#include websock.js
|
||||||
#include ui/emotes.js
|
|
||||||
#include ui/markup.js
|
|
||||||
#include ui/menus.js
|
|
||||||
#include ui/messages.jsx
|
|
||||||
#include ui/view.js
|
|
||||||
#include ui/loading-overlay.jsx
|
|
||||||
|
|
||||||
Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
Umi.Protocol.SockChat.Protocol = function() {
|
||||||
const pub = {};
|
const watchers = new MamiWatchers(false);
|
||||||
|
watchers.define([
|
||||||
|
'conn:init', 'conn:ready', 'conn:lost', 'conn:error',
|
||||||
|
'ping:send', 'ping:long', 'ping:recv',
|
||||||
|
'session:start', 'session:fail', 'session:term',
|
||||||
|
'user:add', 'user:remove', 'user:update', 'user:clear',
|
||||||
|
'chan:add', 'chan:remove', 'chan:update', 'chan:clear', 'chan:focus', 'chan:join', 'chan:leave',
|
||||||
|
'msg:add', 'msg:remove', 'msg:clear',
|
||||||
|
]);
|
||||||
|
|
||||||
let noReconnect = false,
|
const parseUserColour = str => {
|
||||||
connectAttempts = 0,
|
// todo
|
||||||
wasKicked = false,
|
return str;
|
||||||
isRestarting = false;
|
};
|
||||||
|
|
||||||
let userId = null,
|
let parseUserPermsSep;
|
||||||
channelName = null,
|
const parseUserPerms = str => {
|
||||||
pmUserName = null;
|
parseUserPermsSep ??= str.includes("\f") ? "\f" : ' ';
|
||||||
|
return str.split(parseUserPermsSep);
|
||||||
|
};
|
||||||
|
|
||||||
let sock = null;
|
const parseMsgFlags = str => {
|
||||||
|
return {
|
||||||
|
nameBold: str[0] !== '0',
|
||||||
|
nameItalics: str[1] !== '0',
|
||||||
|
nameUnderline: str[2] !== '0',
|
||||||
|
showColon: str[3] !== '0',
|
||||||
|
isPM: str[4] !== '0',
|
||||||
|
isAction: str[1] !== '0' && str[3] === '0',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let wasConnected = false;
|
||||||
|
let noReconnect = false;
|
||||||
|
let connectAttempts = 0;
|
||||||
|
let wasKicked = false;
|
||||||
|
let isRestarting = false;
|
||||||
|
let dumpPackets = false;
|
||||||
|
|
||||||
|
let sock;
|
||||||
|
let selfUserId, selfChannelName, selfPseudoChannelName;
|
||||||
|
let lastPing, lastPong, pingTimer, pingWatcher;
|
||||||
|
|
||||||
|
const stopPingWatcher = () => {
|
||||||
|
if(pingWatcher !== undefined) {
|
||||||
|
clearTimeout(pingWatcher);
|
||||||
|
pingWatcher = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const startPingWatcher = () => {
|
||||||
|
if(pingWatcher === undefined)
|
||||||
|
pingWatcher = setTimeout(() => {
|
||||||
|
stopPingWatcher();
|
||||||
|
|
||||||
|
if(lastPong === undefined)
|
||||||
|
watchers.call('ping:long');
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const send = (opcode, data) => {
|
||||||
|
if(sock === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
const send = function(opcode, data) {
|
|
||||||
if(!sock) return;
|
|
||||||
let msg = opcode;
|
let msg = opcode;
|
||||||
if(data) msg += "\t" + data.join("\t");
|
if(data)
|
||||||
if(settings.get('dumpPackets'))
|
msg += `\t${data.join("\t")}`;
|
||||||
|
|
||||||
|
if(dumpPackets)
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
|
|
||||||
sock.send(msg);
|
sock.send(msg);
|
||||||
};
|
};
|
||||||
const sendPing = function() {
|
|
||||||
if(userId === null)
|
const onSendPing = () => {
|
||||||
|
if(selfUserId === undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
watchers.call('ping:send');
|
||||||
|
startPingWatcher();
|
||||||
|
|
||||||
|
lastPong = undefined;
|
||||||
lastPing = Date.now();
|
lastPing = Date.now();
|
||||||
send('0', [userId]);
|
|
||||||
};
|
};
|
||||||
const sendAuth = function(args) {
|
const sendAuth = args => {
|
||||||
if(userId !== null)
|
if(selfUserId === undefined)
|
||||||
return;
|
send('1', args);
|
||||||
send('1', args);
|
|
||||||
};
|
};
|
||||||
const sendMessage = function(text) {
|
const sendMessage = text => {
|
||||||
if(userId === null)
|
if(selfUserId === undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(text.substring(0, 1) !== '/' && pmUserName !== null)
|
if(text.substring(0, 1) !== '/' && selfPseudoChannelName !== undefined)
|
||||||
text = '/msg ' + pmUserName + ' ' + text;
|
text = `/msg ${selfPseudoChannelName} ${text}`;
|
||||||
|
|
||||||
send('2', [userId, text]);
|
send('2', [selfUserId, text]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchChannel = function(name) {
|
const startKeepAlive = () => sock?.sendInterval(`0\t${selfUserId}`, futami.get('ping') * 1000);
|
||||||
if(channelName === name)
|
const stopKeepAlive = () => sock?.clearIntervals();
|
||||||
return;
|
|
||||||
|
|
||||||
channelName = name;
|
const onOpen = ev => {
|
||||||
sendMessage('/join ' + name);
|
if(dumpPackets)
|
||||||
};
|
|
||||||
|
|
||||||
const startKeepAlive = function() {
|
|
||||||
if(!sock) return;
|
|
||||||
sock.sendInterval("0\t" + userId, futami.get('ping') * 1000);
|
|
||||||
};
|
|
||||||
const stopKeepAlive = function() {
|
|
||||||
if(!sock) return;
|
|
||||||
sock.clearIntervals();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLoadingOverlay = async (icon, header, message) => {
|
|
||||||
const currentView = views.current();
|
|
||||||
|
|
||||||
if('setIcon' in currentView) {
|
|
||||||
currentView.setIcon(icon);
|
|
||||||
currentView.setHeader(header);
|
|
||||||
currentView.setMessage(message);
|
|
||||||
return currentView;
|
|
||||||
}
|
|
||||||
|
|
||||||
const loading = new Umi.UI.LoadingOverlay(icon, header, message);
|
|
||||||
await views.push(loading);
|
|
||||||
|
|
||||||
return loading;
|
|
||||||
};
|
|
||||||
|
|
||||||
const playBannedSfx = async () => {
|
|
||||||
await mami.sound.library.play('touhou:pichuun');
|
|
||||||
};
|
|
||||||
const playBannedBgm = async preload => {
|
|
||||||
const name = 'touhou:th10score';
|
|
||||||
|
|
||||||
if(preload) {
|
|
||||||
await mami.sound.library.loadBuffer(name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = await mami.sound.library.loadSource(name);
|
|
||||||
source.setLoop(true, 10.512, 38.074);
|
|
||||||
await source.play();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onOpen = function(ev) {
|
|
||||||
if(settings.get('dumpPackets'))
|
|
||||||
console.log(ev);
|
console.log(ev);
|
||||||
|
|
||||||
wasKicked = false;
|
|
||||||
isRestarting = false;
|
isRestarting = false;
|
||||||
|
|
||||||
getLoadingOverlay('spinner', 'Loading...', 'Authenticating...');
|
watchers.call('conn:ready', {
|
||||||
|
wasConnected: wasConnected,
|
||||||
|
});
|
||||||
|
|
||||||
|
// see if these are neccesary
|
||||||
|
watchers.call('user:clear');
|
||||||
|
watchers.call('chan:clear');
|
||||||
|
|
||||||
const authInfo = MamiMisuzuAuth.getInfo();
|
const authInfo = MamiMisuzuAuth.getInfo();
|
||||||
sendAuth([authInfo.method, authInfo.token]);
|
sendAuth([authInfo.method, authInfo.token]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeReasons = {
|
const onClose = ev => {
|
||||||
'_1000': 'The connection has been ended.',
|
if(dumpPackets)
|
||||||
'_1001': 'Something went wrong on the server side.',
|
|
||||||
'_1002': 'Your client sent broken data to the server.',
|
|
||||||
'_1003': 'Your client sent data to the server that it doesn\'t understand.',
|
|
||||||
'_1005': 'No additional information was provided.',
|
|
||||||
'_1006': 'You lost connection unexpectedly!',
|
|
||||||
'_1007': 'Your client sent broken data to the server.',
|
|
||||||
'_1008': 'Your client did something the server did not agree with.',
|
|
||||||
'_1009': 'Your client sent too much data to the server at once.',
|
|
||||||
'_1011': 'Something went wrong on the server side.',
|
|
||||||
'_1012': 'The server is restarting, reconnecting soon...',
|
|
||||||
'_1013': 'You cannot connect to the server right now, try again later.',
|
|
||||||
'_1015': 'Your client and the server could not establish a secure connection.',
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClose = function(ev) {
|
|
||||||
if(settings.get('dumpPackets'))
|
|
||||||
console.log(ev);
|
console.log(ev);
|
||||||
|
|
||||||
userId = null;
|
selfUserId = undefined;
|
||||||
channelName = null;
|
selfChannelName = undefined;
|
||||||
pmUserName = null;
|
selfPseudoChannelName = undefined;
|
||||||
|
stopPingWatcher();
|
||||||
stopKeepAlive();
|
stopKeepAlive();
|
||||||
|
|
||||||
if(wasKicked)
|
if(wasKicked)
|
||||||
|
@ -155,189 +142,199 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
||||||
} else if(code === 1012)
|
} else if(code === 1012)
|
||||||
isRestarting = true;
|
isRestarting = true;
|
||||||
|
|
||||||
const msg = closeReasons['_' + code.toString()]
|
watchers.call('conn:lost', {
|
||||||
|| ('Something caused an unexpected connection loss, the error code was: ' + ev.code.toString() + '.');
|
wasConnected: wasConnected,
|
||||||
|
isRestarting: isRestarting,
|
||||||
getLoadingOverlay('unlink', 'Disconnected!', msg);
|
code: code,
|
||||||
|
});
|
||||||
Umi.Users.Clear();
|
|
||||||
|
|
||||||
connectAttempts = 0;
|
connectAttempts = 0;
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => beginConnecting(), 5000);
|
||||||
beginConnecting();
|
|
||||||
}, 5000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const unfuckText = function(text) {
|
const onError = ex => {
|
||||||
|
watchers.call('conn:error', ex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const unfuckText = text => {
|
||||||
const elem = document.createElement('div');
|
const elem = document.createElement('div');
|
||||||
elem.innerHTML = text.replace(/ <br\/> /g, "\n");
|
elem.innerHTML = text.replace(/ <br\/> /g, "\n");
|
||||||
text = elem.innerText;
|
text = elem.innerText;
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMessage = function(ev) {
|
const onMessage = ev => {
|
||||||
const data = ev.data.split("\t");
|
const data = ev.data.split("\t");
|
||||||
|
|
||||||
if(settings.get('dumpPackets'))
|
if(dumpPackets)
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
switch(data[0]) {
|
switch(data[0]) {
|
||||||
case '0': // ping
|
case '0': // ping
|
||||||
// nothing to do
|
lastPong = Date.now();
|
||||||
|
watchers.call('ping:recv', {
|
||||||
|
ping: lastPing,
|
||||||
|
pong: lastPong,
|
||||||
|
diff: lastPong - lastPing,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '1': // join
|
case '1': // join
|
||||||
if(userId === null) {
|
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') {
|
if(data[1] == 'y') {
|
||||||
userId = data[2];
|
selfUserId = data[2];
|
||||||
channelName = data[6];
|
selfChannelName = data[6];
|
||||||
|
|
||||||
views.pop(ctx => MamiAnimate({
|
watchers.call('session:start', {
|
||||||
async: true,
|
wasConnected: wasConnected,
|
||||||
duration: 120,
|
session: { success: true },
|
||||||
easing: 'inOutSine',
|
ctx: {
|
||||||
start: () => {
|
maxMsgLength: parseInt(data[7]),
|
||||||
ctx.toElem.style.zIndex = '100';
|
|
||||||
ctx.fromElem.style.pointerEvents = 'none';
|
|
||||||
ctx.fromElem.style.zIndex = '200';
|
|
||||||
},
|
},
|
||||||
update: t => {
|
user: {
|
||||||
ctx.fromElem.style.transform = `scale(${1 + (.25 * t)})`;
|
id: selfUserId,
|
||||||
ctx.fromElem.style.opacity = 1 - (1 * t).toString();
|
self: true,
|
||||||
|
name: data[3],
|
||||||
|
colour: parseUserColour(data[4]),
|
||||||
|
perms: parseUserPerms(data[5]),
|
||||||
|
permsRaw: data[5],
|
||||||
},
|
},
|
||||||
end: () => {
|
channel: {
|
||||||
ctx.toElem.style.zIndex = null;
|
name: selfChannelName,
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
|
||||||
startKeepAlive();
|
startKeepAlive();
|
||||||
|
wasConnected = true;
|
||||||
} else {
|
} else {
|
||||||
switch (data[2]) {
|
wasKicked = true;
|
||||||
case 'joinfail':
|
|
||||||
wasKicked = true;
|
|
||||||
|
|
||||||
const jfuntil = new Date(parseInt(data[3]) * 1000);
|
const failInfo = {
|
||||||
let banmsg = 'You were banned until {0}!'.replace('{0}', jfuntil.toLocaleString());
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
if(data[3] === '-1')
|
watchers.call('session:fail', failInfo);
|
||||||
banmsg = 'You have been banned till the end of time, please try again in a different dimension.';
|
|
||||||
|
|
||||||
getLoadingOverlay('hammer', 'Banned!', banmsg);
|
|
||||||
playBannedBgm();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'authfail':
|
|
||||||
let message = 'Authentication failed!';
|
|
||||||
const afredir = futami.get('login');
|
|
||||||
|
|
||||||
if(afredir) {
|
|
||||||
message = 'Authentication failed, redirecting to login page...';
|
|
||||||
setTimeout(function() {
|
|
||||||
location.assign(afredir);
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLoadingOverlay('cross', 'Failed!', message);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'sockfail':
|
|
||||||
getLoadingOverlay('cross', 'Failed!', 'Too many active connections.');
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
getLoadingOverlay('cross', 'Failed!', 'Connection failed!');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const juser = new Umi.User(data[2], data[3], data[4], data[5]);
|
|
||||||
|
|
||||||
if(userId === juser.getId())
|
|
||||||
Umi.User.setCurrentUser(juser);
|
|
||||||
|
|
||||||
Umi.Users.Add(juser);
|
|
||||||
|
|
||||||
if(Umi.User.isCurrentUser(juser)) {
|
|
||||||
Umi.UI.Markup.Reset();
|
|
||||||
Umi.UI.Emoticons.Init();
|
|
||||||
Umi.Parsing.Init();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Umi.Messages.Add(new Umi.Message(
|
|
||||||
data[6], data[1], undefined, '', channelName, false,
|
|
||||||
{ type: 'join', isError: false, args: [juser.getName()], target: juser }
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2': // message
|
case '2': // message
|
||||||
let text = data[3];
|
let mText = unfuckText(data[3]);
|
||||||
const muser = Umi.Users.Get(data[2]);
|
let mChannelName = selfChannelName;
|
||||||
const textParts = text.split("\f");
|
|
||||||
const isPM = data[5][4] !== '0';
|
|
||||||
const isAction = data[5][1] !== '0' && data[5][3] === '0';
|
|
||||||
const isBot = data[2] === '-1';
|
|
||||||
const botInfo = {};
|
|
||||||
let pmChannel = '';
|
|
||||||
|
|
||||||
text = unfuckText(text);
|
if(data[5][4] !== '0') {
|
||||||
|
if(data[2] === selfUserId) {
|
||||||
if(isBot) {
|
const mTextParts = mText.split(' ');
|
||||||
botInfo.isError = textParts[0] !== '0';
|
mChannelName = `@${mTextParts.shift()}`;
|
||||||
botInfo.type = textParts[1];
|
mText = mTextParts.join(' ');
|
||||||
botInfo.args = textParts.slice(2);
|
} else {
|
||||||
|
mChannelName = `@~${data[2]}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isPM) {
|
const msgInfo = {
|
||||||
if(muser.getId() === userId) {
|
msg: {
|
||||||
const tmpMsg = text.split(' ');
|
id: data[4],
|
||||||
pmChannel = `@${tmpMsg.shift()}`;
|
time: new Date(parseInt(data[1]) * 1000),
|
||||||
text = tmpMsg.join(' ');
|
channel: mChannelName,
|
||||||
} else
|
sender: { id: data[2], },
|
||||||
pmChannel = `@${muser.getName()}`;
|
flags: parseMsgFlags(data[5]),
|
||||||
|
flagsRaw: data[5],
|
||||||
|
isBot: data[2] === '-1',
|
||||||
|
text: mText,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if(Umi.Channels.Get(pmChannel) === null)
|
if(msgInfo.msg.isBot) {
|
||||||
Umi.Channels.Add(new Umi.Channel(pmChannel, false, true, true));
|
const botParts = data[3].split("\f");
|
||||||
|
msgInfo.msg.botInfo = {
|
||||||
Umi.UI.Menus.Attention('channels');
|
isError: botParts[0] === '1',
|
||||||
|
type: botParts[1],
|
||||||
|
args: botParts.slice(2),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Umi.Messages.Add(new Umi.Message(
|
watchers.call('msg:add', msgInfo);
|
||||||
data[4], data[1], muser, text,
|
|
||||||
isPM ? pmChannel : channelName,
|
|
||||||
false, botInfo, isAction
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '3': // leave
|
case '3': // leave
|
||||||
const luser = Umi.Users.Get(data[1]);
|
watchers.call('user:remove', {
|
||||||
|
leave: { type: data[3] },
|
||||||
Umi.Messages.Add(new Umi.Message(
|
msg: {
|
||||||
data[5], data[4], undefined, '', channelName, false,
|
id: data[5],
|
||||||
{ type: data[3], isError: false, args: [luser.getName()], target: luser }
|
time: new Date(parseInt(data[4]) * 1000),
|
||||||
));
|
channel: selfChannelName,
|
||||||
Umi.Users.Remove(luser);
|
botInfo: {
|
||||||
|
type: data[3],
|
||||||
|
args: [data[2]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: data[1],
|
||||||
|
self: data[1] === selfUserId,
|
||||||
|
name: data[2],
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '4': // channel
|
case '4': // channel
|
||||||
switch(data[1]) {
|
switch(data[1]) {
|
||||||
case '0':
|
case '0':
|
||||||
Umi.Channels.Add(new Umi.Channel(data[2], data[3] !== '0', data[4] !== '0'));
|
watchers.call('chan:add', {
|
||||||
|
channel: {
|
||||||
|
name: data[2],
|
||||||
|
hasPassword: data[3] !== '0',
|
||||||
|
isTemporary: data[4] !== '0',
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '1':
|
case '1':
|
||||||
const uchannel = Umi.Channels.Get(data[2]);
|
watchers.call('chan:update', {
|
||||||
uchannel.setName(data[3]);
|
channel: {
|
||||||
uchannel.setHasPassword(data[4] !== '0');
|
previousName: data[2],
|
||||||
uchannel.setTemporary(data[5] !== '0');
|
name: data[3],
|
||||||
Umi.Channels.Update(data[2], uchannel);
|
hasPassword: data[4] !== '0',
|
||||||
|
isTemporary: data[5] !== '0',
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2':
|
case '2':
|
||||||
Umi.Channels.Remove(Umi.Channels.Get(data[2]));
|
watchers.call('chan:remove', {
|
||||||
|
channel: { name: data[2] },
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -345,205 +342,202 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
||||||
case '5': // user move
|
case '5': // user move
|
||||||
switch(data[1]) {
|
switch(data[1]) {
|
||||||
case '0':
|
case '0':
|
||||||
const umuser = new Umi.User(data[2], data[3], data[4], data[5]);
|
watchers.call('chan:join', {
|
||||||
|
user: {
|
||||||
Umi.Users.Add(umuser);
|
id: data[2],
|
||||||
Umi.Messages.Add(new Umi.Message(
|
self: data[2] === selfUserId,
|
||||||
data[6], null, undefined, '', channelName, false,
|
name: data[3],
|
||||||
{ type: 'jchan', isError: false, args: [ umuser.getName() ], target: umuser }
|
colour: parseUserColour(data[4]),
|
||||||
));
|
perms: parseUserPerms(data[5]),
|
||||||
|
permsRaw: data[5],
|
||||||
|
},
|
||||||
|
msg: {
|
||||||
|
id: data[6],
|
||||||
|
channel: selfChannelName,
|
||||||
|
botInfo: {
|
||||||
|
type: 'jchan',
|
||||||
|
args: [data[3]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '1':
|
case '1':
|
||||||
if(data[2] === userId)
|
watchers.call('chan:leave', {
|
||||||
return;
|
user: {
|
||||||
|
id: data[2],
|
||||||
const mouser = Umi.Users.Get(+data[2]);
|
self: data[2] === selfUserId,
|
||||||
|
},
|
||||||
Umi.Messages.Add(new Umi.Message(
|
msg: {
|
||||||
data[3], null, undefined, '', channelName, false,
|
id: data[3],
|
||||||
{ type: 'lchan', isError: false, args: [ mouser.getName() ], target: mouser }
|
channel: selfChannelName,
|
||||||
));
|
botInfo: {
|
||||||
Umi.Users.Remove(mouser);
|
type: 'lchan',
|
||||||
|
args: [data[2]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2':
|
case '2':
|
||||||
Umi.Channels.Switch(Umi.Channels.Get(data[2]));
|
selfChannelName = data[2];
|
||||||
|
|
||||||
|
watchers.call('chan:focus', {
|
||||||
|
channel: { name: selfChannelName },
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '6': // message delete
|
case '6': // message delete
|
||||||
Umi.Messages.Remove(Umi.Messages.Get(data[1]));
|
watchers.call('msg:remove', {
|
||||||
|
msg: {
|
||||||
|
id: data[1],
|
||||||
|
channel: selfChannelName,
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '7': // context populate
|
case '7': // context populate
|
||||||
switch(data[1]) {
|
switch(data[1]) {
|
||||||
case '0': // users
|
case '0': // users
|
||||||
const cpuamount = parseInt(data[2]);
|
const cpuamount = parseInt(data[2]);
|
||||||
let cpustart = 3;
|
|
||||||
|
|
||||||
for(let i = 0; i < cpuamount; i++) {
|
for(let i = 0; i < cpuamount; ++i) {
|
||||||
const user = new Umi.User(data[cpustart], data[cpustart + 1], data[cpustart + 2], data[cpustart + 3]);
|
const cpuoffset = 3 + 5 * i;
|
||||||
Umi.Users.Add(user);
|
|
||||||
cpustart += 5;
|
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;
|
break;
|
||||||
|
|
||||||
case '1': // message
|
case '1': // message
|
||||||
let cmid = +data[8],
|
const cmMsgInfo = {
|
||||||
cmtext = data[7],
|
msg: {
|
||||||
cmflags = data[10];
|
id: data[8],
|
||||||
const cmuser = new Umi.User(data[3], data[4], data[5], data[6]),
|
time: new Date(parseInt(data[2]) * 1000),
|
||||||
cmtextParts = cmtext.split("\f"),
|
channel: selfChannelName,
|
||||||
cmbotInfo = {};
|
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]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if(isNaN(cmid))
|
const cmMsgIdFirst = cmMsgInfo.msg.id.charCodeAt(0);
|
||||||
cmid = -Math.ceil(Math.random() * 10000000000);
|
if(cmMsgIdFirst < 48 || cmMsgIdFirst > 57)
|
||||||
|
cmMsgInfo.msg.id = (Math.round(Number.MIN_SAFE_INTEGER * Math.random())).toString();
|
||||||
|
|
||||||
if(cmtextParts[1]) {
|
if(cmMsgInfo.msg.isBot) {
|
||||||
cmbotInfo.isError = cmtextParts[0] !== '0';
|
const cmBotParts = data[7].split("\f");
|
||||||
cmbotInfo.type = cmtextParts[1];
|
cmMsgInfo.msg.botInfo = {
|
||||||
cmbotInfo.args = cmtextParts.slice(2);
|
isError: cmBotParts[0] === '1',
|
||||||
cmtext = '';
|
type: cmBotParts[1],
|
||||||
} else
|
args: cmBotParts.slice(2),
|
||||||
cmtext = unfuckText(cmtext);
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Umi.Messages.Add(new Umi.Message(
|
watchers.call('msg:add', cmMsgInfo);
|
||||||
cmid, data[2], cmuser, cmtext, channelName, false, cmbotInfo,
|
|
||||||
cmflags[1] !== '0' && cmflags[3] === '0', true
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2': // channels
|
case '2': // channels
|
||||||
const ecpamount = +data[2];
|
const ecpamount = parseInt(data[2]);
|
||||||
let ecpstart = 3;
|
|
||||||
|
|
||||||
for(let i = 0; i < ecpamount; i++) {
|
for(let i = 0; i < ecpamount; ++i) {
|
||||||
const channel = new Umi.Channel(
|
const ecpoffset = 3 + 3 * i;
|
||||||
data[ecpstart],
|
|
||||||
data[ecpstart + 1] !== '0',
|
|
||||||
data[ecpstart + 2] !== '0'
|
|
||||||
);
|
|
||||||
Umi.Channels.Add(channel);
|
|
||||||
|
|
||||||
if(channel.getName() === channelName)
|
watchers.call('chan:add', {
|
||||||
Umi.Channels.Switch(channel);
|
channel: {
|
||||||
|
name: data[ecpoffset],
|
||||||
ecpstart = ecpstart + 3;
|
hasPassword: data[ecpoffset + 1] !== '0',
|
||||||
|
isTemporary: data[ecpoffset + 2] !== '0',
|
||||||
|
isCurrent: data[ecpoffset] === selfChannelName,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watchers.call('chan:focus', {
|
||||||
|
channel: { name: selfChannelName },
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '8': // context clear
|
case '8': // context clear
|
||||||
const cckeep = Umi.Users.Get(userId);
|
if(data[1] === '0' || data[1] === '3' || data[1] === '4')
|
||||||
|
watchers.call('msg:clear');
|
||||||
|
|
||||||
switch(data[1]) {
|
if(data[1] === '1' || data[1] === '3' || data[1] === '4')
|
||||||
case '0':
|
watchers.call('user:clear');
|
||||||
Umi.UI.Messages.RemoveAll();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
if(data[1] === '2' || data[1] === '4')
|
||||||
Umi.Users.Clear();
|
watchers.call('chan:clear');
|
||||||
Umi.Users.Add(cckeep);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '2':
|
|
||||||
Umi.Channels.Clear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '3':
|
|
||||||
Umi.Messages.Clear();
|
|
||||||
Umi.Users.Clear();
|
|
||||||
Umi.Users.Add(cckeep);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '4':
|
|
||||||
Umi.UI.Messages.RemoveAll();
|
|
||||||
Umi.Users.Clear();
|
|
||||||
Umi.Users.Add(cckeep);
|
|
||||||
Umi.Channels.Clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '9': // baka
|
case '9': // baka
|
||||||
noReconnect = true;
|
noReconnect = true;
|
||||||
wasKicked = true;
|
wasKicked = true;
|
||||||
|
|
||||||
const isBan = data[1] !== '0';
|
const bakaInfo = {
|
||||||
|
session: { success: false },
|
||||||
let message = 'You were kicked, refresh to log back in!';
|
baka: {
|
||||||
if(isBan) {
|
type: data[1] === '0' ? 'kick' : 'ban',
|
||||||
if(data[2] === '-1') {
|
},
|
||||||
message = 'You have been banned till the end of time, please try again in a different dimension.';
|
};
|
||||||
} else {
|
if(bakaInfo.baka.type === 'ban') {
|
||||||
const until = new Date(parseInt(data[2]) * 1000);
|
bakaInfo.baka.perma = data[2] === '-1';
|
||||||
message = 'You were banned until {0}!'.replace('{0}', until.toLocaleString());
|
bakaInfo.baka.until = data[2] === '-1' ? undefined : new Date(parseInt(data[2]) * 1000);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon, header;
|
watchers.call('session:term', bakaInfo);
|
||||||
if(isBan) {
|
|
||||||
icon = 'hammer';
|
|
||||||
header = 'Banned!';
|
|
||||||
} else {
|
|
||||||
icon = 'bomb';
|
|
||||||
header = 'Kicked!';
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentView = views.currentElement();
|
|
||||||
|
|
||||||
MamiAnimate({
|
|
||||||
duration: 550,
|
|
||||||
easing: 'outExpo',
|
|
||||||
start: () => {
|
|
||||||
playBannedBgm(true);
|
|
||||||
playBannedSfx();
|
|
||||||
},
|
|
||||||
update: t => {
|
|
||||||
currentView.style.transform = `scale(${(1 - .5 * t)}, ${(1 - 1 * t)})`;
|
|
||||||
},
|
|
||||||
end: () => {
|
|
||||||
getLoadingOverlay(icon, header, message).then(() => {
|
|
||||||
playBannedBgm();
|
|
||||||
|
|
||||||
// there's currently no way to reconnect after a kick/ban so just dispose of the ui entirely
|
|
||||||
if(views.count() > 1)
|
|
||||||
views.shift();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '10': // user update
|
case '10': // user update
|
||||||
const spuser = Umi.Users.Get(+data[1]);
|
watchers.call('user:update', {
|
||||||
spuser.setName(data[2]);
|
user: {
|
||||||
spuser.setColour(data[3]);
|
id: data[1],
|
||||||
spuser.setPermissions(data[4]);
|
self: data[1] === selfUserId,
|
||||||
Umi.Users.Update(spuser.getId(), spuser);
|
name: data[2],
|
||||||
|
colour: parseUserColour(data[3]),
|
||||||
|
perms: parseUserPerms(data[4]),
|
||||||
|
permsRaw: data[4],
|
||||||
|
},
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const beginConnecting = function() {
|
const beginConnecting = () => {
|
||||||
|
sock?.close();
|
||||||
|
|
||||||
if(noReconnect)
|
if(noReconnect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
++connectAttempts;
|
UmiServers.getServer(server => {
|
||||||
|
watchers.call('conn:init', {
|
||||||
|
server: server,
|
||||||
|
wasConnected: wasConnected,
|
||||||
|
attempt: ++connectAttempts,
|
||||||
|
});
|
||||||
|
|
||||||
let str = 'Connecting to server...';
|
sock = new UmiWebSocket(server, ev => {
|
||||||
if(connectAttempts > 1)
|
|
||||||
str += ' (Attempt ' + connectAttempts.toString() + ')';
|
|
||||||
|
|
||||||
getLoadingOverlay('spinner', 'Loading...', str);
|
|
||||||
|
|
||||||
UmiServers.getServer(function(server) {
|
|
||||||
if(settings.get('dumpPackets'))
|
|
||||||
console.log('Connecting to ' + server);
|
|
||||||
|
|
||||||
sock = new UmiWebSocket(server, function(ev) {
|
|
||||||
switch(ev.act) {
|
switch(ev.act) {
|
||||||
case 'ws:open':
|
case 'ws:open':
|
||||||
onOpen(ev);
|
onOpen(ev);
|
||||||
|
@ -554,6 +548,16 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
||||||
case 'ws:message':
|
case 'ws:message':
|
||||||
onMessage(ev);
|
onMessage(ev);
|
||||||
break;
|
break;
|
||||||
|
case 'ws:create_interval':
|
||||||
|
pingTimer = ev.id;
|
||||||
|
break;
|
||||||
|
case 'ws:call_interval':
|
||||||
|
if(ev.id === pingTimer)
|
||||||
|
onSendPing();
|
||||||
|
break;
|
||||||
|
case 'ws:clear_intervals':
|
||||||
|
pingTimer = undefined;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(ev.data);
|
console.log(ev.data);
|
||||||
break;
|
break;
|
||||||
|
@ -562,26 +566,35 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Umi.Channels.OnSwitch.push(function(old, channel) {
|
return {
|
||||||
if(channel.isUserChannel()) {
|
sendMessage: sendMessage,
|
||||||
pmUserName = channel.getName().substring(1);
|
open: () => {
|
||||||
} else {
|
noReconnect = false;
|
||||||
pmUserName = null;
|
beginConnecting();
|
||||||
switchChannel(channel.getName());
|
},
|
||||||
}
|
close: () => {
|
||||||
});
|
noReconnect = true;
|
||||||
|
sock?.close();
|
||||||
|
},
|
||||||
|
watch: (name, handler) => watchers.watch(name, handler),
|
||||||
|
unwatch: (name, handler) => watchers.unwatch(name, handler),
|
||||||
|
setDumpPackets: state => dumpPackets = !!state,
|
||||||
|
switchChannel: channelInfo => {
|
||||||
|
if(selfUserId === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
pub.sendMessage = sendMessage;
|
const name = channelInfo.getName();
|
||||||
|
|
||||||
pub.open = function() {
|
if(channelInfo.isUserChannel()) {
|
||||||
noReconnect = false;
|
selfPseudoChannelName = name.substring(1);
|
||||||
beginConnecting();
|
} else {
|
||||||
|
selfPseudoChannelName = undefined;
|
||||||
|
if(selfChannelName === name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selfChannelName = name;
|
||||||
|
sendMessage(`/join ${name}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub.close = function() {
|
|
||||||
noReconnect = true;
|
|
||||||
sock.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
return pub;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,6 +47,7 @@ Umi.UI.Hooks = (function() {
|
||||||
|
|
||||||
Umi.Channels.OnSwitch.push(function(name, channel) {
|
Umi.Channels.OnSwitch.push(function(name, channel) {
|
||||||
Umi.UI.Channels.Reload(name === null);
|
Umi.UI.Channels.Reload(name === null);
|
||||||
|
Umi.Server.switchChannel(channel);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -358,6 +358,11 @@ Umi.UI.Settings = (function() {
|
||||||
title: 'Dump packets to console',
|
title: 'Dump packets to console',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'dumpEvents',
|
||||||
|
title: 'Dump events to console',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'neverUseWorker',
|
name: 'neverUseWorker',
|
||||||
title: 'Never use Worker for connection',
|
title: 'Never use Worker for connection',
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include utility.js
|
#include utility.js
|
||||||
|
|
||||||
const MamiWatcher = function() {
|
const MamiWatcher = function(initCall) {
|
||||||
|
if(typeof initCall !== 'boolean')
|
||||||
|
initCall = true;
|
||||||
|
|
||||||
const handlers = [];
|
const handlers = [];
|
||||||
|
|
||||||
const watch = (handler, ...args) => {
|
const watch = (handler, ...args) => {
|
||||||
|
@ -10,8 +13,11 @@ const MamiWatcher = function() {
|
||||||
throw 'handler already registered';
|
throw 'handler already registered';
|
||||||
|
|
||||||
handlers.push(handler);
|
handlers.push(handler);
|
||||||
args.push(true);
|
|
||||||
handler(...args);
|
if(initCall) {
|
||||||
|
args.push(true);
|
||||||
|
handler(...args);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const unwatch = handler => {
|
const unwatch = handler => {
|
||||||
|
@ -22,7 +28,8 @@ const MamiWatcher = function() {
|
||||||
watch: watch,
|
watch: watch,
|
||||||
unwatch: unwatch,
|
unwatch: unwatch,
|
||||||
call: (...args) => {
|
call: (...args) => {
|
||||||
args.push(false);
|
if(initCall)
|
||||||
|
args.push(false);
|
||||||
|
|
||||||
for(const handler of handlers)
|
for(const handler of handlers)
|
||||||
handler(...args);
|
handler(...args);
|
||||||
|
@ -30,7 +37,10 @@ const MamiWatcher = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const MamiWatchers = function() {
|
const MamiWatchers = function(initCall) {
|
||||||
|
if(typeof initCall !== 'boolean')
|
||||||
|
initCall = true;
|
||||||
|
|
||||||
const watchers = new Map;
|
const watchers = new Map;
|
||||||
|
|
||||||
const getWatcher = name => {
|
const getWatcher = name => {
|
||||||
|
@ -53,10 +63,10 @@ const MamiWatchers = function() {
|
||||||
unwatch: unwatch,
|
unwatch: unwatch,
|
||||||
define: names => {
|
define: names => {
|
||||||
if(typeof names === 'string')
|
if(typeof names === 'string')
|
||||||
watchers.set(names, new MamiWatcher);
|
watchers.set(names, new MamiWatcher(initCall));
|
||||||
else if(Array.isArray(names))
|
else if(Array.isArray(names))
|
||||||
for(const name of names)
|
for(const name of names)
|
||||||
watchers.set(name, new MamiWatcher);
|
watchers.set(name, new MamiWatcher(initCall));
|
||||||
else
|
else
|
||||||
throw 'names must be an array of names or a single name';
|
throw 'names must be an array of names or a single name';
|
||||||
},
|
},
|
||||||
|
|
|
@ -91,10 +91,15 @@ const UmiWebSocket = function(server, message, useWorker) {
|
||||||
return intervals;
|
return intervals;
|
||||||
};
|
};
|
||||||
sendInterval = function(text, interval) {
|
sendInterval = function(text, interval) {
|
||||||
intervals.push(setInterval(function() {
|
const intervalId = setInterval(function() {
|
||||||
if(websocket)
|
if(websocket) {
|
||||||
websocket.send(text);
|
websocket.send(text);
|
||||||
}, interval));
|
message({ act: 'ws:call_interval', id: intervalId });
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
|
||||||
|
intervals.push(intervalId);
|
||||||
|
message({ act: 'ws:create_interval', id: intervalId });
|
||||||
};
|
};
|
||||||
clearIntervals = function() {
|
clearIntervals = function() {
|
||||||
for(let i = 0; i < intervals.length; ++i)
|
for(let i = 0; i < intervals.length; ++i)
|
||||||
|
|
|
@ -75,10 +75,15 @@ addEventListener('message', function(ev) {
|
||||||
|
|
||||||
case 'ws:send_interval':
|
case 'ws:send_interval':
|
||||||
(function(interval, text) {
|
(function(interval, text) {
|
||||||
intervals.push(setInterval(function() {
|
const intervalId = setInterval(function() {
|
||||||
if(websocket)
|
if(websocket) {
|
||||||
websocket.send(text);
|
websocket.send(text);
|
||||||
}, interval));
|
postMessage({ act: 'ws:call_interval', id: intervalId });
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
|
||||||
|
intervals.push(intervalId);
|
||||||
|
postMessage({ act: 'ws:create_interval', id: intervalId });
|
||||||
})(ev.data.interval, ev.data.text);
|
})(ev.data.interval, ev.data.text);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue