proteum 1.0.0-1

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.
Files changed (156) hide show
  1. package/.dockerignore +10 -0
  2. package/Rte.zip +0 -0
  3. package/cli/app/config.ts +54 -0
  4. package/cli/app/index.ts +195 -0
  5. package/cli/bin.js +11 -0
  6. package/cli/commands/build.ts +34 -0
  7. package/cli/commands/deploy/app.ts +29 -0
  8. package/cli/commands/deploy/web.ts +60 -0
  9. package/cli/commands/dev.ts +109 -0
  10. package/cli/commands/init.ts +85 -0
  11. package/cli/compiler/client/identite.ts +72 -0
  12. package/cli/compiler/client/index.ts +334 -0
  13. package/cli/compiler/common/babel/index.ts +170 -0
  14. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  15. package/cli/compiler/common/babel/plugins/services.ts +579 -0
  16. package/cli/compiler/common/babel/routes/imports.ts +127 -0
  17. package/cli/compiler/common/babel/routes/routes.ts +1130 -0
  18. package/cli/compiler/common/files/autres.ts +39 -0
  19. package/cli/compiler/common/files/images.ts +35 -0
  20. package/cli/compiler/common/files/style.ts +78 -0
  21. package/cli/compiler/common/index.ts +154 -0
  22. package/cli/compiler/index.ts +532 -0
  23. package/cli/compiler/server/index.ts +211 -0
  24. package/cli/index.ts +189 -0
  25. package/cli/paths.ts +165 -0
  26. package/cli/print.ts +12 -0
  27. package/cli/tsconfig.json +38 -0
  28. package/cli/utils/index.ts +22 -0
  29. package/cli/utils/keyboard.ts +78 -0
  30. package/client/app/component.tsx +54 -0
  31. package/client/app/index.ts +142 -0
  32. package/client/app/service.ts +34 -0
  33. package/client/app.tsconfig.json +28 -0
  34. package/client/components/Button.tsx +298 -0
  35. package/client/components/Dialog/Manager.tsx +309 -0
  36. package/client/components/Dialog/card.tsx +208 -0
  37. package/client/components/Dialog/index.less +151 -0
  38. package/client/components/Dialog/status.less +176 -0
  39. package/client/components/Dialog/status.tsx +48 -0
  40. package/client/components/index.ts +2 -0
  41. package/client/components/types.d.ts +3 -0
  42. package/client/data/input.ts +32 -0
  43. package/client/global.d.ts +5 -0
  44. package/client/hooks.ts +22 -0
  45. package/client/index.ts +6 -0
  46. package/client/pages/_layout/index.less +6 -0
  47. package/client/pages/_layout/index.tsx +43 -0
  48. package/client/pages/bug.tsx.old +60 -0
  49. package/client/pages/useHeader.tsx +50 -0
  50. package/client/services/captcha/index.ts +67 -0
  51. package/client/services/router/components/Link.tsx +46 -0
  52. package/client/services/router/components/Page.tsx +55 -0
  53. package/client/services/router/components/router.tsx +218 -0
  54. package/client/services/router/index.tsx +521 -0
  55. package/client/services/router/request/api.ts +267 -0
  56. package/client/services/router/request/history.ts +5 -0
  57. package/client/services/router/request/index.ts +53 -0
  58. package/client/services/router/request/multipart.ts +147 -0
  59. package/client/services/router/response/index.tsx +128 -0
  60. package/client/services/router/response/page.ts +86 -0
  61. package/client/services/socket/index.ts +147 -0
  62. package/client/utils/dom.ts +77 -0
  63. package/common/app/index.ts +9 -0
  64. package/common/data/chaines/index.ts +54 -0
  65. package/common/data/dates.ts +179 -0
  66. package/common/data/markdown.ts +73 -0
  67. package/common/data/rte/nodes.ts +83 -0
  68. package/common/data/stats.ts +90 -0
  69. package/common/errors/index.tsx +326 -0
  70. package/common/router/index.ts +213 -0
  71. package/common/router/layouts.ts +93 -0
  72. package/common/router/register.ts +55 -0
  73. package/common/router/request/api.ts +77 -0
  74. package/common/router/request/index.ts +35 -0
  75. package/common/router/response/index.ts +45 -0
  76. package/common/router/response/page.ts +128 -0
  77. package/common/utils/rte.ts +183 -0
  78. package/common/utils.ts +7 -0
  79. package/doc/TODO.md +71 -0
  80. package/doc/front/router.md +27 -0
  81. package/doc/workspace/workspace.png +0 -0
  82. package/doc/workspace/workspace2.png +0 -0
  83. package/doc/workspace/workspace_26.01.22.png +0 -0
  84. package/package.json +171 -0
  85. package/server/app/commands.ts +141 -0
  86. package/server/app/container/config.ts +203 -0
  87. package/server/app/container/console/index.ts +550 -0
  88. package/server/app/container/index.ts +137 -0
  89. package/server/app/index.ts +273 -0
  90. package/server/app/service/container.ts +88 -0
  91. package/server/app/service/index.ts +235 -0
  92. package/server/app.tsconfig.json +28 -0
  93. package/server/context.ts +4 -0
  94. package/server/index.ts +4 -0
  95. package/server/services/auth/index.ts +250 -0
  96. package/server/services/auth/old.ts +277 -0
  97. package/server/services/auth/router/index.ts +95 -0
  98. package/server/services/auth/router/request.ts +54 -0
  99. package/server/services/auth/router/service.json +6 -0
  100. package/server/services/auth/service.json +6 -0
  101. package/server/services/cache/commands.ts +41 -0
  102. package/server/services/cache/index.ts +297 -0
  103. package/server/services/cache/service.json +6 -0
  104. package/server/services/cron/CronTask.ts +86 -0
  105. package/server/services/cron/index.ts +112 -0
  106. package/server/services/cron/service.json +6 -0
  107. package/server/services/disks/driver.ts +103 -0
  108. package/server/services/disks/drivers/local/index.ts +188 -0
  109. package/server/services/disks/drivers/local/service.json +6 -0
  110. package/server/services/disks/drivers/s3/index.ts +301 -0
  111. package/server/services/disks/drivers/s3/service.json +6 -0
  112. package/server/services/disks/index.ts +90 -0
  113. package/server/services/disks/service.json +6 -0
  114. package/server/services/email/index.ts +188 -0
  115. package/server/services/email/utils.ts +53 -0
  116. package/server/services/fetch/index.ts +201 -0
  117. package/server/services/fetch/service.json +7 -0
  118. package/server/services/models.7z +0 -0
  119. package/server/services/prisma/Facet.ts +142 -0
  120. package/server/services/prisma/index.ts +201 -0
  121. package/server/services/prisma/service.json +6 -0
  122. package/server/services/router/http/index.ts +217 -0
  123. package/server/services/router/http/multipart.ts +102 -0
  124. package/server/services/router/http/session.ts.old +40 -0
  125. package/server/services/router/index.ts +801 -0
  126. package/server/services/router/request/api.ts +87 -0
  127. package/server/services/router/request/index.ts +184 -0
  128. package/server/services/router/request/service.ts +21 -0
  129. package/server/services/router/request/validation/zod.ts +180 -0
  130. package/server/services/router/response/index.ts +338 -0
  131. package/server/services/router/response/mask/Filter.ts +323 -0
  132. package/server/services/router/response/mask/index.ts +60 -0
  133. package/server/services/router/response/mask/selecteurs.ts +92 -0
  134. package/server/services/router/response/page/document.tsx +160 -0
  135. package/server/services/router/response/page/index.tsx +196 -0
  136. package/server/services/router/service.json +6 -0
  137. package/server/services/router/service.ts +36 -0
  138. package/server/services/schema/index.ts +44 -0
  139. package/server/services/schema/request.ts +49 -0
  140. package/server/services/schema/router/index.ts +28 -0
  141. package/server/services/schema/router/service.json +6 -0
  142. package/server/services/schema/service.json +6 -0
  143. package/server/services/security/encrypt/aes/index.ts +85 -0
  144. package/server/services/security/encrypt/aes/service.json +6 -0
  145. package/server/services/socket/index.ts +162 -0
  146. package/server/services/socket/scope.ts +226 -0
  147. package/server/services/socket/service.json +6 -0
  148. package/server/services_old/SocketClient.ts +92 -0
  149. package/server/services_old/Token.old.ts +97 -0
  150. package/server/utils/slug.ts +79 -0
  151. package/tsconfig.common.json +45 -0
  152. package/tsconfig.json +3 -0
  153. package/types/aliases.d.ts +54 -0
  154. package/types/global/modules.d.ts +49 -0
  155. package/types/global/utils.d.ts +103 -0
  156. package/types/icons.d.ts +1 -0
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "Core/Schema",
3
+ "name": "Schema",
4
+ "parent": "app",
5
+ "dependences": []
6
+ }
@@ -0,0 +1,85 @@
1
+ /*----------------------------------
2
+ - DEPS
3
+ ----------------------------------*/
4
+
5
+ // Nodejs
6
+ import crypto, { Encoding } from 'crypto';
7
+
8
+ // Core
9
+ import type { Application } from '@server/app';
10
+ import Service from '@server/app/service';
11
+ import { Forbidden } from '@common/errors';
12
+
13
+ /*----------------------------------
14
+ - SERVICE CONFIG
15
+ ----------------------------------*/
16
+
17
+ export type Config = {
18
+ debug?: boolean,
19
+ // Initialisation vector
20
+ // Generate one here: https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx
21
+ iv: string,
22
+ // Define usage-specific keys
23
+ // You can also generate one via the link upper
24
+ keys: {[keyName: string]: string}
25
+ }
26
+
27
+ export type Hooks = {
28
+
29
+ }
30
+
31
+ export type Services = {
32
+
33
+ }
34
+
35
+ /*----------------------------------
36
+ - TYPES
37
+ ----------------------------------*/
38
+
39
+ type TEncryptOptions = {
40
+ encoding: Encoding
41
+ }
42
+
43
+ type TDecryptOptions = {
44
+ encoding: Encoding
45
+ }
46
+
47
+ /*----------------------------------
48
+ - SERVICE
49
+ ----------------------------------*/
50
+ export default class AES<TConfig extends Config = Config> extends Service<TConfig, Hooks, Application, Application> {
51
+
52
+ public encrypt( keyName: keyof TConfig["keys"], data: any, options: TEncryptOptions = {
53
+ encoding: 'base64url'
54
+ }) {
55
+
56
+ const encKey = this.config.keys[ keyName as keyof typeof this.config.keys ];
57
+
58
+ data = JSON.stringify(data);
59
+
60
+ let cipher = crypto.createCipheriv('aes-256-cbc', encKey, this.config.iv);
61
+ let encrypted = cipher.update(data, 'utf8', options.encoding);
62
+ encrypted += cipher.final(options.encoding);
63
+ return encrypted;
64
+
65
+ }
66
+
67
+ public decrypt( keyName: keyof TConfig["keys"], data: string, options: TDecryptOptions = {
68
+ encoding: 'base64url'
69
+ }) {
70
+
71
+ const encKey = this.config.keys[ keyName as keyof typeof this.config.keys ];
72
+
73
+ try {
74
+
75
+ let decipher = crypto.createDecipheriv('aes-256-cbc', encKey, this.config.iv);
76
+ let decrypted = decipher.update(data, options.encoding, 'utf8');
77
+ return JSON.parse(decrypted + decipher.final('utf8'));
78
+
79
+ } catch (error) {
80
+
81
+ throw new Forbidden("Invalid token.");
82
+
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "Core/Encryption/AES",
3
+ "name": "AES",
4
+ "parent": "app",
5
+ "dependences": []
6
+ }
@@ -0,0 +1,162 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import { Server as WebSocketServer, ServerOptions } from 'ws';
7
+ import { v4 as uuidv4 } from 'uuid';
8
+ import { IncomingMessage } from 'http';
9
+ import cookie from 'cookie';
10
+
11
+ // Core
12
+ import type { Application } from '@server/app';
13
+ import Service, { AnyService, TRegisteredService } from '@server/app/service';
14
+ import SocketScope, { WebSocket } from './scope';
15
+ import type Router from '@server/services/router';
16
+ export type { WebSocket, default as SocketScope } from './scope';
17
+ import type UsersManagementService from '../auth';
18
+
19
+ /*----------------------------------
20
+ - TYPES
21
+ ----------------------------------*/
22
+
23
+
24
+ export type Config<TUser extends {}> = {
25
+ debug?: boolean,
26
+ //server: ServerOptions["server"],
27
+ //users: UsersManagementService<TUser>,
28
+ port: number,
29
+
30
+ users: UsersManagementService<TUser, Application>,
31
+ router: Router
32
+ }
33
+
34
+ export type Hooks = {
35
+
36
+ }
37
+
38
+ /*----------------------------------
39
+ - MANAGER
40
+ ----------------------------------*/
41
+ export default class WebSocketCommander<
42
+ TUser extends {},
43
+ TConfig extends Config<TUser>= Config<TUser>
44
+ > extends Service<TConfig, Hooks, Application> {
45
+
46
+ // Services
47
+ public ws!: WebSocketServer;
48
+ public users!: TConfig["users"];
49
+ public router!: TConfig["router"];
50
+
51
+ // Context
52
+ public scopes: {[path: string]: SocketScope<TUser>} = {}
53
+
54
+ public constructor(
55
+ parent: AnyService,
56
+ config: TConfig,
57
+ app: TApplication,
58
+ ) {
59
+ super(parent, config, app);
60
+
61
+ this.users = this.config.users;
62
+ this.router = this.config.router;
63
+
64
+ }
65
+
66
+ /*----------------------------------
67
+ - LIFECYCLE
68
+ ----------------------------------*/
69
+
70
+ public loading: Promise<void> | undefined = undefined;
71
+ protected async ready() {
72
+
73
+ this.users.on('disconnect', async (userId: string) => {
74
+ this.disconnect(userId, 'Logout');
75
+ });
76
+
77
+ console.info(`Loading socket commander`);
78
+ this.ws = new WebSocketServer({ server: this.router.http.http })
79
+ .on('connection', (socket: WebSocket, req: IncomingMessage) => {
80
+
81
+ // Resolve scope
82
+ const path = req.url;
83
+ let scope: SocketScope<TUser> | undefined;
84
+ for (const scopePath in this.scopes)
85
+ if (path === scopePath) {
86
+ scope = this.scopes[path];
87
+ break;
88
+ }
89
+
90
+ if (scope === undefined) {
91
+ console.warn("Unknown scope path:", path);
92
+ socket.close();
93
+ return;
94
+ }
95
+
96
+ socket.id = uuidv4();
97
+
98
+ // req.headers['x-forwarded-for'] = IP réelle du client quand on passe par un porxy apache
99
+ const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
100
+ if (typeof ip !== 'string') {
101
+ console.warn("Invalid IP address", ip);
102
+ socket.close();
103
+ return;
104
+ }
105
+ socket.ip = ip;
106
+
107
+ // Cookies
108
+ if (req.headers.cookie) {
109
+ req.cookies = cookie.parse(req.headers.cookie);
110
+ }
111
+
112
+ scope.newClient(socket, req);
113
+
114
+ })
115
+
116
+ console.info(`Socket commander bound to http server.`);
117
+ }
118
+
119
+ public async shutdown() {
120
+ this.closeAll();
121
+ }
122
+
123
+ /*----------------------------------
124
+ - ACTIONS
125
+ ----------------------------------*/
126
+
127
+ public open(path: string) {
128
+
129
+ if (!(path in this.scopes)) {
130
+
131
+ console.info("Registering socket scope:", path);
132
+ this.scopes[path] = new SocketScope(path, this);
133
+
134
+ }
135
+
136
+ return this.scopes[path];
137
+
138
+ }
139
+
140
+
141
+ public send(scopename: string, usernames: string | string[], command: string, data?: any) {
142
+
143
+ const scope = this.scopes[scopename];
144
+ if (scope === undefined)
145
+ return console.warn("No scope with name", scopename);
146
+
147
+ scope.send(usernames, command, data);
148
+
149
+ }
150
+
151
+ public disconnect( usernames: string | string[], reason: string, data?: any ) {
152
+ console.log(`Disconnecting ${usernames} from all scopes`);
153
+ for (const path in this.scopes)
154
+ this.scopes[path].disconnect( usernames, reason );
155
+ }
156
+
157
+ public closeAll() {
158
+ console.log("Closing All connections");
159
+ for (const path in this.scopes)
160
+ this.scopes[path].close();
161
+ }
162
+ }
@@ -0,0 +1,226 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import ws from 'ws';
7
+ import type { IncomingMessage } from 'http';
8
+
9
+ // Core
10
+ import type SocketService from '.';
11
+ import context from '@server/context';
12
+
13
+ /*----------------------------------
14
+ - TYPES
15
+ ----------------------------------*/
16
+
17
+ export type WebSocket = ws & {
18
+ ip: string,
19
+ id: string,
20
+ username: string,
21
+ activity: number | false,
22
+ disconnect: (reason: string) => void
23
+ }
24
+
25
+ type TConnectCallback = (client: WebSocket, req: IncomingMessage) => Promise<void | false>;
26
+
27
+ type TEventCallback = (data: any, socket: WebSocket) => Promise<void>
28
+
29
+ type TCommands = { [command: string]: TEventCallback }
30
+
31
+ const activityDelay = 10 * 1000; // Clearn broken connections veery 10s
32
+
33
+ /*----------------------------------
34
+ - SCOPE
35
+ ----------------------------------*/
36
+ export default class SocketScope<TUser extends {}> {
37
+
38
+ private connectEvent?: TConnectCallback;
39
+ private disconnectEvent?: TConnectCallback;
40
+ public commands: TCommands = {};
41
+ public users: { [username: string]: WebSocket[] } = {}
42
+
43
+ public constructor(
44
+ public path: string,
45
+ private socket: SocketService<TUser>,
46
+ private app = socket.app
47
+ ) {
48
+
49
+ }
50
+
51
+ private cleaner = setInterval(() => {
52
+ const now = Date.now();
53
+ for (const username in this.users) {
54
+ for (const socket of this.users[username]) {
55
+
56
+ // If the client did not sent any rsponse to the ping
57
+ if (socket.activity === false) {
58
+
59
+ // We consider it as a dead connection (discnnected, but no terminate packet was sent. Ex: internet disabled)
60
+ console.log(this.path + ':', username, socket.ip, socket.id, "is dead");
61
+ socket.terminate();
62
+
63
+ // If user has not been active since x seconds
64
+ } else if (socket.activity < now - activityDelay) {
65
+
66
+ // We consider hil a dead, until he responds to a ping
67
+ socket.activity = false;
68
+ socket.ping();
69
+
70
+ }
71
+ }
72
+ }
73
+ }, activityDelay);
74
+
75
+ public newClient(socket: WebSocket, req: IncomingMessage) {
76
+ context.run({ channelType: 'socket', channelId: this.path }, async () => {
77
+
78
+ // Auth
79
+ const username = await this.socket.config.users.decode(req);
80
+ if (!username) {
81
+ console.log(`Rejecting connection on ${this.path} for client ${socket.ip} (${socket.id})}: Not authenticated`);
82
+ socket.close(4004, "auth");
83
+ return;
84
+ }
85
+
86
+ socket.username = username;
87
+ socket.disconnect = (reason: string) => socket.close(4004, reason);
88
+
89
+ // On connect event
90
+ if (this.connectEvent && await this.connectEvent(socket, req) === false) {
91
+ return;
92
+ }
93
+
94
+ // Indexage
95
+ if (this.users[username] === undefined) {
96
+ this.users[username] = [socket];
97
+ } else {
98
+ this.users[username].push(socket);
99
+ }
100
+
101
+ console.log(`Client ${socket.username} (${socket.ip}) connected on ${this.path}. Connections number for this user: ` + this.users[username].length);
102
+ // Indique au cient que sa connexion a bien été acceptée
103
+ socket.send("ok>ok")
104
+
105
+ // Détection déconnexion
106
+ socket.activity = Date.now();
107
+ socket.on('pong', () => {
108
+ socket.activity = Date.now();
109
+ });
110
+
111
+ // Ecoute résolution des challenges
112
+ socket.on('message', (m: ws.Data) => {
113
+
114
+ const response = m.toString();
115
+ var i = response.indexOf('>');
116
+ if (i === -1) {
117
+ return console.warn(`Bad data structure:`, response.substring(0, 100) + '...');
118
+ }
119
+
120
+ const command = response.slice(0, i);
121
+ const strData = response.slice(i + 1);
122
+
123
+ let data;
124
+ try {
125
+ data = JSON.parse(strData);
126
+ } catch (error) {
127
+ console.warn(`Error decoding data`, error);
128
+ this.send(socket.username, 'log', `Invalid data format.`);
129
+ return;
130
+ }
131
+
132
+ const handler = this.commands[command];
133
+ if (handler === undefined)
134
+ return console.error('Command « ' + command + ' » does not exists.');
135
+
136
+ socket.activity = Date.now();
137
+
138
+ handler(data, socket);
139
+
140
+
141
+ });
142
+
143
+ socket.on('close', () => {
144
+
145
+ if (this.users[username].length > 1)
146
+ this.users[username] = this.users[username].filter(s => s.id !== socket.id);
147
+ else
148
+ this.users[username] = [];
149
+
150
+ console.log(`Client ${socket.ip} (${socket.id}) disconnected from ${this.path}. Connections number for this user: ` + this.users[username].length);
151
+
152
+ if (this.disconnectEvent !== undefined)
153
+ this.disconnectEvent(socket, req);
154
+
155
+ });
156
+ });
157
+ }
158
+
159
+ public isConnected(username: string) {
160
+ return this.users[username] !== undefined && this.users[username].length !== 0;
161
+ }
162
+
163
+ public send(usernames: string | string[], command: string, data: any = true) {
164
+
165
+ if (usernames === '*')
166
+ usernames = Object.keys(this.users);
167
+ else if (!Array.isArray(usernames))
168
+ usernames = [usernames];
169
+
170
+ for (const username of usernames) {
171
+
172
+ const user = this.users[username];
173
+ if (user === undefined)
174
+ return console.warn("User", username, "is not connected to", this.path);
175
+
176
+ for (const client of user) {
177
+ client.send(command + '>' + JSON.stringify(data));
178
+ }
179
+
180
+ console.log("Sent event " + command + " to " + username + " on " + this.path)
181
+
182
+ }
183
+ }
184
+
185
+ public disconnect(usernames: string | string[], reason: string, data?: any) {
186
+
187
+ if (usernames === '*')
188
+ usernames = Object.keys(this.users);
189
+ else if (!Array.isArray(usernames))
190
+ usernames = [usernames];
191
+
192
+ for (const username of usernames) {
193
+
194
+ const user = this.users[username];
195
+ if (user === undefined)
196
+ return console.warn("User", username, "is not connected to", this.path);
197
+
198
+ for (const client of user) {
199
+ client.disconnect(reason);
200
+ }
201
+
202
+ console.log("Disconnected " + username + " from " + this.path + " fo the following reason: " + reason)
203
+
204
+ }
205
+ }
206
+
207
+ public onConnect(cb: TConnectCallback) {
208
+ this.connectEvent = cb;
209
+ return this;
210
+ }
211
+
212
+ public on(event: string, cb: TEventCallback) {
213
+ this.commands[event] = cb;
214
+ return this;
215
+ }
216
+
217
+ public onDisconnect(cb: TConnectCallback) {
218
+ this.disconnectEvent = cb;
219
+ return this;
220
+ }
221
+
222
+ public close() {
223
+ clearInterval(this.cleaner);
224
+ }
225
+
226
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "Core/Socket",
3
+ "name": "Socket",
4
+ "parent": "app",
5
+ "dependences": []
6
+ }
@@ -0,0 +1,92 @@
1
+ // Source: https://github.com/binance-exchange/binance-websocket-examples/blob/master/src/lib/socketClient.js
2
+ // Exmeple utilisation: https://github.com/binance-exchange/binance-websocket-examples/blob/master/src/monitor-spot.js
3
+
4
+ import WebSocket from 'ws';
5
+
6
+ type THandler = (message: any) => void;
7
+
8
+ class SocketClient {
9
+
10
+ private url: string;
11
+
12
+ private ws!: WebSocket;
13
+ private handlers: THandler[] = [];
14
+
15
+ constructor(url: string) {
16
+ this.url = url;
17
+ }
18
+
19
+ private log = (...args: any[]) => console.log('[socket][client]['+ this.url +']', ...args);
20
+
21
+ public connecter(): Promise<this> {
22
+ return new Promise((resolve, reject) => {
23
+
24
+ this.log('Connexion');
25
+
26
+ this.ws = new WebSocket(this.url);
27
+
28
+ this.ws.onopen = () => {
29
+ this.log('Connecté.');
30
+
31
+ resolve(this);
32
+ };
33
+
34
+ this.ws.onmessage = (msg) => {
35
+ try {
36
+ const message = JSON.parse(msg.data);
37
+ for (const handler of this.handlers)
38
+ handler(message);
39
+ } catch (e) {
40
+ this.log('Parse message failed', e);
41
+ }
42
+ };
43
+
44
+ this.ws.onerror = (err) => {
45
+ this.log('Erreur', err);
46
+
47
+ reject(err);
48
+ };
49
+
50
+ this.ws.onclose = (e) => {
51
+ this.log('Fermé', e.reason);
52
+ };
53
+
54
+ this.ws.on('pong', () => {
55
+ this.log('Le serveur a envoyé pong');
56
+ });
57
+
58
+ this.ws.on('ping', () => {
59
+ if (this.ws.readyState === WebSocket.OPEN)
60
+ this.ws.pong();
61
+ });
62
+
63
+ //this.heartBeat();
64
+
65
+ })
66
+ }
67
+
68
+ /*public heartBeat() {
69
+ setInterval(() => {
70
+ if (this.ws.readyState === WebSocket.OPEN) {
71
+ this.ws.ping();
72
+ this.log("Ping serveur");
73
+ }
74
+ }, 5000);
75
+ }*/
76
+
77
+ public send(data: object) {
78
+ this.ws.send( JSON.stringify(data) );
79
+ return this;
80
+ }
81
+
82
+ public handle(handler: THandler) {
83
+ this.handlers.push(handler);
84
+ return this;
85
+ }
86
+
87
+ public close() {
88
+ this.ws.close();
89
+ }
90
+ }
91
+
92
+ export default SocketClient;
@@ -0,0 +1,97 @@
1
+
2
+
3
+ /*
4
+ NOTE: Replaced by AES
5
+ */
6
+
7
+
8
+ /*----------------------------------
9
+ - DEPS
10
+ ----------------------------------*/
11
+
12
+ // NPM
13
+ import { v4 as uuid } from 'uuid';
14
+ import hInterval from 'human-interval';
15
+
16
+ // Core
17
+ import Cron, { CronTask } from '@server/services/cron';
18
+ import { Forbidden } from '@common/errors';
19
+
20
+ const debug = true;
21
+
22
+ /*----------------------------------
23
+ - TYPES
24
+ ----------------------------------*/
25
+
26
+ type TokenOptions = {
27
+ expires?: number, // Timestamp
28
+ data?: any
29
+ };
30
+
31
+ /*----------------------------------
32
+ - SERVICE
33
+ ----------------------------------*/
34
+ class Tokens {
35
+
36
+ private tokens: {[token: string]: TokenOptions} = {};
37
+
38
+ public constructor() {
39
+ Cron.task("tokens.expiration", '*/5 * * * *', async () => {
40
+ this.cleanExpired()
41
+ })
42
+ }
43
+
44
+ private cleanExpired() {
45
+ debug && console.log("Cleaning expired tokens ...");
46
+ const now = Date.now();
47
+ for (const token in this.tokens) {
48
+ const expires = this.tokens[token].expires;
49
+ if (expires !== undefined && expires < now) {
50
+ debug && console.log("Expired: " + token);
51
+ delete this.tokens[token];
52
+ }
53
+ }
54
+ }
55
+
56
+ public create( duration?: string, data?: any ) {
57
+
58
+ const now = Date.now();
59
+ const token = uuid();
60
+ const options: TokenOptions = {
61
+ data
62
+ }
63
+
64
+ if (duration !== undefined) {
65
+
66
+ const interval = hInterval(duration);
67
+ if (!interval)
68
+ throw new Error(`Invalid interval expression: ${duration}`);
69
+
70
+ options.expires = now + interval;
71
+ }
72
+
73
+ this.tokens[ token ] = options;
74
+
75
+ return token;
76
+
77
+ }
78
+
79
+ public get<TData extends any>( token: string, critical: boolean = true ): TData | undefined {
80
+
81
+ const options = this.tokens[token];
82
+ debug && console.log("Get token", token, options);
83
+ if (options === undefined) {
84
+ if (critical)
85
+ throw new Forbidden(`Invalid token.`);
86
+ else
87
+ return undefined;
88
+ }
89
+
90
+ delete this.tokens[token];
91
+
92
+ return options.data;
93
+ }
94
+
95
+ }
96
+
97
+ export default new Tokens;