serverless-ircd 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +6 -1
- package/.gitmodules +3 -0
- package/CHANGELOG.md +214 -0
- package/README.md +110 -23
- package/apps/aws-stack/package.json +1 -1
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/src/origin-allowlist.ts +99 -0
- package/apps/cf-worker/src/worker.ts +89 -9
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
- package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
- package/apps/cf-worker/tests/smoke.test.ts +28 -2
- package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
- package/apps/cf-worker/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +54 -0
- package/apps/local-cli/package.json +1 -1
- package/apps/web/landing/index.html +217 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +125 -0
- package/apps/web/src/build-env.ts +43 -0
- package/apps/web/src/config-schema.ts +138 -0
- package/apps/web/static/config.json +28 -0
- package/apps/web/static/config.prod.json +28 -0
- package/apps/web/static/config.staging.json +28 -0
- package/apps/web/tests/build-env.test.ts +63 -0
- package/apps/web/tests/build-smoke.test.ts +103 -0
- package/apps/web/tests/config-schema.test.ts +432 -0
- package/apps/web/tests/workspace.test.ts +12 -0
- package/apps/web/tsconfig.json +10 -0
- package/apps/web/upstream/.browserslistrc +3 -0
- package/apps/web/upstream/.editorconfig +9 -0
- package/apps/web/upstream/.eslintignore +3 -0
- package/apps/web/upstream/.eslintrc.js +90 -0
- package/apps/web/upstream/.github/FUNDING.yml +12 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/apps/web/upstream/.github/workflows/push.yml +26 -0
- package/apps/web/upstream/.github/workflows/release.yml +33 -0
- package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
- package/apps/web/upstream/.prettierrc.js +9 -0
- package/apps/web/upstream/.stylelintignore +5 -0
- package/apps/web/upstream/.stylelintrc.js +21 -0
- package/apps/web/upstream/LICENSE +201 -0
- package/apps/web/upstream/README.md +76 -0
- package/apps/web/upstream/babel.config.js +25 -0
- package/apps/web/upstream/crowdin.yml +3 -0
- package/apps/web/upstream/index.html +35 -0
- package/apps/web/upstream/jest.config.js +7 -0
- package/apps/web/upstream/jsdoc.json +22 -0
- package/apps/web/upstream/package.json +80 -0
- package/apps/web/upstream/scripts/pre-commit +43 -0
- package/apps/web/upstream/src/components/App.vue +516 -0
- package/apps/web/upstream/src/components/AppSettings.vue +587 -0
- package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
- package/apps/web/upstream/src/components/Avatar.vue +105 -0
- package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
- package/apps/web/upstream/src/components/BufferKey.vue +121 -0
- package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
- package/apps/web/upstream/src/components/Captcha.vue +85 -0
- package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
- package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
- package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
- package/apps/web/upstream/src/components/ChannelList.vue +345 -0
- package/apps/web/upstream/src/components/Container.vue +401 -0
- package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
- package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
- package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
- package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
- package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
- package/apps/web/upstream/src/components/MessageList.vue +1028 -0
- package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
- package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
- package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
- package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
- package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
- package/apps/web/upstream/src/components/Nicklist.vue +309 -0
- package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
- package/apps/web/upstream/src/components/NotConnected.vue +271 -0
- package/apps/web/upstream/src/components/SelfUser.vue +283 -0
- package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
- package/apps/web/upstream/src/components/ServerView.vue +126 -0
- package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
- package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
- package/apps/web/upstream/src/components/Sidebar.vue +429 -0
- package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
- package/apps/web/upstream/src/components/SidebarState.vue +145 -0
- package/apps/web/upstream/src/components/StartupError.vue +35 -0
- package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
- package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
- package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
- package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
- package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
- package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
- package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
- package/apps/web/upstream/src/components/UserBox.vue +728 -0
- package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
- package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
- package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
- package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
- package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
- package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
- package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
- package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
- package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
- package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
- package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
- package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
- package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
- package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
- package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
- package/apps/web/upstream/src/helpers/Colours.js +128 -0
- package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
- package/apps/web/upstream/src/helpers/Md5.js +193 -0
- package/apps/web/upstream/src/helpers/Misc.js +401 -0
- package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
- package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
- package/apps/web/upstream/src/libs/AudioManager.js +60 -0
- package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
- package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
- package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
- package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
- package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
- package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
- package/apps/web/upstream/src/libs/IPC.js +51 -0
- package/apps/web/upstream/src/libs/InputHandler.js +921 -0
- package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
- package/apps/web/upstream/src/libs/Logger.js +71 -0
- package/apps/web/upstream/src/libs/Message.js +169 -0
- package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
- package/apps/web/upstream/src/libs/MessageParser.js +249 -0
- package/apps/web/upstream/src/libs/Notifications.js +78 -0
- package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
- package/apps/web/upstream/src/libs/ServerSession.js +102 -0
- package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
- package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
- package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
- package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
- package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
- package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
- package/apps/web/upstream/src/libs/bufferTools.js +177 -0
- package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
- package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
- package/apps/web/upstream/src/libs/settingTools.js +31 -0
- package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
- package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
- package/apps/web/upstream/src/libs/state/UserState.js +89 -0
- package/apps/web/upstream/src/libs/state/common.js +26 -0
- package/apps/web/upstream/src/libs/state.js +961 -0
- package/apps/web/upstream/src/libs/storage/Local.js +51 -0
- package/apps/web/upstream/src/main.js +566 -0
- package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
- package/apps/web/upstream/src/res/configTemplates.js +373 -0
- package/apps/web/upstream/src/res/globalStyle.css +277 -0
- package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
- package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
- package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
- package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
- package/apps/web/upstream/src/res/localesList.json +27 -0
- package/apps/web/upstream/src/res/logo.png +0 -0
- package/apps/web/upstream/src/thirdparty/about.html +43 -0
- package/apps/web/upstream/src/thirdparty/index.js +5 -0
- package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
- package/apps/web/upstream/static/config.json +28 -0
- package/apps/web/upstream/static/emoticons/smile.png +0 -0
- package/apps/web/upstream/static/favicon.png +0 -0
- package/apps/web/upstream/static/highlight.mp3 +0 -0
- package/apps/web/upstream/static/highlight.ogg +0 -0
- package/apps/web/upstream/static/locales/.gitignore +2 -0
- package/apps/web/upstream/static/plugins/customise.html.example +10 -0
- package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
- package/apps/web/upstream/static/themes/common/base.css +1064 -0
- package/apps/web/upstream/static/themes/dark/theme.css +196 -0
- package/apps/web/upstream/static/themes/default/theme.css +92 -0
- package/apps/web/upstream/static/themes/elite/theme.css +248 -0
- package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
- package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
- package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
- package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
- package/apps/web/upstream/static/themes/sky/theme.css +107 -0
- package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
- package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
- package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
- package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
- package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
- package/apps/web/upstream/vue.config.js +150 -0
- package/apps/web/upstream/yarn.lock +9767 -0
- package/apps/web/vitest.config.ts +13 -0
- package/biome.json +1 -0
- package/docs/Home.md +1 -0
- package/docs/WebClientGuide.md +535 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/cf-adapter/package.json +1 -1
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/reports/mutation/mutation.html +342 -0
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/numerics.test.ts +13 -0
- package/packages/irc-core/tests/parser.test.ts +109 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/tools/ci-hardening/package.json +1 -1
- package/tools/load-test/package.json +1 -1
- package/tools/tcp-ws-forwarder/package.json +1 -1
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
/** @module */
|
|
2
|
+
|
|
3
|
+
import Vue from 'vue';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import { def } from './common';
|
|
6
|
+
import batchedAdd from '../batchedAdd';
|
|
7
|
+
import * as bufferTools from '../bufferTools';
|
|
8
|
+
|
|
9
|
+
let nextBufferId = 0;
|
|
10
|
+
|
|
11
|
+
/** The IRC buffer instance */
|
|
12
|
+
export default class BufferState {
|
|
13
|
+
constructor(name, networkid, state, messageDict) {
|
|
14
|
+
// Enumerable properties that become reactive under Vue
|
|
15
|
+
this.id = nextBufferId++;
|
|
16
|
+
this.networkid = networkid;
|
|
17
|
+
this.name = name;
|
|
18
|
+
this.topics = [];
|
|
19
|
+
this.key = '';
|
|
20
|
+
this.joined = false;
|
|
21
|
+
this.enabled = true;
|
|
22
|
+
this.created_at = null;
|
|
23
|
+
this.users = Object.create(null);
|
|
24
|
+
this.modes = Object.create(null);
|
|
25
|
+
this.flags = {
|
|
26
|
+
unread: 0,
|
|
27
|
+
highlight: false,
|
|
28
|
+
has_opened: false,
|
|
29
|
+
channel_badkey: false,
|
|
30
|
+
chathistory_available: true,
|
|
31
|
+
requested_modes: false,
|
|
32
|
+
requested_banlist: false,
|
|
33
|
+
is_requesting_chathistory: false,
|
|
34
|
+
};
|
|
35
|
+
this.settings = { };
|
|
36
|
+
this.last_read = 0;
|
|
37
|
+
this.active_timeout = null;
|
|
38
|
+
this.message_count = 0;
|
|
39
|
+
this.current_input = '';
|
|
40
|
+
this.input_history = [];
|
|
41
|
+
this.input_history_pos = 0;
|
|
42
|
+
this.show_input = true;
|
|
43
|
+
this.latest_messages = [];
|
|
44
|
+
|
|
45
|
+
// Counter for chathistory requests. While this value is 0, it means that this buffer is
|
|
46
|
+
// still loading messages
|
|
47
|
+
this.chathistory_request_count = 0;
|
|
48
|
+
|
|
49
|
+
Vue.observable(this);
|
|
50
|
+
|
|
51
|
+
// Some non-enumerable properties (vues $watch won't cover these properties)
|
|
52
|
+
def(this, 'state', state, false);
|
|
53
|
+
def(this, 'messageDict', messageDict, false);
|
|
54
|
+
|
|
55
|
+
let messagesObj = {
|
|
56
|
+
networkid: this.networkid,
|
|
57
|
+
buffer: this.name,
|
|
58
|
+
messages: [],
|
|
59
|
+
messageIds: Object.create(null),
|
|
60
|
+
};
|
|
61
|
+
this.messageDict.push(messagesObj);
|
|
62
|
+
def(this, 'messagesObj', messagesObj, false);
|
|
63
|
+
|
|
64
|
+
def(this, 'isMessageTrimming', true, true);
|
|
65
|
+
def(this, 'addMessageBatch', createMessageBatch(this), false);
|
|
66
|
+
def(this, 'addUserBatch', createUserBatch(this), false);
|
|
67
|
+
|
|
68
|
+
// poll who to update away status if away-notify is not enabled
|
|
69
|
+
if (this.isChannel()) {
|
|
70
|
+
maybeStartWhoLoop(this);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// When the network re-connects, we reset the chathistory request counter.
|
|
74
|
+
// This will make the `getLoadingState()` stay as 'loading' while the chathistory reloads.
|
|
75
|
+
function onNetworkConnecting(event) {
|
|
76
|
+
if (event.network === this.getNetwork()) {
|
|
77
|
+
this.chathistory_request_count = 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function onNetworkMotd(event, network) {
|
|
82
|
+
const bufferNetwork = this.getNetwork();
|
|
83
|
+
if (
|
|
84
|
+
network !== bufferNetwork
|
|
85
|
+
|| !bufferNetwork.ircClient.chathistory.isSupported()
|
|
86
|
+
|| !this.isQuery()
|
|
87
|
+
) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (['all', 'queries'].includes(this.setting('auto_request_history'))) {
|
|
92
|
+
this.requestLatestScrollback();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Clean up the previous event and itself when the buffer is closed.
|
|
97
|
+
function onBufferClose(event) {
|
|
98
|
+
if (event.buffer === this) {
|
|
99
|
+
this.state.$off('network.connecting', onNetworkConnectingBound);
|
|
100
|
+
this.state.$off('buffer.close', onBufferCloseBound);
|
|
101
|
+
this.state.$off('irc.motd', onNetworkMotdBound);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const onNetworkConnectingBound = onNetworkConnecting.bind(this);
|
|
106
|
+
const onBufferCloseBound = onBufferClose.bind(this);
|
|
107
|
+
const onNetworkMotdBound = onNetworkMotd.bind(this);
|
|
108
|
+
|
|
109
|
+
state.$on('network.connecting', onNetworkConnectingBound);
|
|
110
|
+
state.$on('buffer.close', onBufferCloseBound);
|
|
111
|
+
state.$on('irc.motd', onNetworkMotdBound);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get topic() {
|
|
115
|
+
return this.topics.length === 0 ?
|
|
116
|
+
'' :
|
|
117
|
+
this.topics[this.topics.length - 1];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set topic(newVal) {
|
|
121
|
+
this.topics.push(newVal);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getNetwork() {
|
|
125
|
+
return this.state.getNetwork(this.networkid);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getMessages() {
|
|
129
|
+
let bufMessages = _.find(this.messageDict, {
|
|
130
|
+
networkid: this.networkid,
|
|
131
|
+
buffer: this.name,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return bufMessages ?
|
|
135
|
+
bufMessages.messages :
|
|
136
|
+
[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getLastMessage() {
|
|
140
|
+
let messages = this.getMessages();
|
|
141
|
+
if (messages.length === 0) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
return messages[messages.length - 1];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
clearMessages() {
|
|
148
|
+
this.messagesObj.messages.splice(0, this.messagesObj.messages.length);
|
|
149
|
+
this.messagesObj.messageIds = Object.create(null);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Remove a block of messages between a time (server-time) range. Inclusive.
|
|
153
|
+
clearMessageRange(startTime, endTime) {
|
|
154
|
+
this.messagesObj.messages = this.messagesObj.messages.filter((message) => {
|
|
155
|
+
if (message.server_time < startTime || message.server_time > endTime) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// This message will be removed
|
|
160
|
+
delete this.messagesObj.messageIds[message.id];
|
|
161
|
+
return false;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Mark that something changed
|
|
165
|
+
this.message_count++;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isServer() {
|
|
169
|
+
return this.name === '*';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
isRaw() {
|
|
173
|
+
return this.name === '*raw';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
isChannel() {
|
|
177
|
+
let chanPrefixes = ['#', '&'];
|
|
178
|
+
let ircNetwork = this.getNetwork().ircClient.network;
|
|
179
|
+
if (ircNetwork && ircNetwork.options.CHANTYPES) {
|
|
180
|
+
chanPrefixes = ircNetwork.options.CHANTYPES;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return chanPrefixes.indexOf(this.name[0]) > -1;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
isQuery() {
|
|
187
|
+
let chanPrefixes = ['#', '&'];
|
|
188
|
+
let ircNetwork = this.getNetwork().ircClient.network;
|
|
189
|
+
if (ircNetwork && ircNetwork.options.CHANTYPES) {
|
|
190
|
+
chanPrefixes = ircNetwork.options.CHANTYPES;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return chanPrefixes.indexOf(this.name[0]) === -1 &&
|
|
194
|
+
!this.isSpecial() &&
|
|
195
|
+
!this.isServer();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
isSpecial() {
|
|
199
|
+
// Special buffer names (Usually controller queries, like *status or *raw).
|
|
200
|
+
// Server buffer '*' is not included in this classification.
|
|
201
|
+
let name = this.name;
|
|
202
|
+
return name[0] === '*' && name.length > 1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
isUserAnOp(nick) {
|
|
206
|
+
let user = this.state.getUser(this.networkid, nick);
|
|
207
|
+
if (!user) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let userBufferInfo = user.buffers[this.id];
|
|
212
|
+
if (!userBufferInfo) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let modes = userBufferInfo.modes;
|
|
217
|
+
let opModes = ['Y', 'y', 'q', 'a', 'o', 'h'];
|
|
218
|
+
let hasOp = _.find(modes, (mode) => opModes.indexOf(mode.toLowerCase()) > -1);
|
|
219
|
+
|
|
220
|
+
return !!hasOp;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get a users prefix symbol on a buffer from its modes
|
|
225
|
+
* @param {Object} user The user object
|
|
226
|
+
*/
|
|
227
|
+
userModePrefix(user) {
|
|
228
|
+
// The user may not be on the buffer
|
|
229
|
+
if (!user.buffers[this.id]) {
|
|
230
|
+
return '';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
let modes = user.buffers[this.id].modes;
|
|
234
|
+
if (modes.length === 0) {
|
|
235
|
+
return '';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let network = this.getNetwork();
|
|
239
|
+
let netPrefixes = network.ircClient.network.options.PREFIX;
|
|
240
|
+
// Find the first (highest) netPrefix in the users buffer modes
|
|
241
|
+
let prefix = _.find(netPrefixes, (p) => modes.indexOf(p.mode) > -1);
|
|
242
|
+
|
|
243
|
+
return prefix ?
|
|
244
|
+
prefix.symbol :
|
|
245
|
+
'';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get a users mode on a buffer
|
|
250
|
+
* @param user {Object} The user object
|
|
251
|
+
*/
|
|
252
|
+
userMode(user) {
|
|
253
|
+
// The user may not be on the buffer
|
|
254
|
+
if (!user.buffers[this.id]) {
|
|
255
|
+
return '';
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let modes = user.buffers[this.id].modes;
|
|
259
|
+
if (modes.length === 0) {
|
|
260
|
+
return '';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// if there is only one mode just return it
|
|
264
|
+
if (modes.length === 1) {
|
|
265
|
+
return modes[0];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let network = this.getNetwork();
|
|
269
|
+
let netPrefixes = network.ircClient.network.options.PREFIX;
|
|
270
|
+
// Find the first (highest) netPrefix in the users buffer modes
|
|
271
|
+
let prefix = _.find(netPrefixes, (p) => modes.indexOf(p.mode) > -1);
|
|
272
|
+
|
|
273
|
+
return prefix ?
|
|
274
|
+
prefix.mode :
|
|
275
|
+
'';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
setting(name, val) {
|
|
279
|
+
if (typeof val !== 'undefined') {
|
|
280
|
+
this.state.$set(this.settings, name, val);
|
|
281
|
+
return val;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Check the buffer specific settings before reverting to global settings
|
|
285
|
+
let result = typeof this.settings[name] !== 'undefined' ?
|
|
286
|
+
this.settings[name] :
|
|
287
|
+
this.state.setting('buffers.' + name);
|
|
288
|
+
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
rename(newName) {
|
|
293
|
+
let network = this.getNetwork();
|
|
294
|
+
let oldName = this.name;
|
|
295
|
+
let setActive = this.state.getActiveBuffer() === this;
|
|
296
|
+
|
|
297
|
+
this.name = newName;
|
|
298
|
+
if (setActive) {
|
|
299
|
+
this.state.setActiveBuffer(network.id, newName);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// update the buffer name on our messages
|
|
303
|
+
let bufferMessages = _.find(this.messageDict, { networkid: network.id, buffer: oldName });
|
|
304
|
+
bufferMessages.buffer = newName;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
flag(name, val) {
|
|
308
|
+
if (typeof val !== 'undefined') {
|
|
309
|
+
this.state.$set(this.flags, name, val);
|
|
310
|
+
return val;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return this.flags[name];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
requestScrollback(_direction) {
|
|
317
|
+
let direction = _direction || 'backward';
|
|
318
|
+
let time = '';
|
|
319
|
+
let chathistoryFuncName = 'before';
|
|
320
|
+
|
|
321
|
+
// Going backwards takes the earliest message we already have and requests messages
|
|
322
|
+
// before it. Going forward takes the last message we have and requests messages after
|
|
323
|
+
// it.
|
|
324
|
+
|
|
325
|
+
if (direction === 'backward') {
|
|
326
|
+
let lastMessage = this.getMessages().reduce((earliest, current) => {
|
|
327
|
+
let ignoreTypes = ['traffic', 'topic', 'connection', 'presence'];
|
|
328
|
+
let validType = ignoreTypes.indexOf(earliest.type) === -1;
|
|
329
|
+
if (validType && earliest.time && earliest.time < current.time) {
|
|
330
|
+
return earliest;
|
|
331
|
+
}
|
|
332
|
+
return current;
|
|
333
|
+
}, this.getMessages()[0]);
|
|
334
|
+
|
|
335
|
+
chathistoryFuncName = 'before';
|
|
336
|
+
time = lastMessage ?
|
|
337
|
+
new Date(lastMessage.server_time) :
|
|
338
|
+
new Date();
|
|
339
|
+
} else if (direction === 'forward') {
|
|
340
|
+
let firstMessage = this.getMessages().reduce((latest, current) => {
|
|
341
|
+
let ignoreTypes = ['traffic', 'topic', 'connection', 'presence'];
|
|
342
|
+
let validType = ignoreTypes.indexOf(latest.type) === -1;
|
|
343
|
+
if (validType && latest.time && latest.time > current.time) {
|
|
344
|
+
return latest;
|
|
345
|
+
}
|
|
346
|
+
return current;
|
|
347
|
+
}, this.getMessages()[0]);
|
|
348
|
+
|
|
349
|
+
chathistoryFuncName = 'after';
|
|
350
|
+
time = firstMessage ?
|
|
351
|
+
new Date(firstMessage.server_time) :
|
|
352
|
+
new Date();
|
|
353
|
+
} else {
|
|
354
|
+
throw new Error('Invalid direction for requestScrollback(): ' + _direction);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
getBufferHistory(this, chathistoryFuncName, time);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
requestLatestScrollback() {
|
|
361
|
+
getBufferHistory(this, 'latest', '*');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
markAsRead(delayed) {
|
|
365
|
+
if (this.active_timeout) {
|
|
366
|
+
clearTimeout(this.active_timeout);
|
|
367
|
+
this.active_timeout = null;
|
|
368
|
+
}
|
|
369
|
+
if (delayed) {
|
|
370
|
+
this.active_timeout = setTimeout(
|
|
371
|
+
this.markAsRead.bind(this),
|
|
372
|
+
10000,
|
|
373
|
+
false
|
|
374
|
+
);
|
|
375
|
+
} else {
|
|
376
|
+
this.last_read = Date.now();
|
|
377
|
+
this.flag('highlight', false);
|
|
378
|
+
|
|
379
|
+
// If running under a bouncer, set it on the server-side too
|
|
380
|
+
let network = this.getNetwork();
|
|
381
|
+
let allowedUpdate = !network ? false : this.isChannel() || this.isQuery();
|
|
382
|
+
if (allowedUpdate && network.connection.bncnetid) {
|
|
383
|
+
network.ircClient.bnc.bufferSeen(network.connection.bncnetid, this.name);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
incrementFlag(flagName) {
|
|
389
|
+
this.flags[flagName] = (this.flags[flagName] || 0) + 1;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
addUser(user) {
|
|
393
|
+
this.addUserBatch(user);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
hasNick(nick) {
|
|
397
|
+
let nickUpper = nick.toUpperCase();
|
|
398
|
+
return (
|
|
399
|
+
nickUpper in this.users
|
|
400
|
+
|| this.addUserBatch.queue().some((u) => u.nick.toUpperCase() === nickUpper)
|
|
401
|
+
|| (this.isQuery() && this.name.toUpperCase() === nickUpper)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
hasMode(mode) {
|
|
406
|
+
return Object.keys(this.modes).indexOf(mode) > -1;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
shouldShareTyping() {
|
|
410
|
+
let network = this.getNetwork();
|
|
411
|
+
if (!this.setting('share_typing')) {
|
|
412
|
+
// Feature disabled
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
if (!this.isChannel() && !this.isQuery()) {
|
|
416
|
+
// Qnly share tying with channels and queries
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
if (this.isChannel() && !this.joined) {
|
|
420
|
+
// Channel is in an unjoined state
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (this.hasMode('m') && !this.userMode(network.currentUser())) {
|
|
424
|
+
// Channel is moderated (+m) and we do not have a user mode +v or above
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
removeUser(nick) {
|
|
431
|
+
let userObj = this.state.getUser(this.networkid, nick);
|
|
432
|
+
|
|
433
|
+
// A user could be queued to be added, so make sure it's not there as it
|
|
434
|
+
// would just be added again. Eg. user joins/parts during a flood
|
|
435
|
+
_.pull(this.addUserBatch.queue(), userObj);
|
|
436
|
+
|
|
437
|
+
this.state.$delete(this.users, nick.toUpperCase());
|
|
438
|
+
|
|
439
|
+
if (userObj) {
|
|
440
|
+
delete userObj.buffers[this.id];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
clearUsers() {
|
|
445
|
+
// Users could be queued to be added, so make sure to clear them as they
|
|
446
|
+
// would just be added again. Eg. user joins/parts during a flood
|
|
447
|
+
this.addUserBatch && this.addUserBatch.queue().splice(0);
|
|
448
|
+
|
|
449
|
+
_.each(this.users, (userObj, nick) => {
|
|
450
|
+
delete userObj.buffers[this.id];
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
this.state.$set(this, 'users', {});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
addMessage(message) {
|
|
457
|
+
this.addMessageBatch(message);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
updateLatestMessages(message) {
|
|
461
|
+
if (!['privmsg', 'notice'].includes(message.type)) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const isNewer = (msg) => this.latest_messages[0].time <= msg.time &&
|
|
466
|
+
this.latest_messages[0].instance_num < msg.instance_num;
|
|
467
|
+
|
|
468
|
+
if (!this.latest_messages[0] || isNewer(message)) {
|
|
469
|
+
this.latest_messages.unshift(message);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (this.latest_messages.length > 5) {
|
|
473
|
+
// restrict array to 5 elements
|
|
474
|
+
this.latest_messages.length = 5;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
getLatestMessage() {
|
|
479
|
+
return this.latest_messages[0];
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
say(message, opts = {}) {
|
|
483
|
+
let network = this.getNetwork();
|
|
484
|
+
let newMessage = {
|
|
485
|
+
time: Date.now(),
|
|
486
|
+
nick: network.nick,
|
|
487
|
+
message: message,
|
|
488
|
+
tags: opts.tags || {},
|
|
489
|
+
type: opts.type || 'privmsg',
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
this.state.addMessage(this, newMessage);
|
|
493
|
+
|
|
494
|
+
let fnNames = {
|
|
495
|
+
privmsg: 'say',
|
|
496
|
+
action: 'action',
|
|
497
|
+
notice: 'notice',
|
|
498
|
+
tagmsg: 'tagmsg',
|
|
499
|
+
};
|
|
500
|
+
let fnName = fnNames[opts.type] || 'say';
|
|
501
|
+
network.ircClient[fnName](this.name, message, opts.tags);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
join() {
|
|
505
|
+
if (!this.isChannel()) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
let network = this.getNetwork();
|
|
510
|
+
network.ircClient.join(this.name, this.key || '');
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
part(reason) {
|
|
514
|
+
if (!this.isChannel()) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
let network = this.getNetwork();
|
|
519
|
+
network.ircClient.part(this.name, reason || '');
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
scrollToMessage(id) {
|
|
523
|
+
this.state.$emit('messagelist.scrollto', { id: id });
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
getLoadingState() {
|
|
527
|
+
const networkState = this.getNetwork().state;
|
|
528
|
+
const historySupport = !!this.getNetwork().ircClient.chathistory.isSupported();
|
|
529
|
+
const messagesInBatchQueue = this.addMessageBatch.queue().length;
|
|
530
|
+
// Hack; We need to make vue aware that we depend on message_count in order to
|
|
531
|
+
// update the loading state.
|
|
532
|
+
// eslint-disable-next-line no-unused-vars
|
|
533
|
+
const messageCount = this.message_count;
|
|
534
|
+
|
|
535
|
+
if (networkState === 'disconnected') {
|
|
536
|
+
return 'disconnected';
|
|
537
|
+
} else if (networkState === 'connecting') {
|
|
538
|
+
return 'connecting';
|
|
539
|
+
} else if (
|
|
540
|
+
networkState === 'connected' &&
|
|
541
|
+
this.enabled &&
|
|
542
|
+
(
|
|
543
|
+
historySupport &&
|
|
544
|
+
(this.flags.is_requesting_chathistory ||
|
|
545
|
+
// If chathistory is supported then a request will always be made when first
|
|
546
|
+
// joining a channel. If request_count===0 then we're still waiting for it
|
|
547
|
+
// to happen.
|
|
548
|
+
this.chathistory_request_count === 0 ||
|
|
549
|
+
// keep in loading state while the batch is being processed
|
|
550
|
+
messagesInBatchQueue > 0
|
|
551
|
+
)
|
|
552
|
+
)
|
|
553
|
+
) {
|
|
554
|
+
return 'loading';
|
|
555
|
+
}
|
|
556
|
+
return 'done';
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
isReady() {
|
|
560
|
+
return this.getLoadingState() === 'done';
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Batch up floods of addUsers for a huge performance gain.
|
|
566
|
+
* Generally happens when reconnecting to a BNC
|
|
567
|
+
*/
|
|
568
|
+
function createUserBatch(bufferState) {
|
|
569
|
+
let addSingleUser = (u) => {
|
|
570
|
+
bufferState.state.$set(bufferState.users, u.nick.toUpperCase(), u);
|
|
571
|
+
};
|
|
572
|
+
let addMultipleUsers = (users) => {
|
|
573
|
+
let o = Object.assign(Object.create(null), bufferState.users);
|
|
574
|
+
users.forEach((u) => {
|
|
575
|
+
o[u.nick.toUpperCase()] = u;
|
|
576
|
+
});
|
|
577
|
+
bufferState.users = o;
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
return batchedAdd(addSingleUser, addMultipleUsers, 2);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* batch up floods of new messages for a huge performance gain
|
|
585
|
+
*/
|
|
586
|
+
function createMessageBatch(bufferState) {
|
|
587
|
+
let addSingleMessage = (newMessage) => {
|
|
588
|
+
if (bufferState.messagesObj.messageIds[newMessage.id]) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
bufferState.updateLatestMessages(newMessage);
|
|
592
|
+
bufferState.messagesObj.messages.push(newMessage);
|
|
593
|
+
bufferState.messagesObj.messageIds[newMessage.id] = newMessage;
|
|
594
|
+
if (bufferState.isMessageTrimming) {
|
|
595
|
+
trimMessages();
|
|
596
|
+
}
|
|
597
|
+
bufferTools.orderedMessages(bufferState, { inPlace: true, noFilter: true });
|
|
598
|
+
bufferState.message_count++;
|
|
599
|
+
};
|
|
600
|
+
let addMultipleMessages = (newMessages) => {
|
|
601
|
+
let toAdd = newMessages.filter((msg) => !bufferState.messagesObj.messageIds[msg.id]);
|
|
602
|
+
if (toAdd.length > 0) {
|
|
603
|
+
bufferState.messagesObj.messages = bufferState.messagesObj.messages.concat(toAdd);
|
|
604
|
+
toAdd.forEach((msg) => {
|
|
605
|
+
bufferState.updateLatestMessages(msg);
|
|
606
|
+
bufferState.messagesObj.messageIds[msg.id] = msg;
|
|
607
|
+
});
|
|
608
|
+
if (bufferState.isMessageTrimming) {
|
|
609
|
+
trimMessages();
|
|
610
|
+
}
|
|
611
|
+
bufferTools.orderedMessages(bufferState, { inPlace: true, noFilter: true });
|
|
612
|
+
}
|
|
613
|
+
// Trigger Vue's reactivity on the buffer whether messages were added or not, just in case
|
|
614
|
+
// anything was depending on the batch queue which has now been emptied.
|
|
615
|
+
bufferState.message_count++;
|
|
616
|
+
};
|
|
617
|
+
let trimMessages = () => {
|
|
618
|
+
let scrollbackSize = bufferState.setting('scrollback_size');
|
|
619
|
+
let length = bufferState.messagesObj.messages.length;
|
|
620
|
+
if (bufferState.messagesObj.messages.length > scrollbackSize) {
|
|
621
|
+
let removed = bufferState.messagesObj.messages.splice(0, length - scrollbackSize);
|
|
622
|
+
removed.forEach((msg) => delete bufferState.messagesObj.messageIds[msg.id]);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
return batchedAdd(addSingleMessage, addMultipleMessages, 4);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Update our user list status every 30seconds to get each users current away status
|
|
630
|
+
function maybeStartWhoLoop(bufferState) {
|
|
631
|
+
let network = bufferState.state.getNetwork(bufferState.networkid);
|
|
632
|
+
|
|
633
|
+
if (network.state === 'connected') {
|
|
634
|
+
// network is connected start the loop if its needed
|
|
635
|
+
nextLoop();
|
|
636
|
+
} else {
|
|
637
|
+
// Network is not coonnected. Wait until it is
|
|
638
|
+
let on001 = (command, event, eventNetwork) => {
|
|
639
|
+
if (eventNetwork === network) {
|
|
640
|
+
bufferState.state.$off('irc.raw.001', on001);
|
|
641
|
+
nextLoop();
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
bufferState.state.$on('irc.raw.001', on001);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function nextLoop() {
|
|
648
|
+
setTimeout(updateWhoStatusLoop, 30000);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function updateWhoStatusLoop() {
|
|
652
|
+
network = bufferState.state.getNetwork(bufferState.networkid);
|
|
653
|
+
|
|
654
|
+
// Make sure the network still exists
|
|
655
|
+
if (!network) {
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Make sure the buffer still exists
|
|
660
|
+
if (!network.bufferByName(bufferState.name)) {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
let whoLoop = bufferState.setting('who_loop');
|
|
665
|
+
let isJoined = bufferState.joined;
|
|
666
|
+
let hasAwayNotify = network.ircClient.network.cap.isEnabled('away-notify');
|
|
667
|
+
let networkConnected = network.state === 'connected';
|
|
668
|
+
|
|
669
|
+
if (whoLoop && networkConnected && isJoined && !hasAwayNotify) {
|
|
670
|
+
network.ircClient.who(bufferState.name, () => {
|
|
671
|
+
nextLoop();
|
|
672
|
+
});
|
|
673
|
+
} else {
|
|
674
|
+
nextLoop();
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function getBufferHistory(buffer, chathistoryFuncName, time) {
|
|
680
|
+
let ircClient = buffer.getNetwork().ircClient;
|
|
681
|
+
buffer.flag('is_requesting_chathistory', true);
|
|
682
|
+
buffer.chathistory_request_count += 1;
|
|
683
|
+
let existingMessageIds = Object.assign({}, buffer.messagesObj.messageIds);
|
|
684
|
+
ircClient.chathistory[chathistoryFuncName](buffer.name, time).then((event) => {
|
|
685
|
+
if (!event) {
|
|
686
|
+
buffer.flag('chathistory_available', false);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// The BNC server may reply with messages that are already in the buffer.
|
|
691
|
+
// If we get no new messages that we didn't already have, assume that we have
|
|
692
|
+
// all the available history
|
|
693
|
+
let hasNewMessages = event.commands.some(
|
|
694
|
+
(msg) => msg.tags.msgid && !existingMessageIds[msg.tags.msgid]
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
// If there are new messages, then there could be more in the backlog.
|
|
698
|
+
// If there are no new messages, then the chat history is empty.
|
|
699
|
+
buffer.flag('chathistory_available', hasNewMessages);
|
|
700
|
+
}).finally(() => {
|
|
701
|
+
buffer.flag('is_requesting_chathistory', false);
|
|
702
|
+
});
|
|
703
|
+
}
|