@everneed/worker 2.1.0 → 2.2.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/index.js +1 -1
- package/package.json +1 -1
- package/worker/rabbitmq.js +210 -218
package/index.js
CHANGED
|
@@ -67,7 +67,7 @@ import pseudoEnv from "./pseudoenv.js"
|
|
|
67
67
|
url: `redis://${pseudoEnv.process.env.REDIS_USERNAME}:${pseudoEnv.process.env.REDIS_PASSWORD}@${pseudoEnv.process.env.REDIS_HOST}:${pseudoEnv.process.env.REDIS_PORT}`
|
|
68
68
|
} */)
|
|
69
69
|
.on("error", err => console.log("Redis Client Error", err))
|
|
70
|
-
|
|
70
|
+
.connect()
|
|
71
71
|
}
|
|
72
72
|
/* Socketio */
|
|
73
73
|
let socketioInstance = ()=>{}
|
package/package.json
CHANGED
package/worker/rabbitmq.js
CHANGED
|
@@ -3,12 +3,13 @@ import fs from "fs"
|
|
|
3
3
|
import crypto from "crypto"
|
|
4
4
|
import amqp from "amqplib/callback_api.js"
|
|
5
5
|
import moment from "moment"
|
|
6
|
+
import EventEmitter from "events"
|
|
6
7
|
|
|
7
8
|
import pseudoEnv from "@everneed/worker/pseudoenv.js"
|
|
8
9
|
import { createHmac } from "crypto"
|
|
9
10
|
import { redis } from "@everneed/worker"
|
|
10
11
|
import { ResponseCode } from "@everneed/responsecode"
|
|
11
|
-
import { pipe, switchPourStr, randomStr } from "@everneed/helper"
|
|
12
|
+
import { pipe, switchPourStr, randomStr, extractUserInfo } from "@everneed/helper"
|
|
12
13
|
|
|
13
14
|
class VersionManager{
|
|
14
15
|
#currentVer
|
|
@@ -181,9 +182,28 @@ class VersionManager{
|
|
|
181
182
|
}
|
|
182
183
|
const version = new VersionManager()
|
|
183
184
|
version.init()
|
|
185
|
+
const bus = new EventEmitter()
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
class RabbitMQ{
|
|
188
|
+
connection = null
|
|
189
|
+
channel = null
|
|
190
|
+
|
|
191
|
+
async init(){
|
|
192
|
+
await new Promise((resolve, reject)=>{
|
|
193
|
+
amqp.connect(pseudoEnv.process.env.RABBIT_HOST, (error0, connection)=>{
|
|
194
|
+
if(error0){ throw error0 }
|
|
195
|
+
this.connection = connection
|
|
196
|
+
|
|
197
|
+
this.connection.createChannel((error1, channel)=>{
|
|
198
|
+
if (error1){ throw error1 }
|
|
199
|
+
this.channel = channel
|
|
200
|
+
|
|
201
|
+
resolve("continue")
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
config(object){
|
|
187
207
|
// config({
|
|
188
208
|
// ENV: value,
|
|
189
209
|
// ...
|
|
@@ -205,105 +225,105 @@ export default {
|
|
|
205
225
|
}
|
|
206
226
|
/* Env Add Process */
|
|
207
227
|
pseudoEnv.config(object)
|
|
208
|
-
}
|
|
209
|
-
start
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
/* Generate consumer */
|
|
232
|
-
channel.assertQueue(`req/${pseudoEnv.process.env.SVC_NAME}/${moduleSpace}/${endpoint}`, {
|
|
233
|
-
durable: true
|
|
228
|
+
}
|
|
229
|
+
async start(){
|
|
230
|
+
const rabbitmqGateway = fs.readdirSync(path.join(process.cwd(), "/src/mq-gateway/"))
|
|
231
|
+
/* Generate consumer */
|
|
232
|
+
// iterating every files in /src/mq-gateway
|
|
233
|
+
// and its function to be built as rabbitmq
|
|
234
|
+
// subscriber (consumer)
|
|
235
|
+
for(const file of rabbitmqGateway){
|
|
236
|
+
const moduleSpace = file.slice(0, -3)
|
|
237
|
+
const main = await import(`file://${path.join(process.cwd(), `/src/mq-gateway/${moduleSpace}`)}.js`)
|
|
238
|
+
// const main = await import(`#@/mq-gateway/${moduleSpace}.js`)
|
|
239
|
+
|
|
240
|
+
for(const endpoint in main.default){
|
|
241
|
+
/* Generate consumer */
|
|
242
|
+
this.channel.assertQueue(`req/${pseudoEnv.process.env.SVC_NAME}/${moduleSpace}/${endpoint}`, {
|
|
243
|
+
durable: false
|
|
244
|
+
})
|
|
245
|
+
this.channel.consume(`req/${pseudoEnv.process.env.SVC_NAME}/${moduleSpace}/${endpoint}`, async (message)=>{
|
|
246
|
+
const mqHeader = message.properties.headers
|
|
247
|
+
const mqReq = await this.#decryptMessage({
|
|
248
|
+
message: message.content.toString(),
|
|
249
|
+
...(mqHeader.auth && { token: mqHeader.auth.token }),
|
|
250
|
+
...(mqHeader.auth && { userAgent: mqHeader.auth.userAgent })
|
|
234
251
|
})
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
...(mqHeader.auth && { token: mqHeader.auth.token }),
|
|
240
|
-
...(mqHeader.auth && { userAgent: mqHeader.auth.userAgent })
|
|
252
|
+
const trueVersion = mqHeader.version ?
|
|
253
|
+
version.trueVersion({
|
|
254
|
+
endpoint: `/${pseudoEnv.process.env.SVC_NAME}/${moduleSpace}/${endpoint}`,
|
|
255
|
+
version: mqHeader.version
|
|
241
256
|
})
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
message: null
|
|
252
|
-
}
|
|
257
|
+
:
|
|
258
|
+
version.latestVersion()
|
|
259
|
+
const prep = {
|
|
260
|
+
message: null
|
|
261
|
+
}
|
|
262
|
+
let timeoutCounter = false
|
|
263
|
+
|
|
264
|
+
// Start Timeout Timer
|
|
265
|
+
const timeout = setTimeout(()=>{ timeoutCounter = true }, main.default[endpoint].timeout || 10000)
|
|
253
266
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
267
|
+
try{
|
|
268
|
+
/* Active Endpoint Filter */
|
|
269
|
+
if(!main.default[endpoint].active) throw "invalid_endpoint"
|
|
270
|
+
/* API enforce Auth */
|
|
271
|
+
if(main.default[endpoint].authentication){
|
|
272
|
+
if(!mqHeader.auth) throw "not_authenticated"
|
|
273
|
+
}
|
|
274
|
+
/* Main Process */
|
|
275
|
+
const result = await main.default[endpoint].function[`v${trueVersion}`](mqHeader.auth || false, mqReq.payload)
|
|
276
|
+
prep["message"] = await this.#encryptMessage({
|
|
277
|
+
message: result,
|
|
278
|
+
...(mqHeader.auth && { token: mqHeader.auth.token }),
|
|
279
|
+
...(mqHeader.auth && { userAgent: mqHeader.auth.userAgent })
|
|
280
|
+
})
|
|
281
|
+
/* Resolve */
|
|
282
|
+
if(timeoutCounter) throw "timeout"
|
|
283
|
+
else throw "finish"
|
|
284
|
+
}
|
|
285
|
+
catch(something){
|
|
286
|
+
/* Imbue response code according to throw */
|
|
287
|
+
if(something == "finish") clearTimeout(timeout)
|
|
288
|
+
if(something != "finish" && mqReq.trip == "returning"){
|
|
289
|
+
const response = new ResponseCode()
|
|
290
|
+
switch(something){
|
|
291
|
+
case "invalid_endpoint": response.pushCode("INVALID_ENDPOINT")
|
|
292
|
+
break;
|
|
293
|
+
case "not_authenticated": response.pushCode("NOT_AUTHENTICATED")
|
|
294
|
+
break;
|
|
295
|
+
case "timeout": response.pushCode("HTTP_TIMEOUT")
|
|
296
|
+
break;
|
|
297
|
+
default: response.pushCode("MQ_ERROR")
|
|
298
|
+
break;
|
|
274
299
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
message: result,
|
|
300
|
+
|
|
301
|
+
prep["message"] = await this.#encryptMessage({
|
|
302
|
+
message: response.result,
|
|
279
303
|
...(mqHeader.auth && { token: mqHeader.auth.token }),
|
|
280
304
|
...(mqHeader.auth && { userAgent: mqHeader.auth.userAgent })
|
|
281
305
|
})
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
channel.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
})
|
|
300
|
-
}
|
|
306
|
+
}
|
|
307
|
+
/* Returning Trip */
|
|
308
|
+
if(mqReq.trip == "returning"){
|
|
309
|
+
this.channel.sendToQueue(message.properties.replyTo, Buffer.from(prep.message), {
|
|
310
|
+
headers:{
|
|
311
|
+
...(mqHeader.version && { version: mqHeader.version }),
|
|
312
|
+
...(mqHeader.auth && { auth: mqHeader.auth })
|
|
313
|
+
}
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
/* Ack Compose */
|
|
317
|
+
if(something == "finish") this.channel.ack(message)
|
|
318
|
+
else this.channel.nack(message, false, false)
|
|
319
|
+
}
|
|
320
|
+
},{
|
|
321
|
+
noAck: false
|
|
322
|
+
},(error, ok)=>{ if(error) throw error })
|
|
301
323
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
},
|
|
306
|
-
publish: function({topic, version, auth=null, trip="passby", data}){
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
publish({topic, version, auth=null, trip="passby", data}){
|
|
307
327
|
/* Usage */
|
|
308
328
|
// publish({
|
|
309
329
|
// topic: <topic start at svc :String>,
|
|
@@ -321,117 +341,103 @@ export default {
|
|
|
321
341
|
|
|
322
342
|
const response = new ResponseCode()
|
|
323
343
|
return new Promise(async (resolve, reject)=>{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
/* Build payload structure */
|
|
336
|
-
// like topic, address, etc.
|
|
337
|
-
const userName = auth ? this.getUserInfo({tokenBody: auth.token.split(".")[0]}).userName : `guest${randomStr({length: 12})}`
|
|
338
|
-
const prep = {
|
|
339
|
-
topic: `req/${topic}`,
|
|
340
|
-
message:{
|
|
341
|
-
trip: trip,
|
|
342
|
-
senderAddress: `${createHmac("sha256", userName).digest("hex").slice(0, 12)}${moment().utc().format("HHmmssSSS")}`,
|
|
343
|
-
payload: data
|
|
344
|
-
}
|
|
344
|
+
try{
|
|
345
|
+
/* Build payload structure */
|
|
346
|
+
// like topic, address, etc.
|
|
347
|
+
const userName = auth ? extractUserInfo({token: auth.token}).userName : `guest${randomStr({length: 12})}`
|
|
348
|
+
const prep = {
|
|
349
|
+
topic: `req/${topic}`,
|
|
350
|
+
message:{
|
|
351
|
+
trip: trip,
|
|
352
|
+
payload: data
|
|
345
353
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
}
|
|
355
|
+
let senderAddress
|
|
356
|
+
/* Validate Auth */
|
|
357
|
+
if(auth){
|
|
358
|
+
const validate = await this.publish({
|
|
359
|
+
topic: "authenthor/session/svVerifyToken",
|
|
360
|
+
trip: "returning",
|
|
361
|
+
data:{
|
|
362
|
+
token: auth.token,
|
|
363
|
+
userAgent: auth.userAgent,
|
|
364
|
+
noRefresh: true
|
|
365
|
+
}
|
|
366
|
+
})
|
|
357
367
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
368
|
+
if(validate.checkError()){
|
|
369
|
+
response.createNew(validate.result)
|
|
370
|
+
throw "abort"
|
|
361
371
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
/* Resolvation According to Trip */
|
|
380
|
-
if(trip == "returning"){
|
|
381
|
-
/* Creates consumer for returning messages */
|
|
382
|
-
channel.assertQueue(`res/${topic}`, { durable: true })
|
|
383
|
-
channel.consume(`res/${topic}`, async (message)=>{
|
|
384
|
-
const mqRes = await this.decryptMessage({
|
|
385
|
-
message: message.content.toString(),
|
|
386
|
-
...(auth && { token: auth.token }),
|
|
387
|
-
...(auth && { userAgent: auth.userAgent })
|
|
388
|
-
})
|
|
389
|
-
|
|
390
|
-
if(message.properties.correlationId == prep.message.senderAddress){
|
|
391
|
-
response.createNew(mqRes)
|
|
392
|
-
channel.ack(message)
|
|
393
|
-
setTimeout(()=>{
|
|
394
|
-
connection.close()
|
|
395
|
-
}, 500)
|
|
396
|
-
|
|
397
|
-
resolve(response)
|
|
398
|
-
}
|
|
399
|
-
}, {
|
|
400
|
-
noAck: false
|
|
372
|
+
}
|
|
373
|
+
/* Prepare Listener */
|
|
374
|
+
if(trip == "returning"){
|
|
375
|
+
/* Creates consumer for returning messages */
|
|
376
|
+
senderAddress = await new Promise((resolva, rejecta)=>{
|
|
377
|
+
this.channel.assertQueue("", { exclusive: true, autoDelete: true }, (error, ok)=>{
|
|
378
|
+
resolva(ok.queue)
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
/* Returning Message's Sub-Consumer */
|
|
382
|
+
this.channel.consume(senderAddress, async (message)=>{
|
|
383
|
+
const mqRes = await this.#decryptMessage({
|
|
384
|
+
message: message.content.toString(),
|
|
385
|
+
...(auth && { token: auth.token }),
|
|
386
|
+
...(auth && { userAgent: auth.userAgent })
|
|
401
387
|
})
|
|
402
|
-
}
|
|
403
|
-
else if(trip == "passby"){
|
|
404
|
-
response.pushCode("GENERAL_OK")
|
|
405
|
-
|
|
406
|
-
setTimeout(()=>{
|
|
407
|
-
connection.close()
|
|
408
|
-
}, 500)
|
|
409
388
|
|
|
389
|
+
this.channel.ack(message)
|
|
390
|
+
response.createNew(mqRes)
|
|
391
|
+
this.channel.cancel(senderAddress)
|
|
410
392
|
resolve(response)
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
393
|
+
}, {
|
|
394
|
+
noAck: false,
|
|
395
|
+
consumerTag: senderAddress
|
|
396
|
+
},(error, ok)=>{ if(error) throw error })
|
|
397
|
+
}
|
|
398
|
+
/* Main publisher */
|
|
399
|
+
const mqReq = await this.#encryptMessage({
|
|
400
|
+
message: prep.message,
|
|
401
|
+
...(auth && { token: auth.token }),
|
|
402
|
+
...(auth && { userAgent: auth.userAgent })
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
this.channel.assertQueue(prep.topic, {
|
|
406
|
+
durable: false
|
|
407
|
+
})
|
|
408
|
+
this.channel.sendToQueue(prep.topic, Buffer.from(mqReq), {
|
|
409
|
+
headers:{
|
|
410
|
+
...(version && { version: version }),
|
|
411
|
+
...(auth && { auth: auth })
|
|
412
|
+
},
|
|
413
|
+
...(trip == "returning" && { replyTo: senderAddress })
|
|
414
|
+
})
|
|
415
|
+
/* Non-returning Trip Resolvation */
|
|
416
|
+
if(trip == "passby"){
|
|
417
|
+
response.pushCode("GENERAL_OK")
|
|
418
|
+
|
|
419
|
+
resolve(response)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch(something){
|
|
423
|
+
response.createNew(response.result)
|
|
424
|
+
if(something != "abort"){
|
|
425
|
+
// err: other error
|
|
426
|
+
response.pushCode("LOGIC_ERROR")
|
|
427
|
+
response.pushTrace({code: "LOGIC_ERROR", trace: `Unexpected error on queue publisher`})
|
|
422
428
|
}
|
|
423
|
-
|
|
424
|
-
|
|
429
|
+
|
|
430
|
+
resolve(response)
|
|
431
|
+
}
|
|
425
432
|
})
|
|
426
|
-
}
|
|
427
|
-
encryptMessage
|
|
433
|
+
}
|
|
434
|
+
#encryptMessage({message, token=null, userAgent=null}){
|
|
428
435
|
return new Promise(async (resolve, reject)=>{
|
|
429
436
|
/* Active Auth Session */
|
|
430
437
|
if(token && userAgent){
|
|
431
|
-
const { userId } =
|
|
438
|
+
const { userId } = extractUserInfo({ token: token })
|
|
432
439
|
const uaHash = crypto.hash("sha256", switchPourStr(userAgent, pseudoEnv.process.env.TOKEN_UA_SALT))
|
|
433
|
-
await redis.
|
|
434
|
-
const authKey = await redis.get(`auth:session:long:${userId}:${uaHash}`)
|
|
440
|
+
const authKey = await redis.get(`auth:session:long:${userId}:${uaHash}`)
|
|
435
441
|
const hash = crypto.hash("sha256", switchPourStr(authKey || "kontol", pseudoEnv.process.env.RABBIT_MESSAGE_SALT))
|
|
436
442
|
const key = hash.substring(0, 16)
|
|
437
443
|
const iv = hash.substring(48)
|
|
@@ -449,15 +455,14 @@ export default {
|
|
|
449
455
|
return resolve(encrypted)
|
|
450
456
|
}
|
|
451
457
|
})
|
|
452
|
-
}
|
|
453
|
-
decryptMessage
|
|
458
|
+
}
|
|
459
|
+
#decryptMessage({message, token=null, userAgent=null}){
|
|
454
460
|
return new Promise(async (resolve, reject)=>{
|
|
455
461
|
/* Active Auth Session */
|
|
456
462
|
if(token && userAgent){
|
|
457
|
-
const { userId } =
|
|
463
|
+
const { userId } = extractUserInfo({ token: token })
|
|
458
464
|
const uaHash = crypto.hash("sha256", switchPourStr(userAgent, pseudoEnv.process.env.TOKEN_UA_SALT))
|
|
459
|
-
await redis.
|
|
460
|
-
const authKey = await redis.get(`auth:session:long:${userId}:${uaHash}`)
|
|
465
|
+
const authKey = await redis.get(`auth:session:long:${userId}:${uaHash}`)
|
|
461
466
|
const hash = crypto.hash("sha256", switchPourStr(authKey || "kontol", pseudoEnv.process.env.RABBIT_MESSAGE_SALT))
|
|
462
467
|
const key = hash.substring(0, 16)
|
|
463
468
|
const iv = hash.substring(48)
|
|
@@ -475,25 +480,12 @@ export default {
|
|
|
475
480
|
return resolve(JSON.parse(decrypted))
|
|
476
481
|
}
|
|
477
482
|
})
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return pipe(tokenBody)
|
|
481
|
-
.then(aes=>{
|
|
482
|
-
const decipher = crypto.createDecipheriv("aes-128-cbc", Buffer.from(pseudoEnv.process.env.TOKEN_KEY), Buffer.from(pseudoEnv.process.env.TOKEN_IV))
|
|
483
|
-
let decrypted = decipher.update(aes, "base64", "utf-8")
|
|
484
|
-
return decrypted += decipher.final("utf-8")
|
|
485
|
-
})
|
|
486
|
-
.then(json=> JSON.parse(json))
|
|
487
|
-
.then(circular=> circular.user)
|
|
488
|
-
.result // { userId, userName, displayName }
|
|
489
|
-
},
|
|
490
|
-
update: function(){
|
|
483
|
+
}
|
|
484
|
+
update(){
|
|
491
485
|
version.update()
|
|
492
|
-
},
|
|
493
|
-
apiVer: function(){
|
|
494
|
-
return version.deprecatedVersion()+1
|
|
495
|
-
},
|
|
496
|
-
latestVer: function(){
|
|
497
|
-
return version.latestVersion()
|
|
498
486
|
}
|
|
499
|
-
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const instance = new RabbitMQ()
|
|
490
|
+
await instance.init()
|
|
491
|
+
export default instance
|