diff --git a/packages/constants/README.md b/packages/constants/README.md index 40f9fea8ef7d352c886a0c913067d1aab43da431..690c776a0b718d0bea15bfa107629a5b282c9859 100755 --- a/packages/constants/README.md +++ b/packages/constants/README.md @@ -172,6 +172,7 @@ Please consult the detail break down below. - CONNECTED_PROP_KEY - CACHE_STORE_PROP_KEY - EVENT_EMITTER_PROP_KEY +- SUSPEND_EVENT_PROP_KEY ### SOCKET diff --git a/packages/constants/browser.js b/packages/constants/browser.js index ccd312a9fe503bedca818ca0998e35174f6bbe1d..2891dfe2f0c76a5883ca0dd24c8d8e73c24d36e4 100644 --- a/packages/constants/browser.js +++ b/packages/constants/browser.js @@ -173,6 +173,7 @@ var jsonqlConstants = { "CONNECTED_PROP_KEY": "connected", "CACHE_STORE_PROP_KEY": "cacheStore", "EVENT_EMITTER_PROP_KEY": "eventEmitter", + "SUSPEND_EVENT_PROP_KEY": "suspendOnStart", "SOCKET_PING_EVENT_NAME": "__ping__", "SWITCH_USER_EVENT_NAME": "__switch__", "LOGIN_EVENT_NAME": "__login__", diff --git a/packages/constants/constants.json b/packages/constants/constants.json index 8136611fd8ae151a01c868cb4c61fff6cd379573..cdb9aa672ab839932b099b35c9b7aa8e7194afd9 100644 --- a/packages/constants/constants.json +++ b/packages/constants/constants.json @@ -173,6 +173,7 @@ "CONNECTED_PROP_KEY": "connected", "CACHE_STORE_PROP_KEY": "cacheStore", "EVENT_EMITTER_PROP_KEY": "eventEmitter", + "SUSPEND_EVENT_PROP_KEY": "suspendOnStart", "SOCKET_PING_EVENT_NAME": "__ping__", "SWITCH_USER_EVENT_NAME": "__switch__", "LOGIN_EVENT_NAME": "__login__", diff --git a/packages/constants/index.js b/packages/constants/index.js index 5a40f8457f1bc68431f3b339b04473c89469411d..5b24c6c514fbfe2d12a6c0ebb517710da3521c97 100644 --- a/packages/constants/index.js +++ b/packages/constants/index.js @@ -248,7 +248,9 @@ export const CONNECTED_PROP_KEY = 'connected' // share naming to id the cache store object export const CACHE_STORE_PROP_KEY = 'cacheStore' -export const EVENT_EMITTER_PROP_KEY = 'eventEmitter' /* socket.js */ +export const EVENT_EMITTER_PROP_KEY = 'eventEmitter' +// track this key if we want to suspend event on start +export const SUSPEND_EVENT_PROP_KEY = 'suspendOnStart' /* socket.js */ // the constants file is gettig too large // we need to split up and group the related constant in one file diff --git a/packages/constants/main.js b/packages/constants/main.js index dfa27981d598ca392361e87a1b4f13ff19a8c66d..285b0f5b709fd6bddd67ee368e5b8dab7a3f3fd2 100644 --- a/packages/constants/main.js +++ b/packages/constants/main.js @@ -173,6 +173,7 @@ module.exports = { "CONNECTED_PROP_KEY": "connected", "CACHE_STORE_PROP_KEY": "cacheStore", "EVENT_EMITTER_PROP_KEY": "eventEmitter", + "SUSPEND_EVENT_PROP_KEY": "suspendOnStart", "SOCKET_PING_EVENT_NAME": "__ping__", "SWITCH_USER_EVENT_NAME": "__switch__", "LOGIN_EVENT_NAME": "__login__", diff --git a/packages/constants/package.json b/packages/constants/package.json index 073e0f8875abece09c3f8481dc83c8519d61e625..ff1f011e7e8d60a015e4f6ad65b0ea4ce73cd70d 100755 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-constants", - "version": "2.0.13", + "version": "2.0.14", "description": "All the share constants for jsonql modules", "main": "main.js", "module": "index.js", diff --git a/packages/constants/prop.js b/packages/constants/prop.js index 0744a21fb52514412ef19daa0afd094c857a798c..161c57214b953a90359eb4868fbefb5c1c39c4c2 100644 --- a/packages/constants/prop.js +++ b/packages/constants/prop.js @@ -103,4 +103,6 @@ export const CONNECTED_PROP_KEY = 'connected' // share naming to id the cache store object export const CACHE_STORE_PROP_KEY = 'cacheStore' -export const EVENT_EMITTER_PROP_KEY = 'eventEmitter' \ No newline at end of file +export const EVENT_EMITTER_PROP_KEY = 'eventEmitter' +// track this key if we want to suspend event on start +export const SUSPEND_EVENT_PROP_KEY = 'suspendOnStart' \ No newline at end of file diff --git a/packages/ws-client-core/package.json b/packages/ws-client-core/package.json index ade2b2de381d0f04c747bd2914a6c6ee1f0bffa3..7cb488d0f55802ba977cb21e5bb0f64a6d162e6f 100644 --- a/packages/ws-client-core/package.json +++ b/packages/ws-client-core/package.json @@ -56,18 +56,18 @@ }, "dependencies": { "@to1source/event": "^1.1.1", - "jsonql-constants": "^2.0.9", + "jsonql-constants": "^2.0.13", "jsonql-errors": "^1.2.1", - "jsonql-params-validator": "^1.6.1", - "jsonql-utils": "^1.2.4" + "jsonql-params-validator": "^1.6.2", + "jsonql-utils": "^1.2.6" }, "devDependencies": { - "ava": "^3.5.0", + "ava": "^3.5.1", "esm": "^3.2.25", "fs-extra": "^9.0.0", "jsonql-contract": "^1.9.1", - "jsonql-jwt": "^1.3.10", - "jsonql-ws-server": "^1.7.8", + "jsonql-jwt": "^1.4.0", + "jsonql-ws-server": "^1.7.9", "kefir": "^3.8.6", "ws": "^7.2.3" }, diff --git a/packages/ws-client-core/src/callers/setup-resolver.js b/packages/ws-client-core/src/callers/setup-resolver.js index b7cdbdc4faf573caa983731857494ca8feb6935c..0f9a71840fd32ff01921f8e50254cc451cc311b4 100644 --- a/packages/ws-client-core/src/callers/setup-resolver.js +++ b/packages/ws-client-core/src/callers/setup-resolver.js @@ -34,8 +34,6 @@ function createResolver(ee, namespace, resolverName, params, log) { } } - - /** * The first one in the chain, just setup a namespace prop * the rest are passing through diff --git a/packages/ws-client-core/src/listener/event-listeners.js b/packages/ws-client-core/src/listener/event-listeners.js index 48db501328e2f1cca9fe17b90fdae52ccfbea369..f5f548a8891733d568c28cf4d5d63a8c4d86b91b 100644 --- a/packages/ws-client-core/src/listener/event-listeners.js +++ b/packages/ws-client-core/src/listener/event-listeners.js @@ -24,6 +24,10 @@ export const notConnectedListener = (namespace, ee, opts) => { createEvt(namespace, EMIT_EVT), function disconnectedEvtCallback(resolverName, args) { log(`[disconnectedListerner] hijack the ws call`, namespace, resolverName, args) + // Now we suspend all the calls but note the existing one won't be affected + // we need to update the methods to move everything across + + const error = { message: DISCONNECTED_ERROR_MSG } @@ -118,4 +122,13 @@ export const logoutEvtListener = (nsps, namespaces, ee, opts) => { notLoginWsListerner(privateNamespace, ee, opts) } ) +} + +/** + * connect event listener this will not be a standalone one, instead + * will combine with the client one, because this is to release the + * $suspend + */ +export const releaseEvtOnConnection = (nsps, namespaces, ee, opts) => { + // @TODO } \ No newline at end of file diff --git a/packages/ws-client-core/src/options/defaults.js b/packages/ws-client-core/src/options/defaults.js index a29877c1ff0152924b2ed5028407396eb01a7b4d..8ca65838a861131be69cddcfdc0007242eecb80a 100644 --- a/packages/ws-client-core/src/options/defaults.js +++ b/packages/ws-client-core/src/options/defaults.js @@ -70,7 +70,9 @@ const configCheckMap = { // we will use this for determine the socket.io client type as well - @TODO remove or rename useJwt: createConfig(true, [BOOLEAN_TYPE, STRING_TYPE]), // this is going to replace the use of useJwt === string next - authStrKey: createConfig(null, [STRING_TYPE]) + authStrKey: createConfig(null, [STRING_TYPE]), + // this is experimental to see the effects, might take downlater + suspendOnStart: createConfig(false, [BOOLEAN_TYPE]) } // socket client diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index 007c51b578cd29c066d98cdbf07d15521c901d29..a5c0c568d50bac68b73be2f49bf369d9d2b796e4 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -70,7 +70,7 @@ function postCheckInjectOpts(opts) { opts.log = getLogFn(opts) opts.eventEmitter = getEventEmitter(opts) - + return opts }) } @@ -95,8 +95,16 @@ function createRequiredParams(opts) { log(`namespaces`, namespaces) // next we loop the namespace and suspend all the events prefix with namespace - // ee.$suspendEvent - namespaces.forEach(namespace => ee.$suspendEvent(namespace)) + if (opts.suspendOnStart === true) { + // we create this as a function then we can call it again + opts.$suspendNamepsace = () => namespaces.forEach(namespace => ee.$suspendEvent(namespace)) + // then we create a new method to releas the queue + // we prefix it with the $ to notify this is not a jsonql part methods + opts.$releaseNamespace = () => ee.$release() + + // now run it + opts.$suspendNamepsace() + } return { opts, nspMap, ee } } diff --git a/packages/ws-client-core/tests/fixtures/server-setup.js b/packages/ws-client-core/tests/fixtures/server-setup.js index 0f27ea07c386b2da3dc7904d70d103eab3153711..0a432a9ea903320bf4bb4e03d1756ad8219a537e 100644 --- a/packages/ws-client-core/tests/fixtures/server-setup.js +++ b/packages/ws-client-core/tests/fixtures/server-setup.js @@ -3,11 +3,14 @@ const http = require('http') const { join } = require('path') // const debug = require('debug')('jsonql-ws-client:fixtures:server') // const { JSONQL_PATH } = require('jsonql-constants') +// const colors = require('colors/safe') +// const logger = (str, ...args) => Reflect.apply(debug, null, [colors.white.bgMagenta(str), ...args]) const resolverDir = join(__dirname, 'resolvers') -// require('../../../ws-server') const { jsonqlWsServer } = require('jsonql-ws-server') +// require('../../../ws-server') +// // start const server = http.createServer(function(req, res) { diff --git a/packages/ws-server-core/package.json b/packages/ws-server-core/package.json index 59cebd284cc54c4f054d2f2bddd556020c417a6f..4bab441f5253cbd8dc7349ffe4c80112336e2bfc 100644 --- a/packages/ws-server-core/package.json +++ b/packages/ws-server-core/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-server-core", - "version": "0.8.1", + "version": "0.8.2", "description": "This is the core module that drive the Jsonql WS Socket server, not for direct use.", "main": "index.js", "files": [ @@ -37,7 +37,7 @@ "jsonql-errors": "^1.2.1", "jsonql-params-validator": "^1.6.2", "jsonql-resolver": "^1.2.2", - "jsonql-utils": "^1.2.5", + "jsonql-utils": "^1.2.6", "lodash": "^4.17.15" }, "devDependencies": { diff --git a/packages/ws-server-core/src/handles/handle-nsp-resolvers.js b/packages/ws-server-core/src/handles/handle-nsp-resolvers.js index ca7e3fdd30125c26a6212d42ea5cff9ac2e8944e..d8b22103b338ac2080b05c4ae6e76e0246a34cba 100644 --- a/packages/ws-server-core/src/handles/handle-nsp-resolvers.js +++ b/packages/ws-server-core/src/handles/handle-nsp-resolvers.js @@ -25,11 +25,13 @@ let nspHandlerFn */ function handleNspResolvers(deliverFn, ws, opts) { // check the cache method first + /* + @BUG when we use this cache method, the reply broken halfway if (typeof nspHandlerFn === 'function') { debug('return the cached nspHandlerFn') return nspHandlerFn } - + */ /** * The actual method to action on the execution of the resolver * @param {string} namespace connected namespace @@ -39,7 +41,7 @@ function handleNspResolvers(deliverFn, ws, opts) { * @param {object} userdata userdata * @return {promise} resolve the result */ - nspHandlerFn = (namespace, resolverName, args, params, userdata) => ( + return (namespace, resolverName, args, params, userdata) => ( validateInput(args, params) .then(_args => resolveSocketMethod( namespace, @@ -62,8 +64,6 @@ function handleNspResolvers(deliverFn, ws, opts) { handleError(deliverFn, resolverName, err) }) ) - - return nspHandlerFn } module.exports = { handleNspResolvers } diff --git a/packages/ws-server-core/src/handles/setup-event-handler.js b/packages/ws-server-core/src/handles/setup-event-handler.js new file mode 100644 index 0000000000000000000000000000000000000000..1db1c628f7e71bace6f1f058a92f6952c4e3445a --- /dev/null +++ b/packages/ws-server-core/src/handles/setup-event-handler.js @@ -0,0 +1,8 @@ +// this is the inter communication event setup + + +function setupEventHandler() { + +} + +module.exports = { setupEventHandler } \ No newline at end of file diff --git a/packages/ws-server-core/src/resolver/resolve-socket-method.js b/packages/ws-server-core/src/resolver/resolve-socket-method.js index 9bd92b04a49ddd03d6028908c4256c39612bd17a..cff9cd85edcfc9071acb4a2b88b9bc64a99d207c 100644 --- a/packages/ws-server-core/src/resolver/resolve-socket-method.js +++ b/packages/ws-server-core/src/resolver/resolve-socket-method.js @@ -29,6 +29,7 @@ const resolveSocketMethod = function( // resolverName, opts, key = null, store = null const key = [namespace, resolverName].join('-') const store = opts[CACHE_STORE_PROP_KEY] + const actionFn = getCompleteSocketResolver(resolverName, opts, key, store) const injectorFns = getInjectors() diff --git a/packages/ws-server-core/src/share/helpers.js b/packages/ws-server-core/src/share/helpers.js index de61d50c52d68f16d900b0056cb7be3d5a5420af..5d38d638e20e2e38a4148ed4ec58ce8f702bd2c5 100644 --- a/packages/ws-server-core/src/share/helpers.js +++ b/packages/ws-server-core/src/share/helpers.js @@ -14,11 +14,12 @@ const { chainFns, objDefineProps, objHasProp, + createWsReply, // port over to the jsonql-utils getResolverFromPayload, extractWsPayload } = require('jsonql-utils') -const { createWsReply } = require('../../../utils/src/socket') +// const { } = require('../../../utils/src/socket') // create debug diff --git a/packages/ws-server-core/tests/object.test.js b/packages/ws-server-core/tests/object.test.js index 5b06df236beaa365f3b433ed0f92c1657082be0f..f71ce5852f14347b9c590dd8b840dd5227b1bc4e 100644 --- a/packages/ws-server-core/tests/object.test.js +++ b/packages/ws-server-core/tests/object.test.js @@ -32,3 +32,17 @@ test(`Different way to extract data from payload`, t => { t.is(resolverName, name) }) + + +test(`Testing the chain object style interface`, t => { + function MyNumber(n) { + function x () { } + x.one = function() { n++; return this; }; + x.valueOf = function() { return n; }; + return x; + } + + const result = MyNumber(5).one().one().valueOf() + + t.is(7, result) +}) \ No newline at end of file diff --git a/packages/ws-server/package.json b/packages/ws-server/package.json index 316347582c3380c7a6ec839557d41e69d5082b01..fa5d0b065aa0b031a316ab75a0ceefc3b1fa0133 100755 --- a/packages/ws-server/package.json +++ b/packages/ws-server/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-ws-server", - "version": "1.7.8", + "version": "1.7.9", "description": "Setup WebSocket server for the jsonql to run on the same host, automatic generate public / private channel using contract", "main": "index.js", "files": [ @@ -33,9 +33,9 @@ "dependencies": { "colors": "^1.4.0", "debug": "^4.1.1", - "jsonql-constants": "^2.0.10", - "jsonql-utils": "^1.2.4", - "jsonql-ws-server-core": "^0.8.0", + "jsonql-constants": "^2.0.13", + "jsonql-utils": "^1.2.6", + "jsonql-ws-server-core": "^0.8.2", "ws": "^7.2.3" }, "devDependencies": { diff --git a/packages/ws-server/src/core/security/create-verify-client.js b/packages/ws-server/src/core/security/create-verify-client.js index 74a4c58775b5e64c96c0cc54d51c7367f2fb01e1..b7e7fa54ad0a8efe95f728ecf73074670ba36419 100644 --- a/packages/ws-server/src/core/security/create-verify-client.js +++ b/packages/ws-server/src/core/security/create-verify-client.js @@ -111,14 +111,13 @@ function createVerifyClient(namespace, opts, jwtOptions = {}, cb = localCb) { } // @TODO here we need to take the interceptor.validate method that created by // develop to run their own checks - - + // auth features const uri = req.url const token = getTokenFromQuery(uri) if (token) { - debug(`Got a token`, token) + debug(`Got a token`) try { const payload = jwtDecode(token, publicKey, jwtOptions) @@ -129,6 +128,7 @@ function createVerifyClient(namespace, opts, jwtOptions = {}, cb = localCb) { } // passing this along to the next info.req[SOCKET_STATE_KEY].userdata = payload + return done(payload) } catch(e) { cb({e, token, uri}) diff --git a/packages/ws-server/src/modules.js b/packages/ws-server/src/modules.js index 7bb40ce31b7ddd03c72fa24f5fdc16fec79c867f..23715832311cd0516a60faa93a8f80e654bbf5e5 100644 --- a/packages/ws-server/src/modules.js +++ b/packages/ws-server/src/modules.js @@ -19,8 +19,8 @@ const { SOCKET_STATE_KEY, getSocketHandler -} = require('../../ws-server-core') -// require('jsonql-ws-server-core') +} = require('jsonql-ws-server-core') +// require('../../ws-server-core') module.exports = { diff --git a/packages/ws-server/tests/ws-connect-error.test.js b/packages/ws-server/tests/ws-connect-error.test.js index 40a5e7bee0f0f3537fc7ccb5b028a7c80321494b..4518f4a9703b21bdfe016c46f57bea9710e206a4 100644 --- a/packages/ws-server/tests/ws-connect-error.test.js +++ b/packages/ws-server/tests/ws-connect-error.test.js @@ -62,17 +62,21 @@ test.cb(`It should able to extract the error object when error throw from the se localDebug('json decoded from msg:', data) - t.truthy(data.error, 'causeError should have error field') - // data.error = typeof data.error === 'string' ? JSON.parse(data.error) : data.error; - t.is(data.error.className, 'JsonqlResolverAppError') - t.is(json.type, ERROR_KEY) - - // The same problem happens again - // data.error.className === 'JsonqlResolverAppError' - // it returned a JsonqlError again - t.is(json.resolverName, 'causeError') - - t.end() + if (data.error) { + + t.truthy(data.error, 'causeError should have error field') + // data.error = typeof data.error === 'string' ? JSON.parse(data.error) : data.error; + t.is(data.error.className, 'JsonqlResolverAppError') + t.is(json.type, ERROR_KEY) + t.is(json.resolverName, 'causeError') + t.end() + } else { + // this seems weird but in fact, + // before the resolver throw error, it send a message out + // therefore here should able to capture a message + + debug('Got a send message:', data) + } } catch(e) { localDebug('error happens in the catch phrase and end the test', e) diff --git a/packages/ws-server/tests/ws-jwt-auth.test.js b/packages/ws-server/tests/ws-jwt-auth.test.js index b97dc75c80b8111c36330d4f84649d964da98d0c..cc3f741f107d72efb271a4cceef7022161f696ad 100644 --- a/packages/ws-server/tests/ws-jwt-auth.test.js +++ b/packages/ws-server/tests/ws-jwt-auth.test.js @@ -22,6 +22,9 @@ const port = 3003 const baseUrl = `ws://localhost:${port}/${JSONQL_PATH}/` const { rainbow } = colors +const EventEmitter = require('@to1source/event') + + test.before(async t => { const { app, io } = await serverSetup({ contract, @@ -48,6 +51,8 @@ test.before(async t => { t.context.client_public = basicClient(baseUrl + 'public') // t.context.client_private_1 = await fullClient(baseUrl + 'private', t.context.token) + t.context.eventEmitter = new EventEmitter() + }) test.after(t => { @@ -74,7 +79,6 @@ test.cb('It should able to connect to public namespace without a token', t => { // client.close() t.end() }) - }) test.cb('It should able to connect to the private namespace', t => { @@ -95,28 +99,36 @@ test.cb('It should able to connect to the private namespace', t => { debug('second json', json) t.end() }) - /* - t.context.client_private_1.on('open', () => { - t.end() - }) - */ }) // @NOTE when we run this in serial, it could hang up. // Also if a 401 happens, does it mean the server die? or the client die (of course) // what about the other clients? Should we reconnect them? so many question at the moment test.cb(`first try to connect to the private without login and see what happens`, t => { - + const evtEmitter = t.context.eventEmitter + const evtName = 'count' + const add = () => evtEmitter.$trigger(evtName) const plan = 3 t.plan(plan) + let ctn = 0 + evtEmitter.$on(evtName, () => { + ++ctn + debug(rainbow('============================= count added ==========================='), ctn) + if (ctn >= plan) { + t.end() + } + }) + // crash out the client let authClient = basicClient(baseUrl + 'private') // this is useful we could add this to the client to handle the error authClient.on('error', err => { debug(rainbow(`Got error`), err) + t.truthy(err, `Expect to get an error`) // (1) + add() }) @@ -128,29 +140,38 @@ test.cb(`first try to connect to the private without login and see what happens` debug(rainbow(`onopen`)) pClient.send( createPayload('availableToEveryone') ) }) + pClient.on('message', data => { let json = extractWsPayload(data) debug(rainbow('PUBLIC reply'), json) + t.truthy(json.data, `Expect to get respond from the public nsp`) + add() }) + pClient.on('error', err => { debug(rainbow('public client error'), err) }) - - setTimeout(() => { authClient = basicClient(baseUrl + 'private', t.context.token1) + authClient.on('message', data => { ++ctn let json = extractWsPayload(data) + debug(rainbow(ctn+''), json) + t.truthy(json.data) // 3 + authClient.close() - t.end() + add() }) + authClient.on('open', () => { - authClient.send( createPayload('secretChatroom', 'la', 'na') ) + authClient.send( + createPayload('secretChatroom', 'la', 'na') + ) }) }, 500)