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,249 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
import { trim } from 'lodash';
|
|
4
|
+
|
|
5
|
+
import * as EmojiProvider from '@/libs/EmojiProvider';
|
|
6
|
+
import formatIrcMessage, { createNewBlock } from '@/libs/MessageFormatter';
|
|
7
|
+
import { urlRegex, channelRegex } from '@/helpers/TextFormatting';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Receives a message, parses its irc blocks, and then finds urls, users, channels and emoji. Each
|
|
11
|
+
* content is extracted to a separate block.
|
|
12
|
+
* E.g. the message:
|
|
13
|
+
* "this is a message www.google.com and #kiwiirc"
|
|
14
|
+
* will be split into the blocks:
|
|
15
|
+
* ["this is a message "]["www.google.com"][" and "]["#kiwiirc"]
|
|
16
|
+
* The special content blocks will also contain additional info about their content according to
|
|
17
|
+
* their type, such as the url, nick colour, emoji code...
|
|
18
|
+
* @param {Array} blocks Array of style blocks from MessageFormatter
|
|
19
|
+
* @param {Array} userList List of users to find within the message
|
|
20
|
+
* @returns An array of blocks, where each special content will be extracted into a separate block.
|
|
21
|
+
*/
|
|
22
|
+
export default function parseMessage(message, formatOpts = {}, userList = null) {
|
|
23
|
+
const blocks = formatIrcMessage(message, formatOpts);
|
|
24
|
+
let formatedBlocks = blocks.reduce(
|
|
25
|
+
(acc, block, i) => acc.concat(processBlock(block, userList)),
|
|
26
|
+
[]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return formatedBlocks;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Receives a block, splits it into words and tries finding channels, urls, nicks, and emoji.
|
|
34
|
+
* @param {Object} block A block that came from MessageFormatter.formatIrcMessage()
|
|
35
|
+
* @param {Object} userList List of users to find within the message
|
|
36
|
+
* @returns An array of blocks, where each special content will be extracted into a separate block.
|
|
37
|
+
*/
|
|
38
|
+
function processBlock(block, userList) {
|
|
39
|
+
const wordsRegex = /\S+/g;
|
|
40
|
+
|
|
41
|
+
let wordMatch;
|
|
42
|
+
let word;
|
|
43
|
+
const specialMatches = [];
|
|
44
|
+
// Array containing the special matches. Each `specialMatch` is an object with:
|
|
45
|
+
// {
|
|
46
|
+
// index: <index of the match>
|
|
47
|
+
// match: <match, i.e. the text that will be extracted into a new block>
|
|
48
|
+
// block: <the block that will replace the match>
|
|
49
|
+
// }
|
|
50
|
+
|
|
51
|
+
// eslint-disable-next-line no-cond-assign
|
|
52
|
+
while ((wordMatch = wordsRegex.exec(block.content)) !== null) {
|
|
53
|
+
// `wordMatch` is an array with the match and the index of the match. We need that so
|
|
54
|
+
// we can re-construct the original message.
|
|
55
|
+
const matchInfo = wordMatch;
|
|
56
|
+
word = wordMatch[0];
|
|
57
|
+
|
|
58
|
+
const matches =
|
|
59
|
+
matchChannel(word) ||
|
|
60
|
+
matchUrl(word) ||
|
|
61
|
+
matchUser(word, userList) ||
|
|
62
|
+
EmojiProvider.matchEmoji(word);
|
|
63
|
+
|
|
64
|
+
if (!matches || !matches.length) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
matches.forEach((match) => {
|
|
69
|
+
specialMatches.push({
|
|
70
|
+
index: matchInfo.index + match.index,
|
|
71
|
+
match: match.match,
|
|
72
|
+
block: createNewBlock(
|
|
73
|
+
match.match,
|
|
74
|
+
block.styles,
|
|
75
|
+
match.type,
|
|
76
|
+
match.meta
|
|
77
|
+
),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// if there are no special matches, return the original block as is.
|
|
83
|
+
if (specialMatches.length === 0) {
|
|
84
|
+
return [block];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// split block with special matches.
|
|
88
|
+
return mergeMatches(block, specialMatches);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Finds a channel in the word match.
|
|
93
|
+
* @param {String} word Word to be searched for channels.
|
|
94
|
+
* @returns {object} Object with the matched channel, index within the word, and block.
|
|
95
|
+
*/
|
|
96
|
+
function matchChannel(word) {
|
|
97
|
+
const channelMatch = channelRegex.exec(word);
|
|
98
|
+
// matches the groups (spaces before)(prefix)(channel)(suffix punctuation)
|
|
99
|
+
|
|
100
|
+
if (channelMatch === null) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return [{
|
|
105
|
+
index: channelMatch[1].length + channelMatch[2].length,
|
|
106
|
+
match: channelMatch[3],
|
|
107
|
+
type: 'channel',
|
|
108
|
+
meta: {
|
|
109
|
+
channel: channelMatch[3],
|
|
110
|
+
},
|
|
111
|
+
}];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Finds an url in the word match.
|
|
116
|
+
* @param {String} word Word to be searched for urls.
|
|
117
|
+
* @returns {Object} Object with the index of the url match in the block content, the
|
|
118
|
+
* url match itself, and the new url text to be placed where the first url was.
|
|
119
|
+
*/
|
|
120
|
+
function matchUrl(word) {
|
|
121
|
+
// this check avoids running the urlRegex, which would return the same result
|
|
122
|
+
// but take much more time to process
|
|
123
|
+
if (!(word.includes('://') || word.startsWith('www'))) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const urlMatch = urlRegex.exec(word);
|
|
128
|
+
|
|
129
|
+
if (urlMatch === null) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let url = urlMatch[0];
|
|
134
|
+
|
|
135
|
+
// Don't allow javascript execution
|
|
136
|
+
if (url.match(/^javascript:/i)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Trim common punctuation from the end of a link. End of scentences etc.
|
|
141
|
+
let punctuation = '.,;:';
|
|
142
|
+
while (punctuation.indexOf(url[url.length - 1]) > -1) {
|
|
143
|
+
url = url.substr(0, url.length - 1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Links almost always contain an opening bracket if the last character is a closing
|
|
147
|
+
// bracket and should be part of the URL.
|
|
148
|
+
// If there isn't an opening bracket but the URL ends in a closing bracket, consider the
|
|
149
|
+
// closing bracket as punctuation outside of the URL.
|
|
150
|
+
if (url.indexOf('(') === -1 && url[url.length - 1] === ')') {
|
|
151
|
+
url = url.substr(0, url.length - 1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Add the http if no protocol was found
|
|
155
|
+
let urlText = url;
|
|
156
|
+
if (urlText.match(/^www\./i)) {
|
|
157
|
+
urlText = 'http://' + url;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return [{
|
|
161
|
+
index: urlMatch.index,
|
|
162
|
+
match: url,
|
|
163
|
+
matchText: urlText,
|
|
164
|
+
type: 'url',
|
|
165
|
+
meta: {
|
|
166
|
+
url: urlText,
|
|
167
|
+
},
|
|
168
|
+
}];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Finds an user in the word match.
|
|
173
|
+
* @param {String} word Word to be searched for users.
|
|
174
|
+
* @returns {Object} Object with the index of the user match in the block content, the
|
|
175
|
+
* user match itself, and the user colour.
|
|
176
|
+
*/
|
|
177
|
+
function matchUser(word, userList) {
|
|
178
|
+
if (!userList) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let user = null;
|
|
183
|
+
let punc = ',.!:;+)]?¿\\/<>@';
|
|
184
|
+
let hasProp = Object.prototype.hasOwnProperty;
|
|
185
|
+
let nickIdx = 0;
|
|
186
|
+
|
|
187
|
+
const trimWord = trim(word, punc);
|
|
188
|
+
let normWord = trimWord.toUpperCase();
|
|
189
|
+
|
|
190
|
+
if (hasProp.call(userList, normWord)) {
|
|
191
|
+
user = userList[normWord];
|
|
192
|
+
nickIdx = word.indexOf(trimWord);
|
|
193
|
+
} else {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return [{
|
|
198
|
+
index: nickIdx,
|
|
199
|
+
match: trimWord,
|
|
200
|
+
type: 'user',
|
|
201
|
+
meta: {
|
|
202
|
+
user: trimWord,
|
|
203
|
+
colour: user.colour,
|
|
204
|
+
},
|
|
205
|
+
}];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Merges the special matches into the block.
|
|
210
|
+
* @param {Object} block A block that came from MessageFormatter.formatIrcMessage()
|
|
211
|
+
* @param {Array} specialMatches Array of special matches. See definition above
|
|
212
|
+
* @returns An array of blocks, where each special content will be extracted into a separate block.
|
|
213
|
+
*/
|
|
214
|
+
function mergeMatches(block, specialMatches) {
|
|
215
|
+
const resultBlocks = [];
|
|
216
|
+
let lastProcessedIndex = 0;
|
|
217
|
+
|
|
218
|
+
// for each special content, creat a block with the text up to the match, and a block with the
|
|
219
|
+
// special content itself.
|
|
220
|
+
specialMatches.forEach((specialMatch, index) => {
|
|
221
|
+
const beforeMatchContent = block.content.substr(
|
|
222
|
+
lastProcessedIndex,
|
|
223
|
+
specialMatch.index - lastProcessedIndex
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
if (beforeMatchContent) {
|
|
227
|
+
resultBlocks.push({
|
|
228
|
+
content: beforeMatchContent,
|
|
229
|
+
styles: { ...block.styles },
|
|
230
|
+
containsContent: !!beforeMatchContent,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
resultBlocks.push(specialMatch.block);
|
|
235
|
+
|
|
236
|
+
lastProcessedIndex = specialMatch.index + specialMatch.match.length;
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// remaining content after the last special content.
|
|
240
|
+
if (lastProcessedIndex < block.content.length) {
|
|
241
|
+
resultBlocks.push({
|
|
242
|
+
content: block.content.substr(lastProcessedIndex),
|
|
243
|
+
styles: { ...block.styles },
|
|
244
|
+
containsContent: !!block.content.substr(lastProcessedIndex),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return resultBlocks;
|
|
249
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
|
|
5
|
+
let isEnabled = false;
|
|
6
|
+
|
|
7
|
+
export function requestPermission(state) {
|
|
8
|
+
// Do we support notifications?
|
|
9
|
+
if (!('Notification' in window)) {
|
|
10
|
+
isEnabled = false;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Permissions already been granted?
|
|
15
|
+
if (Notification.permission === 'granted') {
|
|
16
|
+
state.$emit('notification.enabled');
|
|
17
|
+
isEnabled = true;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (Notification.permission !== 'denied') {
|
|
22
|
+
Notification.requestPermission((permission) => {
|
|
23
|
+
if (permission === 'granted') {
|
|
24
|
+
state.$emit('notification.enabled');
|
|
25
|
+
isEnabled = true;
|
|
26
|
+
} else {
|
|
27
|
+
isEnabled = false;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function show(title, body, opts) {
|
|
34
|
+
if (!isEnabled) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let notify = new Notification(title, {
|
|
39
|
+
body: body,
|
|
40
|
+
icon: opts.icon,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (opts.ttl) {
|
|
44
|
+
setTimeout(notify.close.bind(notify), opts.ttl);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return notify;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const throttledShow = _.throttle(show, 2000);
|
|
51
|
+
|
|
52
|
+
export function listenForNewMessages(state) {
|
|
53
|
+
state.$on('notification.show', (message, _opts) => {
|
|
54
|
+
if (!isEnabled) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let opts = Object.assign({
|
|
59
|
+
title: 'Kiwi IRC',
|
|
60
|
+
message: message,
|
|
61
|
+
icon: '',
|
|
62
|
+
onclick: null,
|
|
63
|
+
ttl: 10000,
|
|
64
|
+
}, _opts);
|
|
65
|
+
|
|
66
|
+
if (!opts.message) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let notification = throttledShow(opts.title, opts.message, {
|
|
71
|
+
ttl: opts.ttl,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (notification && typeof opts.onclick === 'function') {
|
|
75
|
+
notification.onclick = opts.onclick;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
/** @module */
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Multiplexed channels over a websocket connection
|
|
7
|
+
* * Only allow 1 websocket per server
|
|
8
|
+
* * Multiple channels through a single websocket
|
|
9
|
+
* * A channel per IRC network connection
|
|
10
|
+
* Messages are prefixed with : and the channel name then a space. eg:
|
|
11
|
+
* :1 Here is the data
|
|
12
|
+
*
|
|
13
|
+
* Example protocol chatter:
|
|
14
|
+
* Client > START Client tells the server it's starting a session
|
|
15
|
+
* Server > SESSION 1234 Server sends the client the current session ID
|
|
16
|
+
* Client > :1 Client is creating a new channel, ID 1
|
|
17
|
+
* Server > :1 Server acknowledges the new channel, ID 1
|
|
18
|
+
* Client > :1 some data Client sends data over channel 1 to the server
|
|
19
|
+
* Server > :1 some data Server sends data over channel 1 to the client
|
|
20
|
+
* Client > :2 Client is creating a new channel, ID 2
|
|
21
|
+
* Server > :2 Server acknowledges the new channel, ID 2
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import SockJS from 'sockjs-client';
|
|
25
|
+
import EventEmitter from 'eventemitter3';
|
|
26
|
+
|
|
27
|
+
const serverConnections = Object.create(null);
|
|
28
|
+
const createdChannels = Object.create(null);
|
|
29
|
+
const controlChannel = '0';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @param {String} _addr Sockjs endpoint
|
|
34
|
+
* @param {String} sessionId Optional session ID to continue
|
|
35
|
+
* @param {String} _socketChannel The optional multiplexed channel ID. Autogenerated if not provided
|
|
36
|
+
*/
|
|
37
|
+
export function createChannelConstructor(_addr, sessionId, _socketChannel) {
|
|
38
|
+
let addr = _addr.toLowerCase();
|
|
39
|
+
|
|
40
|
+
if (!serverConnections[addr]) {
|
|
41
|
+
serverConnections[addr] = createNewConnection(addr, sessionId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If a channel ID hasn't been specified, create a new one
|
|
45
|
+
let socketChannel = _socketChannel;
|
|
46
|
+
if (!socketChannel) {
|
|
47
|
+
socketChannel = serverConnections[addr].nextChannelId++;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return createChannelOnConnection(
|
|
51
|
+
serverConnections[addr],
|
|
52
|
+
socketChannel
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Creates a new socket connection to a kiwi server.
|
|
58
|
+
* Channels will be created on this connection to send data back and forth.
|
|
59
|
+
*/
|
|
60
|
+
function createNewConnection(wsAddr, sessionId) {
|
|
61
|
+
let connection = new EventEmitter();
|
|
62
|
+
connection.sessionId = '';
|
|
63
|
+
|
|
64
|
+
serverConnections[wsAddr] = connection;
|
|
65
|
+
|
|
66
|
+
connection.nextChannelId = 1;
|
|
67
|
+
connection.connected = false;
|
|
68
|
+
|
|
69
|
+
connection.reconnect =
|
|
70
|
+
connection.connect = function connect() {
|
|
71
|
+
if (connection.ws) {
|
|
72
|
+
try {
|
|
73
|
+
connection.ws.close();
|
|
74
|
+
} catch (err) {
|
|
75
|
+
// Ignore any closing errors. Most likely due to not
|
|
76
|
+
// being connected yet.
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
connection.ws = null;
|
|
80
|
+
}
|
|
81
|
+
connection.ws = new SockJS(wsAddr);
|
|
82
|
+
connection.ws.onopen = () => {
|
|
83
|
+
let connectStr = sessionId ?
|
|
84
|
+
'CONTROL SESSION ' + sessionId :
|
|
85
|
+
'CONTROL START';
|
|
86
|
+
connection.ws.send(`:${controlChannel} ${connectStr}`);
|
|
87
|
+
connection.connected = true;
|
|
88
|
+
connection.emit('open');
|
|
89
|
+
};
|
|
90
|
+
connection.ws.onclose = (err) => {
|
|
91
|
+
connection.connected = false;
|
|
92
|
+
connection.ws = null;
|
|
93
|
+
connection.emit('close', err);
|
|
94
|
+
};
|
|
95
|
+
connection.ws.onmessage = (event) => {
|
|
96
|
+
connection.emit('message', event);
|
|
97
|
+
|
|
98
|
+
// If the message starts with ":channel " then extract that channel and emit
|
|
99
|
+
// an event for it.
|
|
100
|
+
if (event.data[0] === ':') {
|
|
101
|
+
let message = event.data;
|
|
102
|
+
let spacePos = message.indexOf(' ');
|
|
103
|
+
|
|
104
|
+
// If no space, ie. ":1", this is the server acknowledging this channel
|
|
105
|
+
// is now open and ready to be used.
|
|
106
|
+
if (spacePos === -1) {
|
|
107
|
+
connection.emit('open.' + message.substr(1));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let channelId = message.substr(1, spacePos - 1);
|
|
112
|
+
event.data = message.substr(spacePos + 1);
|
|
113
|
+
connection.emit('message.' + channelId, event);
|
|
114
|
+
} else {
|
|
115
|
+
// Core messages. Used for session handling and session syncing
|
|
116
|
+
let parts = event.data.split(' ');
|
|
117
|
+
|
|
118
|
+
if (parts[0] === 'SESSION') {
|
|
119
|
+
connection.sessionId = parts[1];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
connection.connect();
|
|
126
|
+
return connection;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
* Create a channel on a server connection.
|
|
131
|
+
* The ConnectionChannel implements an IrcFramework transport
|
|
132
|
+
*/
|
|
133
|
+
function createChannelOnConnection(connection, channelId) {
|
|
134
|
+
// Only allow 1 ConnectionChannel instance per channel
|
|
135
|
+
return function ConnectionChannelWrapper(options) {
|
|
136
|
+
if (!createdChannels[channelId]) {
|
|
137
|
+
createdChannels[channelId] = new ConnectionChannel(options);
|
|
138
|
+
} else if (connection.connected) {
|
|
139
|
+
createdChannels[channelId].initChannel();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return createdChannels[channelId];
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
function ConnectionChannel(options) {
|
|
146
|
+
let sendControlBuffer = [];
|
|
147
|
+
let encoding = 'utf8';
|
|
148
|
+
let channel = new EventEmitter();
|
|
149
|
+
channel.id = channelId;
|
|
150
|
+
channel.isOpen = false;
|
|
151
|
+
channel.state = 0; // TODO: Is this used anywhere?
|
|
152
|
+
// 0 = disconnected, 1 = connected
|
|
153
|
+
channel.remoteState = 0;
|
|
154
|
+
|
|
155
|
+
// When the websocket opens, open this channel on it
|
|
156
|
+
connection.on('open', () => {
|
|
157
|
+
connection.ws.send(':' + channelId);
|
|
158
|
+
});
|
|
159
|
+
// When we get confirmation of this channel being opened, send any control
|
|
160
|
+
// messages that were buffered
|
|
161
|
+
connection.on('open.' + channelId, () => {
|
|
162
|
+
channel.isOpen = true;
|
|
163
|
+
// channel.emit('open');
|
|
164
|
+
if (sendControlBuffer.length) {
|
|
165
|
+
sendControlBuffer.forEach((line) => {
|
|
166
|
+
channel.sendControl(line);
|
|
167
|
+
});
|
|
168
|
+
sendControlBuffer = [];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
channel.setEncoding(encoding);
|
|
172
|
+
|
|
173
|
+
// This channel is now open and can start sending data to the server
|
|
174
|
+
channel.remoteState = 1;
|
|
175
|
+
channel.emit('open');
|
|
176
|
+
});
|
|
177
|
+
connection.on('close', (err) => {
|
|
178
|
+
channel.state = 3;
|
|
179
|
+
channel.remoteState = 0;
|
|
180
|
+
channel.isOpen = false;
|
|
181
|
+
channel.emit('close', err);
|
|
182
|
+
});
|
|
183
|
+
connection.on('message.' + channelId, (event) => {
|
|
184
|
+
if (event.data.indexOf('control ') === 0) {
|
|
185
|
+
// When we get the signal that the connection to the IRC server
|
|
186
|
+
// has connected, start proxying all data
|
|
187
|
+
if (event.data.indexOf('control connected') === 0) {
|
|
188
|
+
channel.remoteState = 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (event.data.indexOf('control closed') === 0) {
|
|
192
|
+
let err = event.data.split(' ')[2];
|
|
193
|
+
channel.remoteState = 0;
|
|
194
|
+
channel.emit('close', err);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (channel.remoteState === 1) {
|
|
199
|
+
channel.emit('line', event.data);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Send a control message to the server (not relayed to an IRC network)
|
|
204
|
+
channel.sendControl = function writeTarget(data) {
|
|
205
|
+
if (channel.isOpen) {
|
|
206
|
+
connection.ws.send(':' + channelId + ' ' + data);
|
|
207
|
+
} else {
|
|
208
|
+
sendControlBuffer.push(data);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
channel.writeLine = function writeTarget(data, cb) {
|
|
213
|
+
// Buffer the data if the socket has not yet been sent
|
|
214
|
+
if (channel.remoteState >= 1) {
|
|
215
|
+
connection.ws.send(':' + channelId + ' ' + data);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Websocket.send() does not support callbacks
|
|
219
|
+
// call the callback in the next tick instead
|
|
220
|
+
if (cb) {
|
|
221
|
+
setTimeout(cb, 0);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Tell the server to connect to an IRC network
|
|
226
|
+
channel.connect = function connect() {
|
|
227
|
+
// Clear any buffered control messages so we have a clean slate
|
|
228
|
+
sendControlBuffer = [];
|
|
229
|
+
|
|
230
|
+
// If the websocket is not connected, try to reconnect it
|
|
231
|
+
if (!connection.ws) {
|
|
232
|
+
connection.reconnect();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let host = options.host;
|
|
236
|
+
let port = options.port;
|
|
237
|
+
let tls = options.tls || options.ssl;
|
|
238
|
+
channel.sendControl('HOST ' + host + ':' + (tls ? '+' : '') + port);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
channel.close = function close() {
|
|
242
|
+
if (channel.remoteState >= 1) {
|
|
243
|
+
connection.ws.send(':' + channelId);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// This is not supported but irc-framework transports need it, so just noop it
|
|
248
|
+
channel.setEncoding = function setEncoding(newEncoding) {
|
|
249
|
+
encoding = newEncoding;
|
|
250
|
+
if (connection.connected) {
|
|
251
|
+
connection.ws.send(':' + channelId + ' ENCODING ' + newEncoding);
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
channel.disposeSocket = function disposeSocket() {
|
|
257
|
+
// noop
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
channel.initChannel = function initChannel() {
|
|
261
|
+
connection.ws.send(':' + channelId);
|
|
262
|
+
};
|
|
263
|
+
// Let the server know of this new channel if we're already connected
|
|
264
|
+
if (connection.connected) {
|
|
265
|
+
channel.initChannel();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return channel;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
import EventEmitter from 'eventemitter3';
|
|
4
|
+
import getState from './state';
|
|
5
|
+
import * as ServerConnection from './ServerConnection';
|
|
6
|
+
|
|
7
|
+
export default class ServerSession {
|
|
8
|
+
constructor(sessionId) {
|
|
9
|
+
let channelConstruct = ServerConnection.createChannelConstructor(
|
|
10
|
+
getState().settings.kiwiServer,
|
|
11
|
+
sessionId || '',
|
|
12
|
+
'0'
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
this.bus = new EventEmitter();
|
|
16
|
+
this.channel = channelConstruct();
|
|
17
|
+
this.channel.on('line', (line) => {
|
|
18
|
+
if (line.indexOf('CONTROL ') === 0) {
|
|
19
|
+
let parts = line.split(' ');
|
|
20
|
+
|
|
21
|
+
// Remove the 'CONTROL' first part
|
|
22
|
+
parts.shift();
|
|
23
|
+
|
|
24
|
+
let command = parts.shift();
|
|
25
|
+
this.bus.emit(command, parts);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
auth(userId, password) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
this.bus.once('AUTH', (params) => {
|
|
33
|
+
let result = params[0];
|
|
34
|
+
|
|
35
|
+
if (result === 'OK') {
|
|
36
|
+
resolve(true);
|
|
37
|
+
} else {
|
|
38
|
+
reject(result);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.channel.sendControl(`CONTROL AUTH ${userId} ${password}`);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getNetworks() {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
let networks = Object.create(null);
|
|
49
|
+
|
|
50
|
+
let onListing = (params) => {
|
|
51
|
+
if (params[1] === 'END') {
|
|
52
|
+
this.bus.off('LISTING', onListing);
|
|
53
|
+
|
|
54
|
+
// Convert our networks object to an array first
|
|
55
|
+
let networkArr = [];
|
|
56
|
+
Object.keys(networks).forEach((channeId) => {
|
|
57
|
+
networkArr.push(networks[channeId]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
resolve(networkArr);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (params[0] === 'NETWORK') {
|
|
65
|
+
let props = params.slice(1);
|
|
66
|
+
let network = { buffers: [] };
|
|
67
|
+
|
|
68
|
+
props.forEach((prop) => {
|
|
69
|
+
let parts = prop.split('=');
|
|
70
|
+
if (parts[0] && parts[1]) {
|
|
71
|
+
network[parts[0].toLowerCase()] = parts[1];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (network.channel) {
|
|
76
|
+
networks[network.channel] = network;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (params[0] === 'BUFFER') {
|
|
81
|
+
let props = params.slice(1);
|
|
82
|
+
let buffer = {};
|
|
83
|
+
|
|
84
|
+
props.forEach((prop) => {
|
|
85
|
+
let parts = prop.split('=');
|
|
86
|
+
if (parts[0] && parts[1]) {
|
|
87
|
+
buffer[parts[0].toLowerCase()] = parts[1];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
let network = networks[buffer.channel];
|
|
92
|
+
if (network) {
|
|
93
|
+
network.buffers.push(buffer);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
this.bus.on('LISTING', onListing);
|
|
99
|
+
this.channel.sendControl('CONTROL LIST NETWORKS');
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|