summaryrefslogtreecommitdiff
path: root/src/server/api/stream/home.ts
blob: d9b8f7fb96a42be32120e693548b61c248baf7a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import * as websocket from 'websocket';
import * as redis from 'redis';
import * as debug from 'debug';

import User, { IUser } from '../../../models/user';
import Mute from '../../../models/mute';
import { pack as packNote, pack } from '../../../models/note';
import readNotification from '../common/read-notification';
import call from '../call';
import { IApp } from '../../../models/app';

const log = debug('misskey');

export default async function(
	request: websocket.request,
	connection: websocket.connection,
	subscriber: redis.RedisClient,
	user: IUser,
	app: IApp
) {
	// Subscribe Home stream channel
	subscriber.subscribe(`misskey:user-stream:${user._id}`);

	const mute = await Mute.find({ muterId: user._id });
	const mutedUserIds = mute.map(m => m.muteeId.toString());

	subscriber.on('message', async (channel, data) => {
		switch (channel.split(':')[1]) {
			case 'user-stream':
				try {
					const x = JSON.parse(data);

					//#region 流れてきたメッセージがミュートしているユーザーが関わるものだったら無視する
					if (x.type == 'note') {
						if (mutedUserIds.includes(x.body.userId)) {
							return;
						}
						if (x.body.reply != null && mutedUserIds.includes(x.body.reply.userId)) {
							return;
						}
						if (x.body.renote != null && mutedUserIds.includes(x.body.renote.userId)) {
							return;
						}
					} else if (x.type == 'notification') {
						if (mutedUserIds.includes(x.body.userId)) {
							return;
						}
					}
					//#endregion

					// Renoteなら再pack
					if (x.type == 'note' && x.body.renoteId != null) {
						x.body.renote = await pack(x.body.renoteId, user, {
							detail: true
						});
						data = JSON.stringify(x);
					}

					connection.send(data);
				} catch (e) {
					connection.send(data);
				}
				break;

			case 'note-stream':
				const noteId = channel.split(':')[2];
				log(`RECEIVED: ${noteId} ${data} by @${user.username}`);
				const note = await packNote(noteId, user, {
					detail: true
				});
				connection.send(JSON.stringify({
					type: 'note-updated',
					body: {
						note: note
					}
				}));
				break;
		}
	});

	connection.on('message', async data => {
		const msg = JSON.parse(data.utf8Data);

		switch (msg.type) {
			case 'api':
				// 新鮮なデータを利用するためにユーザーをフェッチ
				call(msg.endpoint, await User.findOne({ _id: user._id }), app, msg.data).then(res => {
					connection.send(JSON.stringify({
						type: `api-res:${msg.id}`,
						body: { res }
					}));
				}).catch(e => {
					connection.send(JSON.stringify({
						type: `api-res:${msg.id}`,
						body: { e }
					}));
				});
				break;

			case 'alive':
				// Update lastUsedAt
				User.update({ _id: user._id }, {
					$set: {
						'lastUsedAt': new Date()
					}
				});
				break;

			case 'read_notification':
				if (!msg.id) return;
				readNotification(user._id, msg.id);
				break;

			case 'capture':
				if (!msg.id) return;
				const noteId = msg.id;
				log(`CAPTURE: ${noteId} by @${user.username}`);
				subscriber.subscribe(`misskey:note-stream:${noteId}`);
				break;
		}
	});
}