summaryrefslogtreecommitdiff
path: root/src/client/app
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-10-07 11:06:17 +0900
committerGitHub <noreply@github.com>2018-10-07 11:06:17 +0900
commitd0570d7fe3a3bf3c6b0312dece74bacc04c3534a (patch)
tree698218279a38f9c78b0350e81b8ac77ae52e4a0d /src/client/app
parentFix お知らせが確認中...のままになる(Announcement Fetching...) (... (diff)
downloadmisskey-d0570d7fe3a3bf3c6b0312dece74bacc04c3534a.tar.gz
misskey-d0570d7fe3a3bf3c6b0312dece74bacc04c3534a.tar.bz2
misskey-d0570d7fe3a3bf3c6b0312dece74bacc04c3534a.zip
V10 (#2826)
* wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Update CHANGELOG.md * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Update CHANGELOG.md * Update CHANGELOG.md * wip * Update CHANGELOG.md * wip * wip * wip * wip
Diffstat (limited to 'src/client/app')
-rw-r--r--src/client/app/common/scripts/compose-notification.ts6
-rw-r--r--src/client/app/common/scripts/note-subscriber.ts105
-rw-r--r--src/client/app/common/scripts/stream.ts318
-rw-r--r--src/client/app/common/scripts/streaming/drive.ts34
-rw-r--r--src/client/app/common/scripts/streaming/games/reversi/reversi-game.ts13
-rw-r--r--src/client/app/common/scripts/streaming/games/reversi/reversi.ts31
-rw-r--r--src/client/app/common/scripts/streaming/global-timeline.ts34
-rw-r--r--src/client/app/common/scripts/streaming/hashtag.ts13
-rw-r--r--src/client/app/common/scripts/streaming/home.ts126
-rw-r--r--src/client/app/common/scripts/streaming/hybrid-timeline.ts34
-rw-r--r--src/client/app/common/scripts/streaming/local-timeline.ts34
-rw-r--r--src/client/app/common/scripts/streaming/messaging-index.ts34
-rw-r--r--src/client/app/common/scripts/streaming/messaging.ts20
-rw-r--r--src/client/app/common/scripts/streaming/notes-stats.ts30
-rw-r--r--src/client/app/common/scripts/streaming/server-stats.ts30
-rw-r--r--src/client/app/common/scripts/streaming/stream-manager.ts109
-rw-r--r--src/client/app/common/scripts/streaming/stream.ts137
-rw-r--r--src/client/app/common/scripts/streaming/user-list.ts17
-rw-r--r--src/client/app/common/views/components/games/reversi/reversi.gameroom.vue8
-rw-r--r--src/client/app/common/views/components/games/reversi/reversi.index.vue9
-rw-r--r--src/client/app/common/views/components/games/reversi/reversi.vue8
-rw-r--r--src/client/app/common/views/components/messaging-room.vue8
-rw-r--r--src/client/app/common/views/components/messaging.vue10
-rw-r--r--src/client/app/common/views/components/signin.vue2
-rw-r--r--src/client/app/common/views/components/signup.vue4
-rw-r--r--src/client/app/common/views/components/stream-indicator.vue2
-rw-r--r--src/client/app/common/views/components/welcome-timeline.vue9
-rw-r--r--src/client/app/common/views/widgets/photo-stream.vue11
-rw-r--r--src/client/app/common/views/widgets/posts-monitor.vue8
-rw-r--r--src/client/app/common/views/widgets/server.vue8
-rw-r--r--src/client/app/config.ts2
-rw-r--r--src/client/app/desktop/script.ts84
-rw-r--r--src/client/app/desktop/views/components/drive.vue13
-rw-r--r--src/client/app/desktop/views/components/follow-button.vue11
-rw-r--r--src/client/app/desktop/views/components/home.vue6
-rw-r--r--src/client/app/desktop/views/components/note-detail.vue3
-rw-r--r--src/client/app/desktop/views/components/notes.note.vue86
-rw-r--r--src/client/app/desktop/views/components/notifications.vue14
-rw-r--r--src/client/app/desktop/views/components/settings.signins.vue12
-rw-r--r--src/client/app/desktop/views/components/timeline.core.vue61
-rw-r--r--src/client/app/desktop/views/components/ui.header.nav.vue12
-rw-r--r--src/client/app/desktop/views/components/user-list-timeline.vue1
-rw-r--r--src/client/app/desktop/views/pages/admin/admin.dashboard.vue8
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.direct.vue10
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue3
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.list-tl.vue1
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.mentions.vue10
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.note.vue68
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.notifications.vue11
-rw-r--r--src/client/app/desktop/views/pages/deck/deck.tl.vue21
-rw-r--r--src/client/app/mios.ts135
-rw-r--r--src/client/app/mobile/views/components/drive.vue13
-rw-r--r--src/client/app/mobile/views/components/follow-button.vue10
-rw-r--r--src/client/app/mobile/views/components/note-detail.vue3
-rw-r--r--src/client/app/mobile/views/components/note.vue86
-rw-r--r--src/client/app/mobile/views/components/notifications.vue17
-rw-r--r--src/client/app/mobile/views/components/ui.header.vue17
-rw-r--r--src/client/app/mobile/views/components/ui.nav.vue10
-rw-r--r--src/client/app/mobile/views/components/ui.vue17
-rw-r--r--src/client/app/mobile/views/components/user-list-timeline.vue1
-rw-r--r--src/client/app/mobile/views/pages/home.timeline.vue60
-rw-r--r--src/client/app/tsconfig.json3
62 files changed, 642 insertions, 1379 deletions
diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts
index f42af94370..65087cc98e 100644
--- a/src/client/app/common/scripts/compose-notification.ts
+++ b/src/client/app/common/scripts/compose-notification.ts
@@ -13,21 +13,21 @@ type Notification = {
export default function(type, data): Notification {
switch (type) {
- case 'drive_file_created':
+ case 'driveFileCreated':
return {
title: '%i18n:common.notification.file-uploaded%',
body: data.name,
icon: data.url
};
- case 'unread_messaging_message':
+ case 'unreadMessagingMessage':
return {
title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] ,
body: data.text, // TODO: getMessagingMessageSummary(data),
icon: data.user.avatarUrl
};
- case 'reversi_invited':
+ case 'reversiInvited':
return {
title: '%i18n:common.notification.reversi-invited%',
body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1],
diff --git a/src/client/app/common/scripts/note-subscriber.ts b/src/client/app/common/scripts/note-subscriber.ts
new file mode 100644
index 0000000000..5fc82942d5
--- /dev/null
+++ b/src/client/app/common/scripts/note-subscriber.ts
@@ -0,0 +1,105 @@
+import Vue from 'vue';
+
+export default prop => ({
+ data() {
+ return {
+ connection: null
+ };
+ },
+
+ computed: {
+ $_ns_note_(): any {
+ return this[prop];
+ },
+
+ $_ns_isRenote(): boolean {
+ return (this.$_ns_note_.renote &&
+ this.$_ns_note_.text == null &&
+ this.$_ns_note_.fileIds.length == 0 &&
+ this.$_ns_note_.poll == null);
+ },
+
+ $_ns_target(): any {
+ return this._ns_isRenote ? this.$_ns_note_.renote : this.$_ns_note_;
+ },
+ },
+
+ created() {
+ if (this.$store.getters.isSignedIn) {
+ this.connection = (this as any).os.stream;
+ }
+ },
+
+ mounted() {
+ this.capture(true);
+
+ if (this.$store.getters.isSignedIn) {
+ this.connection.on('_connected_', this.onStreamConnected);
+ }
+ },
+
+ beforeDestroy() {
+ this.decapture(true);
+
+ if (this.$store.getters.isSignedIn) {
+ this.connection.off('_connected_', this.onStreamConnected);
+ }
+ },
+
+ methods: {
+ capture(withHandler = false) {
+ if (this.$store.getters.isSignedIn) {
+ const data = {
+ id: this.$_ns_target.id
+ } as any;
+
+ if (
+ (this.$_ns_target.visibleUserIds || []).includes(this.$store.state.i.id) ||
+ (this.$_ns_target.mentions || []).includes(this.$store.state.i.id)
+ ) {
+ data.read = true;
+ }
+
+ this.connection.send('sn', data);
+ if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
+ }
+ },
+
+ decapture(withHandler = false) {
+ if (this.$store.getters.isSignedIn) {
+ this.connection.send('un', {
+ id: this.$_ns_target.id
+ });
+ if (withHandler) this.connection.off('noteUpdated', this.onStreamNoteUpdated);
+ }
+ },
+
+ onStreamConnected() {
+ this.capture();
+ },
+
+ onStreamNoteUpdated(data) {
+ const { type, id, body } = data;
+
+ if (id !== this.$_ns_target.id) return;
+
+ switch (type) {
+ case 'reacted': {
+ const reaction = body.reaction;
+ if (this.$_ns_target.reactionCounts == null) Vue.set(this.$_ns_target, 'reactionCounts', {});
+ this.$_ns_target.reactionCounts[reaction] = (this.$_ns_target.reactionCounts[reaction] || 0) + 1;
+ break;
+ }
+
+ case 'pollVoted': {
+ if (body.userId == this.$store.state.i.id) return;
+ const choice = body.choice;
+ this.$_ns_target.poll.choices.find(c => c.id === choice).votes++;
+ break;
+ }
+ }
+
+ this.$emit(`update:${prop}`, this.$_ns_note_);
+ },
+ }
+});
diff --git a/src/client/app/common/scripts/stream.ts b/src/client/app/common/scripts/stream.ts
new file mode 100644
index 0000000000..7dc130937b
--- /dev/null
+++ b/src/client/app/common/scripts/stream.ts
@@ -0,0 +1,318 @@
+import autobind from 'autobind-decorator';
+import { EventEmitter } from 'eventemitter3';
+import * as ReconnectingWebsocket from 'reconnecting-websocket';
+import { wsUrl } from '../../config';
+import MiOS from '../../mios';
+
+/**
+ * Misskey stream connection
+ */
+export default class Stream extends EventEmitter {
+ private stream: ReconnectingWebsocket;
+ private state: string;
+ private buffer: any[];
+ private sharedConnections: SharedConnection[] = [];
+ private nonSharedConnections: NonSharedConnection[] = [];
+
+ constructor(os: MiOS) {
+ super();
+
+ this.state = 'initializing';
+ this.buffer = [];
+
+ const user = os.store.state.i;
+
+ this.stream = new ReconnectingWebsocket(wsUrl + (user ? `?i=${user.token}` : ''));
+ this.stream.addEventListener('open', this.onOpen);
+ this.stream.addEventListener('close', this.onClose);
+ this.stream.addEventListener('message', this.onMessage);
+
+ if (user) {
+ const main = this.useSharedConnection('main');
+
+ // 自分の情報が更新されたとき
+ main.on('meUpdated', i => {
+ os.store.dispatch('mergeMe', i);
+ });
+
+ main.on('readAllNotifications', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadNotification: false
+ });
+ });
+
+ main.on('unreadNotification', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadNotification: true
+ });
+ });
+
+ main.on('readAllMessagingMessages', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadMessagingMessage: false
+ });
+ });
+
+ main.on('unreadMessagingMessage', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadMessagingMessage: true
+ });
+ });
+
+ main.on('unreadMention', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadMentions: true
+ });
+ });
+
+ main.on('readAllUnreadMentions', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadMentions: false
+ });
+ });
+
+ main.on('unreadSpecifiedNote', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadSpecifiedNotes: true
+ });
+ });
+
+ main.on('readAllUnreadSpecifiedNotes', () => {
+ os.store.dispatch('mergeMe', {
+ hasUnreadSpecifiedNotes: false
+ });
+ });
+
+ main.on('clientSettingUpdated', x => {
+ os.store.commit('settings/set', {
+ key: x.key,
+ value: x.value
+ });
+ });
+
+ main.on('homeUpdated', x => {
+ os.store.commit('settings/setHome', x);
+ });
+
+ main.on('mobileHomeUpdated', x => {
+ os.store.commit('settings/setMobileHome', x);
+ });
+
+ main.on('widgetUpdated', x => {
+ os.store.commit('settings/setWidget', {
+ id: x.id,
+ data: x.data
+ });
+ });
+
+ // トークンが再生成されたとき
+ // このままではMisskeyが利用できないので強制的にサインアウトさせる
+ main.on('myTokenRegenerated', () => {
+ alert('%i18n:common.my-token-regenerated%');
+ os.signout();
+ });
+ }
+ }
+
+ public useSharedConnection = (channel: string): SharedConnection => {
+ const existConnection = this.sharedConnections.find(c => c.channel === channel);
+
+ if (existConnection) {
+ existConnection.use();
+ return existConnection;
+ } else {
+ const connection = new SharedConnection(this, channel);
+ connection.use();
+ this.sharedConnections.push(connection);
+ return connection;
+ }
+ }
+
+ @autobind
+ public removeSharedConnection(connection: SharedConnection) {
+ this.sharedConnections = this.sharedConnections.filter(c => c.id !== connection.id);
+ }
+
+ public connectToChannel = (channel: string, params?: any): NonSharedConnection => {
+ const connection = new NonSharedConnection(this, channel, params);
+ this.nonSharedConnections.push(connection);
+ return connection;
+ }
+
+ @autobind
+ public disconnectToChannel(connection: NonSharedConnection) {
+ this.nonSharedConnections = this.nonSharedConnections.filter(c => c.id !== connection.id);
+ }
+
+ /**
+ * Callback of when open connection
+ */
+ @autobind
+ private onOpen() {
+ const isReconnect = this.state == 'reconnecting';
+
+ this.state = 'connected';
+ this.emit('_connected_');
+
+ // バッファーを処理
+ const _buffer = [].concat(this.buffer); // Shallow copy
+ this.buffer = []; // Clear buffer
+ _buffer.forEach(data => {
+ this.send(data); // Resend each buffered messages
+ });
+
+ // チャンネル再接続
+ if (isReconnect) {
+ this.sharedConnections.forEach(c => {
+ c.connect();
+ });
+ this.nonSharedConnections.forEach(c => {
+ c.connect();
+ });
+ }
+ }
+
+ /**
+ * Callback of when close connection
+ */
+ @autobind
+ private onClose() {
+ this.state = 'reconnecting';
+ this.emit('_disconnected_');
+ }
+
+ /**
+ * Callback of when received a message from connection
+ */
+ @autobind
+ private onMessage(message) {
+ const { type, body } = JSON.parse(message.data);
+
+ if (type == 'channel') {
+ const id = body.id;
+ const connection = this.sharedConnections.find(c => c.id === id) || this.nonSharedConnections.find(c => c.id === id);
+ connection.emit(body.type, body.body);
+ } else {
+ this.emit(type, body);
+ }
+ }
+
+ /**
+ * Send a message to connection
+ */
+ @autobind
+ public send(typeOrPayload, payload?) {
+ const data = payload === undefined ? typeOrPayload : {
+ type: typeOrPayload,
+ body: payload
+ };
+
+ // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
+ if (this.state != 'connected') {
+ this.buffer.push(data);
+ return;
+ }
+
+ this.stream.send(JSON.stringify(data));
+ }
+
+ /**
+ * Close this connection
+ */
+ @autobind
+ public close() {
+ this.stream.removeEventListener('open', this.onOpen);
+ this.stream.removeEventListener('message', this.onMessage);
+ }
+}
+
+abstract class Connection extends EventEmitter {
+ public channel: string;
+ public id: string;
+ protected params: any;
+ protected stream: Stream;
+
+ constructor(stream: Stream, channel: string, params?: any) {
+ super();
+
+ this.stream = stream;
+ this.channel = channel;
+ this.params = params;
+ this.id = Math.random().toString();
+ this.connect();
+ }
+
+ @autobind
+ public connect() {
+ this.stream.send('connect', {
+ channel: this.channel,
+ id: this.id,
+ params: this.params
+ });
+ }
+
+ @autobind
+ public send(typeOrPayload, payload?) {
+ const data = payload === undefined ? typeOrPayload : {
+ type: typeOrPayload,
+ body: payload
+ };
+
+ this.stream.send('channel', {
+ id: this.id,
+ body: data
+ });
+ }
+
+ public abstract dispose: () => void;
+}
+
+class SharedConnection extends Connection {
+ private users = 0;
+ private disposeTimerId: any;
+
+ constructor(stream: Stream, channel: string) {
+ super(stream, channel);
+ }
+
+ @autobind
+ public use() {
+ this.users++;
+
+ // タイマー解除
+ if (this.disposeTimerId) {
+ clearTimeout(this.disposeTimerId);
+ this.disposeTimerId = null;
+ }
+ }
+
+ @autobind
+ public dispose() {
+ this.users--;
+
+ // そのコネクションの利用者が誰もいなくなったら
+ if (this.users === 0) {
+ // また直ぐに再利用される可能性があるので、一定時間待ち、
+ // 新たな利用者が現れなければコネクションを切断する
+ this.disposeTimerId = setTimeout(() => {
+ this.disposeTimerId = null;
+ this.removeAllListeners();
+ this.stream.send('disconnect', { id: this.id });
+ this.stream.removeSharedConnection(this);
+ }, 3000);
+ }
+ }
+}
+
+class NonSharedConnection extends Connection {
+ constructor(stream: Stream, channel: string, params?: any) {
+ super(stream, channel, params);
+ }
+
+ @autobind
+ public dispose() {
+ this.removeAllListeners();
+ this.stream.send('disconnect', { id: this.id });
+ this.stream.disconnectToChannel(this);
+ }
+}
diff --git a/src/client/app/common/scripts/streaming/drive.ts b/src/client/app/common/scripts/streaming/drive.ts
deleted file mode 100644
index 50fff05737..0000000000
--- a/src/client/app/common/scripts/streaming/drive.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Drive stream connection
- */
-export class DriveStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'drive', {
- i: me.token
- });
- }
-}
-
-export class DriveStreamManager extends StreamManager<DriveStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new DriveStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/games/reversi/reversi-game.ts b/src/client/app/common/scripts/streaming/games/reversi/reversi-game.ts
deleted file mode 100644
index adfa75ff3b..0000000000
--- a/src/client/app/common/scripts/streaming/games/reversi/reversi-game.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import Stream from '../../stream';
-import MiOS from '../../../../../mios';
-
-export class ReversiGameStream extends Stream {
- constructor(os: MiOS, me, game) {
- super(os, 'games/reversi-game', me ? {
- i: me.token,
- game: game.id
- } : {
- game: game.id
- });
- }
-}
diff --git a/src/client/app/common/scripts/streaming/games/reversi/reversi.ts b/src/client/app/common/scripts/streaming/games/reversi/reversi.ts
deleted file mode 100644
index 1f4fd8c63e..0000000000
--- a/src/client/app/common/scripts/streaming/games/reversi/reversi.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import StreamManager from '../../stream-manager';
-import Stream from '../../stream';
-import MiOS from '../../../../../mios';
-
-export class ReversiStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'games/reversi', {
- i: me.token
- });
- }
-}
-
-export class ReversiStreamManager extends StreamManager<ReversiStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new ReversiStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/global-timeline.ts b/src/client/app/common/scripts/streaming/global-timeline.ts
deleted file mode 100644
index a639f1595c..0000000000
--- a/src/client/app/common/scripts/streaming/global-timeline.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Global timeline stream connection
- */
-export class GlobalTimelineStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'global-timeline', {
- i: me.token
- });
- }
-}
-
-export class GlobalTimelineStreamManager extends StreamManager<GlobalTimelineStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new GlobalTimelineStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/hashtag.ts b/src/client/app/common/scripts/streaming/hashtag.ts
deleted file mode 100644
index 276b8f8d3d..0000000000
--- a/src/client/app/common/scripts/streaming/hashtag.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import Stream from './stream';
-import MiOS from '../../../mios';
-
-export class HashtagStream extends Stream {
- constructor(os: MiOS, me, q) {
- super(os, 'hashtag', me ? {
- i: me.token,
- q: JSON.stringify(q)
- } : {
- q: JSON.stringify(q)
- });
- }
-}
diff --git a/src/client/app/common/scripts/streaming/home.ts b/src/client/app/common/scripts/streaming/home.ts
deleted file mode 100644
index 26729507fb..0000000000
--- a/src/client/app/common/scripts/streaming/home.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Home stream connection
- */
-export class HomeStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, '', {
- i: me.token
- });
-
- // 最終利用日時を更新するため定期的にaliveメッセージを送信
- setInterval(() => {
- this.send({ type: 'alive' });
- me.lastUsedAt = new Date();
- }, 1000 * 60);
-
- // 自分の情報が更新されたとき
- this.on('meUpdated', i => {
- if (os.debug) {
- console.log('I updated:', i);
- }
-
- os.store.dispatch('mergeMe', i);
- });
-
- this.on('read_all_notifications', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadNotification: false
- });
- });
-
- this.on('unread_notification', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadNotification: true
- });
- });
-
- this.on('read_all_messaging_messages', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadMessagingMessage: false
- });
- });
-
- this.on('unread_messaging_message', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadMessagingMessage: true
- });
- });
-
- this.on('unreadMention', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadMentions: true
- });
- });
-
- this.on('readAllUnreadMentions', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadMentions: false
- });
- });
-
- this.on('unreadSpecifiedNote', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadSpecifiedNotes: true
- });
- });
-
- this.on('readAllUnreadSpecifiedNotes', () => {
- os.store.dispatch('mergeMe', {
- hasUnreadSpecifiedNotes: false
- });
- });
-
- this.on('clientSettingUpdated', x => {
- os.store.commit('settings/set', {
- key: x.key,
- value: x.value
- });
- });
-
- this.on('home_updated', x => {
- os.store.commit('settings/setHome', x);
- });
-
- this.on('mobile_home_updated', x => {
- os.store.commit('settings/setMobileHome', x);
- });
-
- this.on('widgetUpdated', x => {
- os.store.commit('settings/setWidget', {
- id: x.id,
- data: x.data
- });
- });
-
- // トークンが再生成されたとき
- // このままではMisskeyが利用できないので強制的にサインアウトさせる
- this.on('my_token_regenerated', () => {
- alert('%i18n:common.my-token-regenerated%');
- os.signout();
- });
- }
-}
-
-export class HomeStreamManager extends StreamManager<HomeStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new HomeStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/hybrid-timeline.ts b/src/client/app/common/scripts/streaming/hybrid-timeline.ts
deleted file mode 100644
index cd290797c4..0000000000
--- a/src/client/app/common/scripts/streaming/hybrid-timeline.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Hybrid timeline stream connection
- */
-export class HybridTimelineStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'hybrid-timeline', {
- i: me.token
- });
- }
-}
-
-export class HybridTimelineStreamManager extends StreamManager<HybridTimelineStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new HybridTimelineStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/local-timeline.ts b/src/client/app/common/scripts/streaming/local-timeline.ts
deleted file mode 100644
index 41c36aa14c..0000000000
--- a/src/client/app/common/scripts/streaming/local-timeline.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Local timeline stream connection
- */
-export class LocalTimelineStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'local-timeline', me ? {
- i: me.token
- } : {});
- }
-}
-
-export class LocalTimelineStreamManager extends StreamManager<LocalTimelineStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new LocalTimelineStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/messaging-index.ts b/src/client/app/common/scripts/streaming/messaging-index.ts
deleted file mode 100644
index addcccb952..0000000000
--- a/src/client/app/common/scripts/streaming/messaging-index.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Messaging index stream connection
- */
-export class MessagingIndexStream extends Stream {
- constructor(os: MiOS, me) {
- super(os, 'messaging-index', {
- i: me.token
- });
- }
-}
-
-export class MessagingIndexStreamManager extends StreamManager<MessagingIndexStream> {
- private me;
- private os: MiOS;
-
- constructor(os: MiOS, me) {
- super();
-
- this.me = me;
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new MessagingIndexStream(this.os, this.me);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/messaging.ts b/src/client/app/common/scripts/streaming/messaging.ts
deleted file mode 100644
index a59377d867..0000000000
--- a/src/client/app/common/scripts/streaming/messaging.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import Stream from './stream';
-import MiOS from '../../../mios';
-
-/**
- * Messaging stream connection
- */
-export class MessagingStream extends Stream {
- constructor(os: MiOS, me, otherparty) {
- super(os, 'messaging', {
- i: me.token,
- otherparty
- });
-
- (this as any).on('_connected_', () => {
- this.send({
- i: me.token
- });
- });
- }
-}
diff --git a/src/client/app/common/scripts/streaming/notes-stats.ts b/src/client/app/common/scripts/streaming/notes-stats.ts
deleted file mode 100644
index 9e3e78a709..0000000000
--- a/src/client/app/common/scripts/streaming/notes-stats.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Notes stats stream connection
- */
-export class NotesStatsStream extends Stream {
- constructor(os: MiOS) {
- super(os, 'notes-stats');
- }
-}
-
-export class NotesStatsStreamManager extends StreamManager<NotesStatsStream> {
- private os: MiOS;
-
- constructor(os: MiOS) {
- super();
-
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new NotesStatsStream(this.os);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/server-stats.ts b/src/client/app/common/scripts/streaming/server-stats.ts
deleted file mode 100644
index 9983dfcaf0..0000000000
--- a/src/client/app/common/scripts/streaming/server-stats.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../../mios';
-
-/**
- * Server stats stream connection
- */
-export class ServerStatsStream extends Stream {
- constructor(os: MiOS) {
- super(os, 'server-stats');
- }
-}
-
-export class ServerStatsStreamManager extends StreamManager<ServerStatsStream> {
- private os: MiOS;
-
- constructor(os: MiOS) {
- super();
-
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new ServerStatsStream(this.os);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/common/scripts/streaming/stream-manager.ts b/src/client/app/common/scripts/streaming/stream-manager.ts
deleted file mode 100644
index 8dd06f67d3..0000000000
--- a/src/client/app/common/scripts/streaming/stream-manager.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { EventEmitter } from 'eventemitter3';
-import * as uuid from 'uuid';
-import Connection from './stream';
-import { erase } from '../../../../../prelude/array';
-
-/**
- * ストリーム接続を管理するクラス
- * 複数の場所から同じストリームを利用する際、接続をまとめたりする
- */
-export default abstract class StreamManager<T extends Connection> extends EventEmitter {
- private _connection: T = null;
-
- private disposeTimerId: any;
-
- /**
- * コネクションを必要としているユーザー
- */
- private users = [];
-
- protected set connection(connection: T) {
- this._connection = connection;
-
- if (this._connection == null) {
- this.emit('disconnected');
- } else {
- this.emit('connected', this._connection);
-
- this._connection.on('_connected_', () => {
- this.emit('_connected_');
- });
-
- this._connection.on('_disconnected_', () => {
- this.emit('_disconnected_');
- });
-
- this._connection.user = 'Managed';
- }
- }
-
- protected get connection() {
- return this._connection;
- }
-
- /**
- * コネクションを持っているか否か
- */
- public get hasConnection() {
- return this._connection != null;
- }
-
- public get state(): string {
- if (!this.hasConnection) return 'no-connection';
- return this._connection.state;
- }
-
- /**
- * コネクションを要求します
- */
- public abstract getConnection(): T;
-
- /**
- * 現在接続しているコネクションを取得します
- */
- public borrow() {
- return this._connection;
- }
-
- /**
- * コネクションを要求するためのユーザーIDを発行します
- */
- public use() {
- // タイマー解除
- if (this.disposeTimerId) {
- clearTimeout(this.disposeTimerId);
- this.disposeTimerId = null;
- }
-
- // ユーザーID生成
- const userId = uuid();
-
- this.users.push(userId);
-
- this._connection.user = `Managed (${ this.users.length })`;
-
- return userId;
- }
-
- /**
- * コネクションを利用し終わってもう必要ないことを通知します
- * @param userId use で発行したユーザーID
- */
- public dispose(userId) {
- this.users = erase(userId, this.users);
-
- this._connection.user = `Managed (${ this.users.length })`;
-
- // 誰もコネクションの利用者がいなくなったら
- if (this.users.length == 0) {
- // また直ぐに再利用される可能性があるので、一定時間待ち、
- // 新たな利用者が現れなければコネクションを切断する
- this.disposeTimerId = setTimeout(() => {
- this.disposeTimerId = null;
-
- this.connection.close();
- this.connection = null;
- }, 3000);
- }
- }
-}
diff --git a/src/client/app/common/scripts/streaming/stream.ts b/src/client/app/common/scripts/streaming/stream.ts
deleted file mode 100644
index 4ab78f1190..0000000000
--- a/src/client/app/common/scripts/streaming/stream.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import { EventEmitter } from 'eventemitter3';
-import * as uuid from 'uuid';
-import * as ReconnectingWebsocket from 'reconnecting-websocket';
-import { wsUrl } from '../../../config';
-import MiOS from '../../../mios';
-
-/**
- * Misskey stream connection
- */
-export default class Connection extends EventEmitter {
- public state: string;
- private buffer: any[];
- public socket: ReconnectingWebsocket;
- public name: string;
- public connectedAt: Date;
- public user: string = null;
- public in: number = 0;
- public out: number = 0;
- public inout: Array<{
- type: 'in' | 'out',
- at: Date,
- data: string
- }> = [];
- public id: string;
- public isSuspended = false;
- private os: MiOS;
-
- constructor(os: MiOS, endpoint, params?) {
- super();
-
- //#region BIND
- this.onOpen = this.onOpen.bind(this);
- this.onClose = this.onClose.bind(this);
- this.onMessage = this.onMessage.bind(this);
- this.send = this.send.bind(this);
- this.close = this.close.bind(this);
- //#endregion
-
- this.id = uuid();
- this.os = os;
- this.name = endpoint;
- this.state = 'initializing';
- this.buffer = [];
-
- const query = params
- ? Object.keys(params)
- .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
- .join('&')
- : null;
-
- this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? `?${query}` : ''}`);
- this.socket.addEventListener('open', this.onOpen);
- this.socket.addEventListener('close', this.onClose);
- this.socket.addEventListener('message', this.onMessage);
-
- // Register this connection for debugging
- this.os.registerStreamConnection(this);
- }
-
- /**
- * Callback of when open connection
- */
- private onOpen() {
- this.state = 'connected';
- this.emit('_connected_');
-
- this.connectedAt = new Date();
-
- // バッファーを処理
- const _buffer = [].concat(this.buffer); // Shallow copy
- this.buffer = []; // Clear buffer
- _buffer.forEach(data => {
- this.send(data); // Resend each buffered messages
-
- if (this.os.debug) {
- this.out++;
- this.inout.push({ type: 'out', at: new Date(), data });
- }
- });
- }
-
- /**
- * Callback of when close connection
- */
- private onClose() {
- this.state = 'reconnecting';
- this.emit('_disconnected_');
- }
-
- /**
- * Callback of when received a message from connection
- */
- private onMessage(message) {
- if (this.isSuspended) return;
-
- if (this.os.debug) {
- this.in++;
- this.inout.push({ type: 'in', at: new Date(), data: message.data });
- }
-
- try {
- const msg = JSON.parse(message.data);
- if (msg.type) this.emit(msg.type, msg.body);
- } catch (e) {
- // noop
- }
- }
-
- /**
- * Send a message to connection
- */
- public send(data) {
- if (this.isSuspended) return;
-
- // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
- if (this.state != 'connected') {
- this.buffer.push(data);
- return;
- }
-
- if (this.os.debug) {
- this.out++;
- this.inout.push({ type: 'out', at: new Date(), data });
- }
-
- this.socket.send(JSON.stringify(data));
- }
-
- /**
- * Close this connection
- */
- public close() {
- this.os.unregisterStreamConnection(this);
- this.socket.removeEventListener('open', this.onOpen);
- this.socket.removeEventListener('message', this.onMessage);
- }
-}
diff --git a/src/client/app/common/scripts/streaming/user-list.ts b/src/client/app/common/scripts/streaming/user-list.ts
deleted file mode 100644
index 30a52b98dd..0000000000
--- a/src/client/app/common/scripts/streaming/user-list.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import Stream from './stream';
-import MiOS from '../../mios';
-
-export class UserListStream extends Stream {
- constructor(os: MiOS, me, listId) {
- super(os, 'user-list', {
- i: me.token,
- listId
- });
-
- (this as any).on('_connected_', () => {
- this.send({
- i: me.token
- });
- });
- }
-}
diff --git a/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue b/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
index 1539c88de0..0a18e0b19a 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
@@ -9,7 +9,6 @@
import Vue from 'vue';
import XGame from './reversi.game.vue';
import XRoom from './reversi.room.vue';
-import { ReversiGameStream } from '../../../../scripts/streaming/games/reversi/reversi-game';
export default Vue.extend({
components: {
@@ -34,12 +33,13 @@ export default Vue.extend({
},
created() {
this.g = this.game;
- this.connection = new ReversiGameStream((this as any).os, this.$store.state.i, this.game);
+ this.connection = (this as any).os.stream.connectToChannel('gamesReversiGame', {
+ gameId: this.game.id
+ });
this.connection.on('started', this.onStarted);
},
beforeDestroy() {
- this.connection.off('started', this.onStarted);
- this.connection.close();
+ this.connection.dispose();
},
methods: {
onStarted(game) {
diff --git a/src/client/app/common/views/components/games/reversi/reversi.index.vue b/src/client/app/common/views/components/games/reversi/reversi.index.vue
index 3725aa6cb4..a040162802 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.index.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.index.vue
@@ -59,15 +59,13 @@ export default Vue.extend({
myGames: [],
matching: null,
invitations: [],
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.streams.reversiStream.getConnection();
- this.connectionId = (this as any).os.streams.reversiStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('gamesReversi');
this.connection.on('invited', this.onInvited);
@@ -90,8 +88,7 @@ export default Vue.extend({
beforeDestroy() {
if (this.connection) {
- this.connection.off('invited', this.onInvited);
- (this as any).os.streams.reversiStream.dispose(this.connectionId);
+ this.connection.dispose();
}
},
diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue
index 6eb9511ce9..f2156bc41b 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.vue
@@ -47,7 +47,6 @@ export default Vue.extend({
game: null,
matching: null,
connection: null,
- connectionId: null,
pingClock: null
};
},
@@ -66,8 +65,7 @@ export default Vue.extend({
this.fetch();
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.streams.reversiStream.getConnection();
- this.connectionId = (this as any).os.streams.reversiStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('gamesReversi');
this.connection.on('matched', this.onMatched);
@@ -84,9 +82,7 @@ export default Vue.extend({
beforeDestroy() {
if (this.connection) {
- this.connection.off('matched', this.onMatched);
- (this as any).os.streams.reversiStream.dispose(this.connectionId);
-
+ this.connection.dispose();
clearInterval(this.pingClock);
}
},
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index 98661bc39d..c2cd79e116 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -30,7 +30,6 @@
<script lang="ts">
import Vue from 'vue';
-import { MessagingStream } from '../../scripts/streaming/messaging';
import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue';
import { url } from '../../../config';
@@ -72,7 +71,7 @@ export default Vue.extend({
},
mounted() {
- this.connection = new MessagingStream((this as any).os, this.$store.state.i, this.user.id);
+ this.connection =((this as any).os.stream.connectToChannel('messaging', { otherparty: this.user.id });
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
@@ -92,9 +91,7 @@ export default Vue.extend({
},
beforeDestroy() {
- this.connection.off('message', this.onMessage);
- this.connection.off('read', this.onRead);
- this.connection.close();
+ this.connection.dispose();
if (this.isNaked) {
window.removeEventListener('scroll', this.onScroll);
@@ -166,6 +163,7 @@ export default Vue.extend({
},
onMessage(message) {
+ console.log(message);
// サウンドを再生する
if (this.$store.state.device.enableSounds) {
const sound = new Audio(`${url}/assets/message.mp3`);
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index 91453e16ec..f5b5e232f6 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -71,13 +71,11 @@ export default Vue.extend({
messages: [],
q: null,
result: [],
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.streams.messagingIndexStream.getConnection();
- this.connectionId = (this as any).os.streams.messagingIndexStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('messagingIndex');
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
@@ -88,9 +86,7 @@ export default Vue.extend({
});
},
beforeDestroy() {
- this.connection.off('message', this.onMessage);
- this.connection.off('read', this.onRead);
- (this as any).os.streams.messagingIndexStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
getAcct,
diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index 7025ecea33..9224f82cb9 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -56,7 +56,7 @@ export default Vue.extend({
username: this.username,
password: this.password,
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
- }).then(() => {
+ }, true).then(() => {
location.reload();
}).catch(() => {
alert('%i18n:@login-failed%');
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index b817ca729d..8e06b13491 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -131,11 +131,11 @@ export default Vue.extend({
password: this.password,
invitationCode: this.invitationCode,
'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null
- }).then(() => {
+ }, true).then(() => {
(this as any).api('signin', {
username: this.username,
password: this.password
- }).then(() => {
+ }, true).then(() => {
location.href = '/';
});
}).catch(() => {
diff --git a/src/client/app/common/views/components/stream-indicator.vue b/src/client/app/common/views/components/stream-indicator.vue
index d573db32e6..0f25b37cc9 100644
--- a/src/client/app/common/views/components/stream-indicator.vue
+++ b/src/client/app/common/views/components/stream-indicator.vue
@@ -22,7 +22,7 @@ import * as anime from 'animejs';
export default Vue.extend({
computed: {
stream() {
- return (this as any).os.stream;
+ return (this as any).os.stream.useSharedConnection('main');
}
},
created() {
diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index 6934fb4856..4a66db57b8 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -38,23 +38,20 @@ export default Vue.extend({
return {
fetching: true,
notes: [],
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
this.fetch();
- this.connection = (this as any).os.streams.localTimelineStream.getConnection();
- this.connectionId = (this as any).os.streams.localTimelineStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
this.connection.on('note', this.onNote);
},
beforeDestroy() {
- this.connection.off('note', this.onNote);
- (this as any).os.streams.localTimelineStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/common/views/widgets/photo-stream.vue b/src/client/app/common/views/widgets/photo-stream.vue
index 3e24c58e8e..047b01df4f 100644
--- a/src/client/app/common/views/widgets/photo-stream.vue
+++ b/src/client/app/common/views/widgets/photo-stream.vue
@@ -24,15 +24,13 @@ export default define({
return {
images: [],
fetching: true,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
- this.connection.on('drive_file_created', this.onDriveFileCreated);
+ this.connection.on('driveFileCreated', this.onDriveFileCreated);
(this as any).api('drive/stream', {
type: 'image/*',
@@ -43,8 +41,7 @@ export default define({
});
},
beforeDestroy() {
- this.connection.off('drive_file_created', this.onDriveFileCreated);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
onDriveFileCreated(file) {
diff --git a/src/client/app/common/views/widgets/posts-monitor.vue b/src/client/app/common/views/widgets/posts-monitor.vue
index 18df1241a9..1c70e6dbc4 100644
--- a/src/client/app/common/views/widgets/posts-monitor.vue
+++ b/src/client/app/common/views/widgets/posts-monitor.vue
@@ -82,7 +82,6 @@ export default define({
data() {
return {
connection: null,
- connectionId: null,
viewBoxY: 30,
stats: [],
fediGradientId: uuid(),
@@ -110,8 +109,7 @@ export default define({
}
},
mounted() {
- this.connection = (this as any).os.streams.notesStatsStream.getConnection();
- this.connectionId = (this as any).os.streams.notesStatsStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('notesStats');
this.connection.on('stats', this.onStats);
this.connection.on('statsLog', this.onStatsLog);
@@ -121,9 +119,7 @@ export default define({
});
},
beforeDestroy() {
- this.connection.off('stats', this.onStats);
- this.connection.off('statsLog', this.onStatsLog);
- (this as any).os.streams.notesStatsStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
toggle() {
diff --git a/src/client/app/common/views/widgets/server.vue b/src/client/app/common/views/widgets/server.vue
index d796a3ae05..62d75e2bf6 100644
--- a/src/client/app/common/views/widgets/server.vue
+++ b/src/client/app/common/views/widgets/server.vue
@@ -45,8 +45,7 @@ export default define({
return {
fetching: true,
meta: null,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
@@ -55,11 +54,10 @@ export default define({
this.fetching = false;
});
- this.connection = (this as any).os.streams.serverStatsStream.getConnection();
- this.connectionId = (this as any).os.streams.serverStatsStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('serverStats');
},
beforeDestroy() {
- (this as any).os.streams.serverStatsStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
toggle() {
diff --git a/src/client/app/config.ts b/src/client/app/config.ts
index a326c521db..c3bc427eab 100644
--- a/src/client/app/config.ts
+++ b/src/client/app/config.ts
@@ -12,7 +12,7 @@ export const host = address.host;
export const hostname = address.hostname;
export const url = address.origin;
export const apiUrl = url + '/api';
-export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://');
+export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
export const lang = _LANG_;
export const langs = _LANGS_;
export const themeColor = _THEME_COLOR_;
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index 05aa928fa3..85c81d73a2 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -9,7 +9,6 @@ import './style.styl';
import init from '../init';
import fuckAdBlock from '../common/scripts/fuck-ad-block';
-import { HomeStreamManager } from '../common/scripts/streaming/home';
import composeNotification from '../common/scripts/compose-notification';
import chooseDriveFolder from './api/choose-drive-folder';
@@ -37,6 +36,7 @@ import MkTag from './views/pages/tag.vue';
import MkReversi from './views/pages/games/reversi.vue';
import MkShare from './views/pages/share.vue';
import MkFollow from '../common/views/pages/follow.vue';
+import MiOS from '../mios';
/**
* init
@@ -102,62 +102,56 @@ init(async (launch) => {
}
if ((Notification as any).permission == 'granted') {
- registerNotifications(os.stream);
+ registerNotifications(os);
}
}
}, true);
-function registerNotifications(stream: HomeStreamManager) {
+function registerNotifications(os: MiOS) {
+ const stream = os.stream;
+
if (stream == null) return;
- if (stream.hasConnection) {
- attach(stream.borrow());
- }
+ const connection = stream.useSharedConnection('main');
- stream.on('connected', connection => {
- attach(connection);
- });
-
- function attach(connection) {
- connection.on('notification', notification => {
- const _n = composeNotification('notification', notification);
- const n = new Notification(_n.title, {
- body: _n.body,
- icon: _n.icon
- });
- setTimeout(n.close.bind(n), 6000);
+ connection.on('notification', notification => {
+ const _n = composeNotification('notification', notification);
+ const n = new Notification(_n.title, {
+ body: _n.body,
+ icon: _n.icon
});
+ setTimeout(n.close.bind(n), 6000);
+ });
- connection.on('drive_file_created', file => {
- const _n = composeNotification('drive_file_created', file);
- const n = new Notification(_n.title, {
- body: _n.body,
- icon: _n.icon
- });
- setTimeout(n.close.bind(n), 5000);
+ connection.on('driveFileCreated', file => {
+ const _n = composeNotification('driveFileCreated', file);
+ const n = new Notification(_n.title, {
+ body: _n.body,
+ icon: _n.icon
});
+ setTimeout(n.close.bind(n), 5000);
+ });
- connection.on('unread_messaging_message', message => {
- const _n = composeNotification('unread_messaging_message', message);
- const n = new Notification(_n.title, {
- body: _n.body,
- icon: _n.icon
- });
- n.onclick = () => {
- n.close();
- /*(riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), {
- user: message.user
- });*/
- };
- setTimeout(n.close.bind(n), 7000);
+ connection.on('unreadMessagingMessage', message => {
+ const _n = composeNotification('unreadMessagingMessage', message);
+ const n = new Notification(_n.title, {
+ body: _n.body,
+ icon: _n.icon
});
+ n.onclick = () => {
+ n.close();
+ /*(riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), {
+ user: message.user
+ });*/
+ };
+ setTimeout(n.close.bind(n), 7000);
+ });
- connection.on('reversi_invited', matching => {
- const _n = composeNotification('reversi_invited', matching);
- const n = new Notification(_n.title, {
- body: _n.body,
- icon: _n.icon
- });
+ connection.on('reversiInvited', matching => {
+ const _n = composeNotification('reversiInvited', matching);
+ const n = new Notification(_n.title, {
+ body: _n.body,
+ icon: _n.icon
});
- }
+ });
}
diff --git a/src/client/app/desktop/views/components/drive.vue b/src/client/app/desktop/views/components/drive.vue
index f9b7eea64e..1376a04d99 100644
--- a/src/client/app/desktop/views/components/drive.vue
+++ b/src/client/app/desktop/views/components/drive.vue
@@ -98,8 +98,7 @@ export default Vue.extend({
hierarchyFolders: [],
selectedFiles: [],
uploadings: [],
- connection: null,
- connectionId: null,
+ connection: null
/**
* ドロップされようとしているか
@@ -116,8 +115,7 @@ export default Vue.extend({
};
},
mounted() {
- this.connection = (this as any).os.streams.driveStream.getConnection();
- this.connectionId = (this as any).os.streams.driveStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('drive');
this.connection.on('file_created', this.onStreamDriveFileCreated);
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
@@ -132,12 +130,7 @@ export default Vue.extend({
}
},
beforeDestroy() {
- this.connection.off('file_created', this.onStreamDriveFileCreated);
- this.connection.off('file_updated', this.onStreamDriveFileUpdated);
- this.connection.off('file_deleted', this.onStreamDriveFileDeleted);
- this.connection.off('folder_created', this.onStreamDriveFolderCreated);
- this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
- (this as any).os.streams.driveStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
onContextmenu(e) {
diff --git a/src/client/app/desktop/views/components/follow-button.vue b/src/client/app/desktop/views/components/follow-button.vue
index 4d4bd5cc5a..4d3d61dfe0 100644
--- a/src/client/app/desktop/views/components/follow-button.vue
+++ b/src/client/app/desktop/views/components/follow-button.vue
@@ -34,23 +34,18 @@ export default Vue.extend({
return {
u: this.user,
wait: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
-
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('follow', this.onFollow);
this.connection.on('unfollow', this.onUnfollow);
},
beforeDestroy() {
- this.connection.off('follow', this.onFollow);
- this.connection.off('unfollow', this.onUnfollow);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index bdaf2ddf47..9008e26263 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -141,7 +141,6 @@ export default Vue.extend({
data() {
return {
connection: null,
- connectionId: null,
widgetAdderSelected: null,
trash: []
};
@@ -176,12 +175,11 @@ export default Vue.extend({
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
},
beforeDestroy() {
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 0c4b560e98..b119f23d7a 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -93,12 +93,15 @@ import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './notes.note.sub.vue';
import { sum } from '../../../../../prelude/array';
+import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
components: {
XSub
},
+ mixins: [noteSubscriber('note')],
+
props: {
note: {
type: Object,
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index b628d045aa..3892260181 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -77,6 +77,7 @@ import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './notes.note.sub.vue';
import { sum } from '../../../../../prelude/array';
+import noteSubscriber from '../../../common/scripts/note-subscriber';
function focus(el, fn) {
const target = fn(el);
@@ -94,6 +95,8 @@ export default Vue.extend({
XSub
},
+ mixins: [noteSubscriber('note')],
+
props: {
note: {
type: Object,
@@ -104,9 +107,7 @@ export default Vue.extend({
data() {
return {
showContent: false,
- isDetailOpened: false,
- connection: null,
- connectionId: null
+ isDetailOpened: false
};
},
@@ -168,86 +169,7 @@ export default Vue.extend({
}
},
- created() {
- if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
- }
- },
-
- mounted() {
- this.capture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.on('_connected_', this.onStreamConnected);
- }
-
- // Draw map
- if (this.p.geo) {
- const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
- if (shouldShowMap) {
- (this as any).os.getGoogleMaps().then(maps => {
- const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
- const map = new maps.Map(this.$refs.map, {
- center: uluru,
- zoom: 15
- });
- new maps.Marker({
- position: uluru,
- map: map
- });
- });
- }
- }
- },
-
- beforeDestroy() {
- this.decapture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.off('_connected_', this.onStreamConnected);
- (this as any).os.stream.dispose(this.connectionId);
- }
- },
-
methods: {
- capture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- const data = {
- type: 'capture',
- id: this.p.id
- } as any;
- if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
- data.read = true;
- }
- this.connection.send(data);
- if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- decapture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- this.connection.send({
- type: 'decapture',
- id: this.p.id
- });
- if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- onStreamConnected() {
- this.capture();
- },
-
- onStreamNoteUpdated(data) {
- const note = data.note;
- if (note.id == this.note.id) {
- this.$emit('update:note', note);
- } else if (note.id == this.note.renoteId) {
- this.note.renote = note;
- }
- },
-
reply(viaKeyboard = false) {
(this as any).os.new(MkPostFormWindow, {
reply: this.p,
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index 1f3f62395a..95b8e1355a 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -118,10 +118,10 @@ export default Vue.extend({
notifications: [],
moreNotifications: false,
connection: null,
- connectionId: null,
getNoteSummary
};
},
+
computed: {
_notifications(): any[] {
return (this.notifications as any).map(notification => {
@@ -133,9 +133,9 @@ export default Vue.extend({
});
}
},
+
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('notification', this.onNotification);
@@ -153,10 +153,11 @@ export default Vue.extend({
this.fetching = false;
});
},
+
beforeDestroy() {
- this.connection.off('notification', this.onNotification);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
+
methods: {
fetchMoreNotifications() {
this.fetchingMoreNotifications = true;
@@ -177,10 +178,11 @@ export default Vue.extend({
this.fetchingMoreNotifications = false;
});
},
+
onNotification(notification) {
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
this.connection.send({
- type: 'read_notification',
+ type: 'readNotification',
id: notification.id
});
diff --git a/src/client/app/desktop/views/components/settings.signins.vue b/src/client/app/desktop/views/components/settings.signins.vue
index a414c95c27..7d1bb4f4e7 100644
--- a/src/client/app/desktop/views/components/settings.signins.vue
+++ b/src/client/app/desktop/views/components/settings.signins.vue
@@ -23,25 +23,25 @@ export default Vue.extend({
return {
fetching: true,
signins: [],
- connection: null,
- connectionId: null
+ connection: null
};
},
+
mounted() {
(this as any).api('i/signin_history').then(signins => {
this.signins = signins;
this.fetching = false;
});
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('signin', this.onSignin);
},
+
beforeDestroy() {
- this.connection.off('signin', this.onSignin);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
+
methods: {
onSignin(signin) {
this.signins.unshift(signin);
diff --git a/src/client/app/desktop/views/components/timeline.core.vue b/src/client/app/desktop/views/components/timeline.core.vue
index aef873dd11..2c17e936eb 100644
--- a/src/client/app/desktop/views/components/timeline.core.vue
+++ b/src/client/app/desktop/views/components/timeline.core.vue
@@ -15,7 +15,6 @@
<script lang="ts">
import Vue from 'vue';
-import { HashtagStream } from '../../../common/scripts/streaming/hashtag';
const fetchLimit = 10;
@@ -35,9 +34,7 @@ export default Vue.extend({
fetching: true,
moreFetching: false,
existMore: false,
- streamManager: null,
connection: null,
- connectionId: null,
date: null,
baseQuery: {
includeMyRenotes: this.$store.state.settings.showMyRenotes,
@@ -69,69 +66,33 @@ export default Vue.extend({
this.query = {
query: this.tagTl.query
};
- this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
+ this.connection = (this as any).os.stream.connectToChannel('hashtag', { q: this.tagTl.query });
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.connection.close();
- });
} else if (this.src == 'home') {
this.endpoint = 'notes/timeline';
const onChangeFollowing = () => {
this.fetch();
};
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('homeTimeline');
this.connection.on('note', prepend);
this.connection.on('follow', onChangeFollowing);
this.connection.on('unfollow', onChangeFollowing);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.connection.off('follow', onChangeFollowing);
- this.connection.off('unfollow', onChangeFollowing);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'local') {
this.endpoint = 'notes/local-timeline';
- this.streamManager = (this as any).os.streams.localTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'hybrid') {
this.endpoint = 'notes/hybrid-timeline';
- this.streamManager = (this as any).os.streams.hybridTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('hybridTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'global') {
this.endpoint = 'notes/global-timeline';
- this.streamManager = (this as any).os.streams.globalTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('globalTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'mentions') {
this.endpoint = 'notes/mentions';
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('mention', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'messages') {
this.endpoint = 'notes/mentions';
this.query = {
@@ -142,21 +103,15 @@ export default Vue.extend({
prepend(note);
}
};
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', onNote);
- this.$once('beforeDestroy', () => {
- this.connection.off('mention', onNote);
- this.streamManager.dispose(this.connectionId);
- });
}
this.fetch();
},
beforeDestroy() {
- this.$emit('beforeDestroy');
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue
index 4f679db938..122570a696 100644
--- a/src/client/app/desktop/views/components/ui.header.nav.vue
+++ b/src/client/app/desktop/views/components/ui.header.nav.vue
@@ -42,8 +42,7 @@ export default Vue.extend({
data() {
return {
hasGameInvitations: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
computed: {
@@ -53,18 +52,15 @@ export default Vue.extend({
},
mounted() {
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
- this.connection.on('reversi_invited', this.onReversiInvited);
+ this.connection.on('reversiInvited', this.onReversiInvited);
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
}
},
beforeDestroy() {
if (this.$store.getters.isSignedIn) {
- this.connection.off('reversi_invited', this.onReversiInvited);
- this.connection.off('reversi_no_invites', this.onReversiNoInvites);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
}
},
methods: {
diff --git a/src/client/app/desktop/views/components/user-list-timeline.vue b/src/client/app/desktop/views/components/user-list-timeline.vue
index 0a6f758763..3407851fc5 100644
--- a/src/client/app/desktop/views/components/user-list-timeline.vue
+++ b/src/client/app/desktop/views/components/user-list-timeline.vue
@@ -6,7 +6,6 @@
<script lang="ts">
import Vue from 'vue';
-import { UserListStream } from '../../../common/scripts/streaming/user-list';
const fetchLimit = 10;
diff --git a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue
index 1b0c5f8125..c0075220bc 100644
--- a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue
+++ b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue
@@ -56,13 +56,11 @@ export default Vue.extend({
disableLocalTimeline: false,
bannerUrl: null,
inviteCode: null,
- connection: null,
- connectionId: null
+ connection: null
};
},
created() {
- this.connection = (this as any).os.streams.serverStatsStream.getConnection();
- this.connectionId = (this as any).os.streams.serverStatsStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('serverStats');
(this as any).os.getMeta().then(meta => {
this.disableRegistration = meta.disableRegistration;
@@ -75,7 +73,7 @@ export default Vue.extend({
});
},
beforeDestroy() {
- (this as any).os.streams.serverStatsStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
invite() {
diff --git a/src/client/app/desktop/views/pages/deck/deck.direct.vue b/src/client/app/desktop/views/pages/deck/deck.direct.vue
index ec9e6b9c3d..c771e58a6e 100644
--- a/src/client/app/desktop/views/pages/deck/deck.direct.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.direct.vue
@@ -21,23 +21,19 @@ export default Vue.extend({
fetching: true,
moreFetching: false,
existMore: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
-
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', this.onNote);
this.fetch();
},
beforeDestroy() {
- this.connection.off('mention', this.onNote);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue b/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue
index f38d5a6df5..02d99d3883 100644
--- a/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue
@@ -5,7 +5,6 @@
<script lang="ts">
import Vue from 'vue';
import XNotes from './deck.notes.vue';
-import { HashtagStream } from '../../../../common/scripts/streaming/hashtag';
const fetchLimit = 10;
@@ -48,7 +47,7 @@ export default Vue.extend({
mounted() {
if (this.connection) this.connection.close();
- this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
+ this.connection = (this as any).os.stream.connectToChannel('hashtag', this.tagTl.query);
this.connection.on('note', this.onNote);
this.fetch();
diff --git a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue b/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
index e82e76e4d0..e543130310 100644
--- a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
@@ -5,7 +5,6 @@
<script lang="ts">
import Vue from 'vue';
import XNotes from './deck.notes.vue';
-import { UserListStream } from '../../../../common/scripts/streaming/user-list';
const fetchLimit = 10;
diff --git a/src/client/app/desktop/views/pages/deck/deck.mentions.vue b/src/client/app/desktop/views/pages/deck/deck.mentions.vue
index cecb75f067..17b572f146 100644
--- a/src/client/app/desktop/views/pages/deck/deck.mentions.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.mentions.vue
@@ -21,23 +21,19 @@ export default Vue.extend({
fetching: true,
moreFetching: false,
existMore: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
-
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', this.onNote);
this.fetch();
},
beforeDestroy() {
- this.connection.off('mention', this.onNote);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index eac0e78f0f..e843ac54fe 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -70,12 +70,15 @@ import parse from '../../../../../../mfm/parse';
import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../../common/views/components/reaction-picker.vue';
import XSub from './deck.note.sub.vue';
+import noteSubscriber from '../../../../common/scripts/note-subscriber';
export default Vue.extend({
components: {
XSub
},
+ mixins: [noteSubscriber('note')],
+
props: {
note: {
type: Object,
@@ -90,9 +93,7 @@ export default Vue.extend({
data() {
return {
- showContent: false,
- connection: null,
- connectionId: null
+ showContent: false
};
},
@@ -120,68 +121,7 @@ export default Vue.extend({
}
},
- created() {
- if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
- }
- },
-
- mounted() {
- this.capture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.on('_connected_', this.onStreamConnected);
- }
- },
-
- beforeDestroy() {
- this.decapture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.off('_connected_', this.onStreamConnected);
- (this as any).os.stream.dispose(this.connectionId);
- }
- },
-
methods: {
- capture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- const data = {
- type: 'capture',
- id: this.p.id
- } as any;
- if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
- data.read = true;
- }
- this.connection.send(data);
- if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- decapture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- this.connection.send({
- type: 'decapture',
- id: this.p.id
- });
- if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- onStreamConnected() {
- this.capture();
- },
-
- onStreamNoteUpdated(data) {
- const note = data.note;
- if (note.id == this.note.id) {
- this.$emit('update:note', note);
- } else if (note.id == this.note.renoteId) {
- this.note.renote = note;
- }
- },
-
reply() {
(this as any).apis.post({
reply: this.p
diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications.vue b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
index 1417cc3ee8..29de691fe2 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
@@ -38,8 +38,7 @@ export default Vue.extend({
notifications: [],
queue: [],
moreNotifications: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
@@ -62,8 +61,7 @@ export default Vue.extend({
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('notification', this.onNotification);
@@ -86,8 +84,7 @@ export default Vue.extend({
},
beforeDestroy() {
- this.connection.off('notification', this.onNotification);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
this.column.$off('top', this.onTop);
this.column.$off('bottom', this.onBottom);
@@ -117,7 +114,7 @@ export default Vue.extend({
onNotification(notification) {
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
this.connection.send({
- type: 'read_notification',
+ type: 'readNotification',
id: notification.id
});
diff --git a/src/client/app/desktop/views/pages/deck/deck.tl.vue b/src/client/app/desktop/views/pages/deck/deck.tl.vue
index 120ceb7fc2..8aed80fa1b 100644
--- a/src/client/app/desktop/views/pages/deck/deck.tl.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.tl.vue
@@ -36,18 +36,17 @@ export default Vue.extend({
fetching: true,
moreFetching: false,
existMore: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
computed: {
stream(): any {
switch (this.src) {
- case 'home': return (this as any).os.stream;
- case 'local': return (this as any).os.streams.localTimelineStream;
- case 'hybrid': return (this as any).os.streams.hybridTimelineStream;
- case 'global': return (this as any).os.streams.globalTimelineStream;
+ case 'home': return (this as any).os.stream.useSharedConnection('homeTimeline');
+ case 'local': return (this as any).os.stream.useSharedConnection('localTimeline');
+ case 'hybrid': return (this as any).os.stream.useSharedConnection('hybridTimeline');
+ case 'global': return (this as any).os.stream.useSharedConnection('globalTimeline');
}
},
@@ -68,8 +67,7 @@ export default Vue.extend({
},
mounted() {
- this.connection = this.stream.getConnection();
- this.connectionId = this.stream.use();
+ this.connection = this.stream;
this.connection.on('note', this.onNote);
if (this.src == 'home') {
@@ -81,12 +79,7 @@ export default Vue.extend({
},
beforeDestroy() {
- this.connection.off('note', this.onNote);
- if (this.src == 'home') {
- this.connection.off('follow', this.onChangeFollowing);
- this.connection.off('unfollow', this.onChangeFollowing);
- }
- this.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/mios.ts b/src/client/app/mios.ts
index ed9e3a6aeb..42171e71fa 100644
--- a/src/client/app/mios.ts
+++ b/src/client/app/mios.ts
@@ -1,3 +1,4 @@
+import autobind from 'autobind-decorator';
import Vue from 'vue';
import { EventEmitter } from 'eventemitter3';
import * as uuid from 'uuid';
@@ -5,19 +6,9 @@ import * as uuid from 'uuid';
import initStore from './store';
import { apiUrl, version, lang } from './config';
import Progress from './common/scripts/loading';
-import Connection from './common/scripts/streaming/stream';
-import { HomeStreamManager } from './common/scripts/streaming/home';
-import { DriveStreamManager } from './common/scripts/streaming/drive';
-import { ServerStatsStreamManager } from './common/scripts/streaming/server-stats';
-import { NotesStatsStreamManager } from './common/scripts/streaming/notes-stats';
-import { MessagingIndexStreamManager } from './common/scripts/streaming/messaging-index';
-import { ReversiStreamManager } from './common/scripts/streaming/games/reversi/reversi';
import Err from './common/views/components/connect-failed.vue';
-import { LocalTimelineStreamManager } from './common/scripts/streaming/local-timeline';
-import { HybridTimelineStreamManager } from './common/scripts/streaming/hybrid-timeline';
-import { GlobalTimelineStreamManager } from './common/scripts/streaming/global-timeline';
-import { erase } from '../../prelude/array';
+import Stream from './common/scripts/stream';
//#region api requests
let spinner = null;
@@ -102,30 +93,7 @@ export default class MiOS extends EventEmitter {
/**
* A connection manager of home stream
*/
- public stream: HomeStreamManager;
-
- /**
- * Connection managers
- */
- public streams: {
- localTimelineStream: LocalTimelineStreamManager;
- hybridTimelineStream: HybridTimelineStreamManager;
- globalTimelineStream: GlobalTimelineStreamManager;
- driveStream: DriveStreamManager;
- serverStatsStream: ServerStatsStreamManager;
- notesStatsStream: NotesStatsStreamManager;
- messagingIndexStream: MessagingIndexStreamManager;
- reversiStream: ReversiStreamManager;
- } = {
- localTimelineStream: null,
- hybridTimelineStream: null,
- globalTimelineStream: null,
- driveStream: null,
- serverStatsStream: null,
- notesStatsStream: null,
- messagingIndexStream: null,
- reversiStream: null
- };
+ public stream: Stream;
/**
* A registration of service worker
@@ -151,71 +119,36 @@ export default class MiOS extends EventEmitter {
this.shouldRegisterSw = shouldRegisterSw;
- //#region BIND
- this.log = this.log.bind(this);
- this.logInfo = this.logInfo.bind(this);
- this.logWarn = this.logWarn.bind(this);
- this.logError = this.logError.bind(this);
- this.init = this.init.bind(this);
- this.api = this.api.bind(this);
- this.getMeta = this.getMeta.bind(this);
- this.registerSw = this.registerSw.bind(this);
- //#endregion
-
if (this.debug) {
(window as any).os = this;
}
}
- private googleMapsIniting = false;
-
- public getGoogleMaps() {
- return new Promise((res, rej) => {
- if ((window as any).google && (window as any).google.maps) {
- res((window as any).google.maps);
- } else {
- this.once('init-google-maps', () => {
- res((window as any).google.maps);
- });
-
- //#region load google maps api
- if (!this.googleMapsIniting) {
- this.googleMapsIniting = true;
- (window as any).initGoogleMaps = () => {
- this.emit('init-google-maps');
- };
- const head = document.getElementsByTagName('head')[0];
- const script = document.createElement('script');
- script.setAttribute('src', `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=initGoogleMaps`);
- script.setAttribute('async', 'true');
- script.setAttribute('defer', 'true');
- head.appendChild(script);
- }
- //#endregion
- }
- });
- }
-
+ @autobind
public log(...args) {
if (!this.debug) return;
console.log.apply(null, args);
}
+ @autobind
public logInfo(...args) {
if (!this.debug) return;
console.info.apply(null, args);
}
+ @autobind
public logWarn(...args) {
if (!this.debug) return;
console.warn.apply(null, args);
}
+ @autobind
public logError(...args) {
if (!this.debug) return;
console.error.apply(null, args);
}
+ @autobind
public signout() {
this.store.dispatch('logout');
location.href = '/';
@@ -225,27 +158,10 @@ export default class MiOS extends EventEmitter {
* Initialize MiOS (boot)
* @param callback A function that call when initialized
*/
+ @autobind
public async init(callback) {
this.store = initStore(this);
- //#region Init stream managers
- this.streams.serverStatsStream = new ServerStatsStreamManager(this);
- this.streams.notesStatsStream = new NotesStatsStreamManager(this);
- this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.store.state.i);
-
- this.once('signedin', () => {
- // Init home stream manager
- this.stream = new HomeStreamManager(this, this.store.state.i);
-
- // Init other stream manager
- this.streams.hybridTimelineStream = new HybridTimelineStreamManager(this, this.store.state.i);
- this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.store.state.i);
- this.streams.driveStream = new DriveStreamManager(this, this.store.state.i);
- this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.store.state.i);
- this.streams.reversiStream = new ReversiStreamManager(this, this.store.state.i);
- });
- //#endregion
-
// ユーザーをフェッチしてコールバックする
const fetchme = (token, cb) => {
let me = null;
@@ -296,6 +212,8 @@ export default class MiOS extends EventEmitter {
const fetched = () => {
this.emit('signedin');
+ this.stream = new Stream(this);
+
// Finish init
callback();
@@ -328,6 +246,8 @@ export default class MiOS extends EventEmitter {
} else {
// Finish init
callback();
+
+ this.stream = new Stream(this);
}
});
}
@@ -336,6 +256,7 @@ export default class MiOS extends EventEmitter {
/**
* Register service worker
*/
+ @autobind
private registerSw() {
// Check whether service worker and push manager supported
const isSwSupported =
@@ -418,7 +339,8 @@ export default class MiOS extends EventEmitter {
* @param endpoint エンドポイント名
* @param data パラメータ
*/
- public api(endpoint: string, data: { [x: string]: any } = {}): Promise<{ [x: string]: any }> {
+ @autobind
+ public api(endpoint: string, data: { [x: string]: any } = {}, forceFetch = false): Promise<{ [x: string]: any }> {
if (++pending === 1) {
spinner = document.createElement('div');
spinner.setAttribute('id', 'wait');
@@ -430,13 +352,12 @@ export default class MiOS extends EventEmitter {
};
const promise = new Promise((resolve, reject) => {
- const viaStream = this.stream && this.stream.hasConnection && this.store.state.device.apiViaStream;
+ const viaStream = this.stream && this.store.state.device.apiViaStream && !forceFetch;
if (viaStream) {
- const stream = this.stream.borrow();
const id = Math.random().toString();
- stream.once(`api-res:${id}`, res => {
+ this.stream.once(`api:${id}`, res => {
if (res == null || Object.keys(res).length == 0) {
resolve(null);
} else if (res.res) {
@@ -446,11 +367,10 @@ export default class MiOS extends EventEmitter {
}
});
- stream.send({
- type: 'api',
- id,
- endpoint,
- data
+ this.stream.send('api', {
+ id: id,
+ ep: endpoint,
+ data: data
});
} else {
// Append a credential
@@ -503,6 +423,7 @@ export default class MiOS extends EventEmitter {
* Misskeyのメタ情報を取得します
* @param force キャッシュを無視するか否か
*/
+ @autobind
public getMeta(force = false) {
return new Promise<{ [x: string]: any }>(async (res, rej) => {
if (this.isMetaFetching) {
@@ -530,16 +451,6 @@ export default class MiOS extends EventEmitter {
}
});
}
-
- public connections: Connection[] = [];
-
- public registerStreamConnection(connection: Connection) {
- this.connections.push(connection);
- }
-
- public unregisterStreamConnection(connection: Connection) {
- this.connections = erase(connection, this.connections);
- }
}
class WindowSystem extends EventEmitter {
diff --git a/src/client/app/mobile/views/components/drive.vue b/src/client/app/mobile/views/components/drive.vue
index 8919462511..469f6da240 100644
--- a/src/client/app/mobile/views/components/drive.vue
+++ b/src/client/app/mobile/views/components/drive.vue
@@ -81,8 +81,7 @@ export default Vue.extend({
hierarchyFolders: [],
selectedFiles: [],
info: null,
- connection: null,
- connectionId: null,
+ connection: null
fetching: true,
fetchingMoreFiles: false,
@@ -102,8 +101,7 @@ export default Vue.extend({
}
},
mounted() {
- this.connection = (this as any).os.streams.driveStream.getConnection();
- this.connectionId = (this as any).os.streams.driveStream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('drive');
this.connection.on('file_created', this.onStreamDriveFileCreated);
this.connection.on('file_updated', this.onStreamDriveFileUpdated);
@@ -124,12 +122,7 @@ export default Vue.extend({
}
},
beforeDestroy() {
- this.connection.off('file_created', this.onStreamDriveFileCreated);
- this.connection.off('file_updated', this.onStreamDriveFileUpdated);
- this.connection.off('file_deleted', this.onStreamDriveFileDeleted);
- this.connection.off('folder_created', this.onStreamDriveFolderCreated);
- this.connection.off('folder_updated', this.onStreamDriveFolderUpdated);
- (this as any).os.streams.driveStream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
onStreamDriveFileCreated(file) {
diff --git a/src/client/app/mobile/views/components/follow-button.vue b/src/client/app/mobile/views/components/follow-button.vue
index aea2d285e4..3c8b2f98e6 100644
--- a/src/client/app/mobile/views/components/follow-button.vue
+++ b/src/client/app/mobile/views/components/follow-button.vue
@@ -28,21 +28,17 @@ export default Vue.extend({
return {
u: this.user,
wait: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('follow', this.onFollow);
this.connection.on('unfollow', this.onUnfollow);
},
beforeDestroy() {
- this.connection.off('follow', this.onFollow);
- this.connection.off('unfollow', this.onUnfollow);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 48d6d32868..082f72f1a9 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -92,12 +92,15 @@ import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note.sub.vue';
import { sum } from '../../../../../prelude/array';
+import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
components: {
XSub
},
+ mixins: [noteSubscriber('note')],
+
props: {
note: {
type: Object,
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 4af19ade29..db1be4a00e 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -69,19 +69,20 @@ import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
import XSub from './note.sub.vue';
import { sum } from '../../../../../prelude/array';
+import noteSubscriber from '../../../common/scripts/note-subscriber';
export default Vue.extend({
components: {
XSub
},
+ mixins: [noteSubscriber('note')],
+
props: ['note'],
data() {
return {
- showContent: false,
- connection: null,
- connectionId: null
+ showContent: false
};
},
@@ -115,86 +116,7 @@ export default Vue.extend({
}
},
- created() {
- if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
- }
- },
-
- mounted() {
- this.capture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.on('_connected_', this.onStreamConnected);
- }
-
- // Draw map
- if (this.p.geo) {
- const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
- if (shouldShowMap) {
- (this as any).os.getGoogleMaps().then(maps => {
- const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
- const map = new maps.Map(this.$refs.map, {
- center: uluru,
- zoom: 15
- });
- new maps.Marker({
- position: uluru,
- map: map
- });
- });
- }
- }
- },
-
- beforeDestroy() {
- this.decapture(true);
-
- if (this.$store.getters.isSignedIn) {
- this.connection.off('_connected_', this.onStreamConnected);
- (this as any).os.stream.dispose(this.connectionId);
- }
- },
-
methods: {
- capture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- const data = {
- type: 'capture',
- id: this.p.id
- } as any;
- if ((this.p.visibleUserIds || []).includes(this.$store.state.i.id) || (this.p.mentions || []).includes(this.$store.state.i.id)) {
- data.read = true;
- }
- this.connection.send(data);
- if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- decapture(withHandler = false) {
- if (this.$store.getters.isSignedIn) {
- this.connection.send({
- type: 'decapture',
- id: this.p.id
- });
- if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
- }
- },
-
- onStreamConnected() {
- this.capture();
- },
-
- onStreamNoteUpdated(data) {
- const note = data.note;
- if (note.id == this.note.id) {
- this.$emit('update:note', note);
- } else if (note.id == this.note.renoteId) {
- this.note.renote = note;
- }
- },
-
reply() {
(this as any).apis.post({
reply: this.p
diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue
index bfb6c1e62a..e1a2967071 100644
--- a/src/client/app/mobile/views/components/notifications.vue
+++ b/src/client/app/mobile/views/components/notifications.vue
@@ -23,6 +23,7 @@
<script lang="ts">
import Vue from 'vue';
+
export default Vue.extend({
data() {
return {
@@ -30,10 +31,10 @@ export default Vue.extend({
fetchingMoreNotifications: false,
notifications: [],
moreNotifications: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
+
computed: {
_notifications(): any[] {
return (this.notifications as any).map(notification => {
@@ -45,9 +46,9 @@ export default Vue.extend({
});
}
},
+
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('notification', this.onNotification);
@@ -66,10 +67,11 @@ export default Vue.extend({
this.$emit('fetched');
});
},
+
beforeDestroy() {
- this.connection.off('notification', this.onNotification);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
},
+
methods: {
fetchMoreNotifications() {
this.fetchingMoreNotifications = true;
@@ -90,10 +92,11 @@ export default Vue.extend({
this.fetchingMoreNotifications = false;
});
},
+
onNotification(notification) {
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
this.connection.send({
- type: 'read_notification',
+ type: 'readNotification',
id: notification.id
});
diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue
index 7fd68002e7..9793d03a8c 100644
--- a/src/client/app/mobile/views/components/ui.header.vue
+++ b/src/client/app/mobile/views/components/ui.header.vue
@@ -24,44 +24,47 @@ import { env } from '../../../config';
export default Vue.extend({
props: ['func'],
+
data() {
return {
hasGameInvitation: false,
connection: null,
- connectionId: null,
env: env
};
},
+
computed: {
hasUnreadNotification(): boolean {
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadNotification;
},
+
hasUnreadMessagingMessage(): boolean {
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
}
},
+
mounted() {
this.$store.commit('setUiHeaderHeight', this.$refs.root.offsetHeight);
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
- this.connection.on('reversi_invited', this.onReversiInvited);
+ this.connection.on('reversiInvited', this.onReversiInvited);
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
}
},
+
beforeDestroy() {
if (this.$store.getters.isSignedIn) {
- this.connection.off('reversi_invited', this.onReversiInvited);
- this.connection.off('reversi_no_invites', this.onReversiNoInvites);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
}
},
+
methods: {
onReversiInvited() {
this.hasGameInvitation = true;
},
+
onReversiNoInvites() {
this.hasGameInvitation = false;
}
diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue
index ba122cc3e2..c9c0c082b2 100644
--- a/src/client/app/mobile/views/components/ui.nav.vue
+++ b/src/client/app/mobile/views/components/ui.nav.vue
@@ -57,7 +57,6 @@ export default Vue.extend({
return {
hasGameInvitation: false,
connection: null,
- connectionId: null,
aboutUrl: `/docs/${lang}/about`,
announcements: []
};
@@ -79,19 +78,16 @@ export default Vue.extend({
});
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
- this.connection.on('reversi_invited', this.onReversiInvited);
+ this.connection.on('reversiInvited', this.onReversiInvited);
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
}
},
beforeDestroy() {
if (this.$store.getters.isSignedIn) {
- this.connection.off('reversi_invited', this.onReversiInvited);
- this.connection.off('reversi_no_invites', this.onReversiNoInvites);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
}
},
diff --git a/src/client/app/mobile/views/components/ui.vue b/src/client/app/mobile/views/components/ui.vue
index d2af15d235..b16c246b10 100644
--- a/src/client/app/mobile/views/components/ui.vue
+++ b/src/client/app/mobile/views/components/ui.vue
@@ -23,40 +23,43 @@ export default Vue.extend({
XHeader,
XNav
},
+
props: ['title'],
+
data() {
return {
isDrawerOpening: false,
- connection: null,
- connectionId: null
+ connection: null
};
},
+
watch: {
'$store.state.uiHeaderHeight'() {
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
}
},
+
mounted() {
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
if (this.$store.getters.isSignedIn) {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('notification', this.onNotification);
}
},
+
beforeDestroy() {
if (this.$store.getters.isSignedIn) {
- this.connection.off('notification', this.onNotification);
- (this as any).os.stream.dispose(this.connectionId);
+ this.connection.dispose();
}
},
+
methods: {
onNotification(notification) {
// TODO: ユーザーが画面を見てないと思われるとき(ブラウザやタブがアクティブじゃないなど)は送信しない
this.connection.send({
- type: 'read_notification',
+ type: 'readNotification',
id: notification.id
});
diff --git a/src/client/app/mobile/views/components/user-list-timeline.vue b/src/client/app/mobile/views/components/user-list-timeline.vue
index 9b3f11f5c2..97200eb5b3 100644
--- a/src/client/app/mobile/views/components/user-list-timeline.vue
+++ b/src/client/app/mobile/views/components/user-list-timeline.vue
@@ -6,7 +6,6 @@
<script lang="ts">
import Vue from 'vue';
-import { UserListStream } from '../../../common/scripts/streaming/user-list';
const fetchLimit = 10;
diff --git a/src/client/app/mobile/views/pages/home.timeline.vue b/src/client/app/mobile/views/pages/home.timeline.vue
index 225abcff6b..1979747bf7 100644
--- a/src/client/app/mobile/views/pages/home.timeline.vue
+++ b/src/client/app/mobile/views/pages/home.timeline.vue
@@ -13,7 +13,6 @@
<script lang="ts">
import Vue from 'vue';
-import { HashtagStream } from '../../../common/scripts/streaming/hashtag';
const fetchLimit = 10;
@@ -35,7 +34,6 @@ export default Vue.extend({
existMore: false,
streamManager: null,
connection: null,
- connectionId: null,
unreadCount: 0,
date: null,
baseQuery: {
@@ -68,69 +66,33 @@ export default Vue.extend({
this.query = {
query: this.tagTl.query
};
- this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
+ this.connection = (this as any).os.stream.connectToChannel('hashtag', { q: this.tagTl.query });
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.connection.close();
- });
} else if (this.src == 'home') {
this.endpoint = 'notes/timeline';
const onChangeFollowing = () => {
this.fetch();
};
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('homeTimeline');
this.connection.on('note', prepend);
this.connection.on('follow', onChangeFollowing);
this.connection.on('unfollow', onChangeFollowing);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.connection.off('follow', onChangeFollowing);
- this.connection.off('unfollow', onChangeFollowing);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'local') {
this.endpoint = 'notes/local-timeline';
- this.streamManager = (this as any).os.streams.localTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('localTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'hybrid') {
this.endpoint = 'notes/hybrid-timeline';
- this.streamManager = (this as any).os.streams.hybridTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('hybridTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'global') {
this.endpoint = 'notes/global-timeline';
- this.streamManager = (this as any).os.streams.globalTimelineStream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('globalTimeline');
this.connection.on('note', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('note', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'mentions') {
this.endpoint = 'notes/mentions';
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', prepend);
- this.$once('beforeDestroy', () => {
- this.connection.off('mention', prepend);
- this.streamManager.dispose(this.connectionId);
- });
} else if (this.src == 'messages') {
this.endpoint = 'notes/mentions';
this.query = {
@@ -141,21 +103,15 @@ export default Vue.extend({
prepend(note);
}
};
- this.streamManager = (this as any).os.stream;
- this.connection = this.streamManager.getConnection();
- this.connectionId = this.streamManager.use();
+ this.connection = (this as any).os.stream.useSharedConnection('main');
this.connection.on('mention', onNote);
- this.$once('beforeDestroy', () => {
- this.connection.off('mention', onNote);
- this.streamManager.dispose(this.connectionId);
- });
}
this.fetch();
},
beforeDestroy() {
- this.$emit('beforeDestroy');
+ this.connection.dispose();
},
methods: {
diff --git a/src/client/app/tsconfig.json b/src/client/app/tsconfig.json
index e31b52dab1..4a05469673 100644
--- a/src/client/app/tsconfig.json
+++ b/src/client/app/tsconfig.json
@@ -14,7 +14,8 @@
"removeComments": false,
"noLib": false,
"strict": true,
- "strictNullChecks": false
+ "strictNullChecks": false,
+ "experimentalDecorators": true
},
"compileOnSave": false,
"include": [