FoundKey/src/server/api/stream/channels/messaging.ts
tamaina 69b56f6658
refactor: publishHogeStreamとStreamのEventEmitterに型定義する (#7769)
* wip

* wip

* wip

* ✌️

* add main stream

* packedNotificationSchemaを更新

* read:gallery, write:gallery, read:gallery-likes, write:gallery-likesに翻訳を追加

* fix

* ok

* add header, choice, invitation

* add header, choice, invitation

* test

* fix

* fix

* yatta

* remove no longer needed "as PackedUser/PackedNote"

* clean up

* add simple-schema

* fix lint

* fix lint

* wip

* wip!

* wip

* fix

* wip

* wip

* ✌️

* 送信側に型エラーがないことを3回確認した

* ✌️

* wip

* update typescript

* define items in full Schema

* edit comment

* edit comment

* edit comment

* Update src/prelude/types.ts

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* https://github.com/misskey-dev/misskey/pull/7769#discussion_r703058458

* user packとnote packの型不整合を修正

* revert https://github.com/misskey-dev/misskey/pull/7772#discussion_r706627736

* revert https://github.com/misskey-dev/misskey/pull/7772#discussion_r706627736

* user packとnote packの型不整合を修正

* add prelude/types.ts

* emoji

* signin

* game

* matching

* clean up

* ev => data

* refactor

* clean up

* add type

* antenna

* channel

* fix

* add Packed type

* add PackedRef

* fix lint

* add emoji schema

* add reversiGame

* add reversiMatching

* remove signin schema (use Signin entity)

* add schemas refs, fix Packed type

* wip PackedHoge => Packed<'Hoge'>

* add Packed type

* note-reaction

* user

* user-group

* user-list

* note

* app, messaging-message

* notification

* drive-file

* drive-folder

* following

* muting

* blocking

* hashtag

* page

* app (with modifying schema)

* import user?

* channel

* antenna

* clip

* gallery-post

* emoji

* Packed

* reversi-matching

* update stream.ts

* https://github.com/misskey-dev/misskey/pull/7769#issuecomment-917542339

* fix lint

* clean up?

* add changelog

* add changelog

* add changelog

* fix: アンテナが既読にならないのを修正

* revert fix

* https://github.com/misskey-dev/misskey/pull/7769#discussion_r711474875

* spec => payload

* edit commetn

Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
2021-10-21 01:04:10 +09:00

107 lines
3.1 KiB
TypeScript

import autobind from 'autobind-decorator';
import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from '../../common/read-messaging-message';
import Channel from '../channel';
import { UserGroupJoinings, Users, MessagingMessages } from '@/models/index';
import { User, ILocalUser, IRemoteUser } from '@/models/entities/user';
import { UserGroup } from '@/models/entities/user-group';
import { StreamMessages } from '../types';
export default class extends Channel {
public readonly chName = 'messaging';
public static shouldShare = false;
public static requireCredential = true;
private otherpartyId: string | null;
private otherparty: User | null;
private groupId: string | null;
private subCh: `messagingStream:${User['id']}-${User['id']}` | `messagingStream:${UserGroup['id']}`;
private typers: Record<User['id'], Date> = {};
private emitTypersIntervalId: ReturnType<typeof setInterval>;
@autobind
public async init(params: any) {
this.otherpartyId = params.otherparty;
this.otherparty = this.otherpartyId ? await Users.findOneOrFail({ id: this.otherpartyId }) : null;
this.groupId = params.group;
// Check joining
if (this.groupId) {
const joining = await UserGroupJoinings.findOne({
userId: this.user!.id,
userGroupId: this.groupId
});
if (joining == null) {
return;
}
}
this.emitTypersIntervalId = setInterval(this.emitTypers, 5000);
this.subCh = this.otherpartyId
? `messagingStream:${this.user!.id}-${this.otherpartyId}`
: `messagingStream:${this.groupId}`;
// Subscribe messaging stream
this.subscriber.on(this.subCh, this.onEvent);
}
@autobind
private onEvent(data: StreamMessages['messaging']['payload'] | StreamMessages['groupMessaging']['payload']) {
if (data.type === 'typing') {
const id = data.body;
const begin = this.typers[id] == null;
this.typers[id] = new Date();
if (begin) {
this.emitTypers();
}
} else {
this.send(data);
}
}
@autobind
public onMessage(type: string, body: any) {
switch (type) {
case 'read':
if (this.otherpartyId) {
readUserMessagingMessage(this.user!.id, this.otherpartyId, [body.id]);
// リモートユーザーからのメッセージだったら既読配信
if (Users.isLocalUser(this.user!) && Users.isRemoteUser(this.otherparty!)) {
MessagingMessages.findOne(body.id).then(message => {
if (message) deliverReadActivity(this.user as ILocalUser, this.otherparty as IRemoteUser, message);
});
}
} else if (this.groupId) {
readGroupMessagingMessage(this.user!.id, this.groupId, [body.id]);
}
break;
}
}
@autobind
private async emitTypers() {
const now = new Date();
// Remove not typing users
for (const [userId, date] of Object.entries(this.typers)) {
if (now.getTime() - date.getTime() > 5000) delete this.typers[userId];
}
const users = await Users.packMany(Object.keys(this.typers), null, { detail: false });
this.send({
type: 'typers',
body: users,
});
}
@autobind
public dispose() {
this.subscriber.off(this.subCh, this.onEvent);
clearInterval(this.emitTypersIntervalId);
}
}