@owlmeans/server-socket 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +560 -0
- package/build/.gitkeep +0 -0
- package/build/consts.d.ts +2 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +2 -0
- package/build/consts.js.map +1 -0
- package/build/helper.d.ts +7 -0
- package/build/helper.d.ts.map +1 -0
- package/build/helper.js +14 -0
- package/build/helper.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/middleware.d.ts +3 -0
- package/build/middleware.d.ts.map +1 -0
- package/build/middleware.js +25 -0
- package/build/middleware.js.map +1 -0
- package/build/service.d.ts +5 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +109 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +11 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/connection.d.ts +6 -0
- package/build/utils/connection.d.ts.map +1 -0
- package/build/utils/connection.js +104 -0
- package/build/utils/connection.js.map +1 -0
- package/build/utils/index.d.ts +3 -0
- package/build/utils/index.d.ts.map +1 -0
- package/build/utils/index.js +3 -0
- package/build/utils/index.js.map +1 -0
- package/build/utils/server.d.ts +5 -0
- package/build/utils/server.d.ts.map +1 -0
- package/build/utils/server.js +15 -0
- package/build/utils/server.js.map +1 -0
- package/package.json +46 -0
- package/src/consts.ts +2 -0
- package/src/helper.ts +21 -0
- package/src/index.ts +6 -0
- package/src/middleware.ts +32 -0
- package/src/service.ts +133 -0
- package/src/types.ts +12 -0
- package/src/utils/connection.ts +124 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/server.ts +21 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { WebSocket } from '@fastify/websocket'
|
|
2
|
+
import type { Connection, EventMessage } from '@owlmeans/socket'
|
|
3
|
+
import type { Config, Context } from '@owlmeans/server-api'
|
|
4
|
+
import {
|
|
5
|
+
SocketUnsupported, createBasicConnection, MessageType, SocketInitializationError, SocketUnauthorized
|
|
6
|
+
} from '@owlmeans/socket'
|
|
7
|
+
import { AbstractRequest } from '@owlmeans/module'
|
|
8
|
+
import { AuthenticationStage, AUTH_QUERY } from '@owlmeans/auth'
|
|
9
|
+
import type { Auth, AuthCredentials } from '@owlmeans/auth'
|
|
10
|
+
import { isAuth, isAuthCredentials, isAuthToken } from '@owlmeans/auth'
|
|
11
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
12
|
+
import type { AuthServiceAppend } from '@owlmeans/server-auth'
|
|
13
|
+
|
|
14
|
+
export const makeConnection = <C extends Config, T extends Context<C> = Context<C>>(
|
|
15
|
+
request: AbstractRequest<WebSocket>, context: T
|
|
16
|
+
): Connection => {
|
|
17
|
+
if (request.body == null) {
|
|
18
|
+
throw new SocketInitializationError('request')
|
|
19
|
+
}
|
|
20
|
+
let auth: Auth | AuthCredentials | null | undefined = undefined
|
|
21
|
+
const conn = request.body
|
|
22
|
+
|
|
23
|
+
const model = createBasicConnection()
|
|
24
|
+
|
|
25
|
+
model.close = async () => {
|
|
26
|
+
await conn.close()
|
|
27
|
+
// @TODO check if on close event is triggered
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
model.send = async message => {
|
|
31
|
+
if (typeof message !== 'string') {
|
|
32
|
+
model.prepare?.(message)
|
|
33
|
+
}
|
|
34
|
+
await conn.send(typeof message === 'string' ? message : JSON.stringify(message))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// @TODO This method is fully supported only by authentication services
|
|
38
|
+
model.authenticate = async (stage, payload) => {
|
|
39
|
+
if (AuthenticationStage.Authenticate === stage) {
|
|
40
|
+
if (isAuthToken(payload)) {
|
|
41
|
+
const ctx = context as AuthServiceAppend & T
|
|
42
|
+
const _auth = await ctx.auth().authenticate(payload)
|
|
43
|
+
if (_auth == null) {
|
|
44
|
+
throw new SocketUnauthorized(stage)
|
|
45
|
+
}
|
|
46
|
+
const model = makeEnvelopeModel<Auth>(_auth.token, EnvelopeKind.Token)
|
|
47
|
+
auth = model.message()
|
|
48
|
+
|
|
49
|
+
return [AuthenticationStage.Authenticated, _auth as any]
|
|
50
|
+
}
|
|
51
|
+
if (isAuth(payload)) {
|
|
52
|
+
auth = payload
|
|
53
|
+
|
|
54
|
+
return [stage, auth as any]
|
|
55
|
+
}
|
|
56
|
+
} else if (AuthenticationStage.Authenticated === stage) {
|
|
57
|
+
if (auth == null) {
|
|
58
|
+
throw new SocketUnauthorized(stage)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return [stage, auth as any]
|
|
62
|
+
}
|
|
63
|
+
throw new SocketUnsupported('auth-service')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
model.prepare = (message, isRequest) => {
|
|
67
|
+
if (auth === undefined) {
|
|
68
|
+
auth = null
|
|
69
|
+
try {
|
|
70
|
+
let authorization = (request.query as any)?.[AUTH_QUERY]
|
|
71
|
+
if (authorization != null) {
|
|
72
|
+
const envelope = makeEnvelopeModel<Auth | AuthCredentials>(authorization, EnvelopeKind.Token)
|
|
73
|
+
const _auth = envelope.message()
|
|
74
|
+
if (isAuth(_auth) || isAuthCredentials(_auth)) {
|
|
75
|
+
auth = _auth
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
auth = null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (isRequest) {
|
|
83
|
+
message.dt = message.dt ?? Date.now()
|
|
84
|
+
if (auth != null && message.recipient == null) {
|
|
85
|
+
message.recipient = auth.profileId ?? auth.userId
|
|
86
|
+
}
|
|
87
|
+
if (message.sender == null) {
|
|
88
|
+
// @TODO think about using dids here
|
|
89
|
+
message.sender = context.cfg.service
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (auth != null && message.sender == null) {
|
|
93
|
+
message.sender = auth.profileId ?? auth.userId
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return message
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const messageHandler = async (_message: Buffer | Buffer[]) => {
|
|
101
|
+
_message = Array.isArray(_message) ? _message : [_message]
|
|
102
|
+
const message = _message.map(msg => msg.toString('utf8')).join('')
|
|
103
|
+
await model.receive(message)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const closeHandler = async (code: number) => {
|
|
107
|
+
const msg: EventMessage<{ code: number }> = {
|
|
108
|
+
type: MessageType.System,
|
|
109
|
+
event: 'close',
|
|
110
|
+
payload: { code }
|
|
111
|
+
}
|
|
112
|
+
if (model.prepare != null) {
|
|
113
|
+
model.prepare(msg)
|
|
114
|
+
}
|
|
115
|
+
await Promise.all(model.getListeners().map(async listener => listener(msg)))
|
|
116
|
+
conn.off('message', messageHandler)
|
|
117
|
+
conn.off('close', closeHandler)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
conn.on('message', messageHandler)
|
|
121
|
+
conn.on('close', closeHandler)
|
|
122
|
+
|
|
123
|
+
return model
|
|
124
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CommonModule } from '@owlmeans/module'
|
|
2
|
+
import type { ServerModule } from '@owlmeans/server-module'
|
|
3
|
+
import { RouteProtocols } from '@owlmeans/route'
|
|
4
|
+
import { AppType } from '@owlmeans/context'
|
|
5
|
+
import type { Context } from '@owlmeans/server-api'
|
|
6
|
+
|
|
7
|
+
export const canServerModule = (context: Context, module: CommonModule): module is ServerModule<unknown> => {
|
|
8
|
+
if (module.route.route.type !== AppType.Backend) {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (module.route.route.service != null && module.route.route.service !== context.cfg.service) {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (module.route.route.protocol !== RouteProtocols.SOCKET) {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return 'isIntermediate' in module.route
|
|
21
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"../tsconfig.default.json",
|
|
4
|
+
"../tsconfig.react.json",
|
|
5
|
+
],
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"rootDir": "./src/", /* Specify the root folder within your source files. */
|
|
8
|
+
"outDir": "./build/", /* Specify an output folder for all emitted files. */
|
|
9
|
+
"moduleResolution": "Bundler"
|
|
10
|
+
},
|
|
11
|
+
"exclude": [
|
|
12
|
+
"./dist/**/*",
|
|
13
|
+
"./build/**/*",
|
|
14
|
+
"./*.ts"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/consts.ts","./src/helper.ts","./src/index.ts","./src/middleware.ts","./src/service.ts","./src/types.ts","./src/utils/connection.ts","./src/utils/index.ts","./src/utils/server.ts"],"version":"5.6.3"}
|