/
receiver.ts
126 lines (113 loc) · 3.45 KB
/
receiver.ts
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
123
124
125
126
import type { PopEventWrapper, PopEventFn, PopErrorFn } from '@machinat/core';
import { makeClassProvider } from '@machinat/core/service';
import ModuleUtilitiesI from '@machinat/core/base/ModuleUtilities';
import {
AnyServerAuthenticator,
UserOfAuthenticator,
ContextOfAuthenticator,
} from '@machinat/auth';
import type { HttpRequestInfo } from '@machinat/http';
import WebSocket, {
EventInput,
EventValue,
ConnectEventValue,
DisconnectEventValue,
} from '@machinat/websocket';
import { WEBVIEW } from './constant';
import { WebviewSocketServer, PlatformUtilitiesI } from './interface';
import { BotP } from './bot';
import { WebviewConnection } from './channel';
import { createEvent } from './utils';
import type { WebviewEventContext } from './types';
/**
* @category Provider
*/
export class WebviewReceiver<
Authenticator extends AnyServerAuthenticator,
Value extends EventValue
> {
private _bot: BotP;
private _server: WebviewSocketServer<Authenticator>;
private _popEvent: PopEventFn<
WebviewEventContext<Authenticator, Value>,
null
>;
private _popError: PopErrorFn;
constructor(
bot: BotP,
server: WebviewSocketServer<Authenticator>,
popEventWrapper: PopEventWrapper<
WebviewEventContext<Authenticator, Value>,
null
>,
popError: PopErrorFn
) {
this._bot = bot;
this._server = server;
this._popEvent = popEventWrapper(() => Promise.resolve(null));
this._popError = popError;
this._server.on(
'events',
(values, { connId, user, request, authContext }) => {
values.forEach((value) => {
this._issueEvent(value, connId, user, request, authContext);
});
}
);
this._server.on('connect', ({ connId, user, request, authContext }) => {
const value: ConnectEventValue = {
category: 'connection',
type: 'connect',
payload: null,
};
this._issueEvent(value, connId, user, request, authContext);
});
this._server.on('disconnect', ({ reason }, connData) => {
const { connId, user, request, authContext } = connData;
const value: DisconnectEventValue = {
category: 'connection',
type: 'disconnect',
payload: { reason },
};
this._issueEvent(value, connId, user, request, authContext);
});
this._server.on('error', (err: Error) => {
this._popError(err);
});
}
private _issueEvent(
value: EventInput,
connId: string,
user: UserOfAuthenticator<Authenticator>,
request: HttpRequestInfo,
authContext: ContextOfAuthenticator<Authenticator>
) {
const channel = new WebviewConnection(this._server.id, connId);
this._popEvent({
platform: WEBVIEW,
bot: this._bot,
event: createEvent(value, channel, user),
metadata: {
source: 'websocket',
request,
connection: channel,
auth: authContext,
},
reply: (message) => this._bot.render(channel, message),
}).catch(this._popError);
}
}
export const ReceiverP = makeClassProvider({
lifetime: 'singleton',
deps: [BotP, WebSocket.Server, ModuleUtilitiesI, PlatformUtilitiesI],
factory: (
bot,
server: WebviewSocketServer<AnyServerAuthenticator>,
{ popError },
{ popEventWrapper }
) => new WebviewReceiver(bot, server, popEventWrapper, popError),
})(WebviewReceiver);
export type ReceiverP<
Authenticator extends AnyServerAuthenticator,
Value extends EventValue
> = WebviewReceiver<Authenticator, Value>;