diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js b/packages/@jsonql/ws/src/core/create-nsp.js similarity index 84% rename from packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js rename to packages/@jsonql/ws/src/core/create-nsp.js index 58933a868245bf8c9717a96046f99e6dc027c264..b015d2875f518d1e748e777b0fdc58a6819ac603 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp-action.js +++ b/packages/@jsonql/ws/src/core/create-nsp.js @@ -1,7 +1,8 @@ +// actually binding the event client to the socket client import { createNspClient, createNspAuthClient -} from '../modules' +} from './modules' import { chainPromises } from 'jsonql-utils/src/chain-promises' @@ -16,9 +17,11 @@ import { * @param {string|null} token whether we have the token at run time * @return {promise} resolve the nsps namespace with namespace as key */ -const createNspAction = function(opts, nspMap, token) { - const { log } = opts +const createNsp = function(opts, nspMap, token = null) { + // we leave the token param out because it could get call by another method + token = token || opts.token let { publicNamespace, namespaces } = nspMap + const { log } = opts log(`createNspAction`, 'publicNamespace', publicNamespace, 'namespaces', namespaces) // reverse the namespaces because it got stuck for some reason @@ -48,5 +51,4 @@ const createNspAction = function(opts, nspMap, token) { .then(nsp => ({[publicNamespace]: nsp})) } - -export { createNspAction } \ No newline at end of file +export { createNsp } diff --git a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js b/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js deleted file mode 100644 index a148e9367c97b69fa4ca02e6b977b3d208266e2c..0000000000000000000000000000000000000000 --- a/packages/@jsonql/ws/src/core/create-nsp/create-nsp.js +++ /dev/null @@ -1,37 +0,0 @@ -// actually binding the event client to the socket client - -// from the jsonql-ws-client-core -import { clientEventListener } from '../modules' -import { bindSocketEventHandler } from './bind-socket-event-handler' -// local -import { createNspAction } from './create-nsp-action' -import { loginEventListener } from './login-event-listener' - - -/** - * create the NSP(s) and determine if this require auth or not - * @param {object} opts configuration - * @param {object} nspMap namespace with resolvers - * @param {object} ee EventEmitter to pass through - * @return {object} what comes in what goes out - */ -function createNsp(opts, nspMap, ee) { - // now create the nsps - // const { namespaces } = nspMap - const { token } = opts - - return createNspAction(opts, nspMap, token) - .then(nsps => { - const listenerFn = clientEventListener(bindSocketEventHandler, nsps) - // now run it - listenerFn(opts, nspMap, ee) - - if (opts.enableAuth) { - loginEventHandler(opts, nspMap, ee) - } - // return what input - return { opts, nspMap, ee } - }) -} - -export { createNsp } diff --git a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js index cdb6df394df51bdb113b29ef97af5d4575d83b7f..9ca78977b5740fcf944b06eac6057e5bd89ed2fd 100644 --- a/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-framework-to-jsonql.js @@ -1,7 +1,30 @@ // share method to create the wsClientResolver +import { + NSP_CLIENT, + NSP_AUTH_CLIENT, + CONNECT_EVENT_NAME +} from 'jsonql-constants' + +import { clientEventListener } from '../modules' +import { createNsp } from '../create-nsp' + import { initWebSocketClient } from './init-websocket-client' -import createNsp from '../create-nsp' -import { NSP_CLIENT, NSP_AUTH_CLIENT } from 'jsonql-constants' +import { bindSocketEventHandler } from './bind-socket-event-handler' + +/** + * This is finally the core of this operation + * 1. connect the nsp (with or without the token auth) + * 2. binding nsp to the jsonql event listener + * @param {object} config configuration + * @param {object} nspMap the namespace map etc + * @param {object} ee the event class instance + * @return {*} + */ +function nspToEvtBinding(config, nspMap, ee) { + return createNsp(config, nspMap) + .then(nsps => clientEventListener(bindSocketEventHandler, nsps)) + .then(listenerFn => listenerFn(config, nspMap, ee)) +} /** * Create the framework <---> jsonql client binding @@ -20,11 +43,22 @@ function bindFrameworkToJsonql(frameworkModule) { const { log } = opts opts[NSP_CLIENT] = initWebSocketClient(frameworkModule, false, log) opts[NSP_AUTH_CLIENT] = initWebSocketClient(frameworkModule, true, log) - // @1.0.7 remove later once everything fixed - + // debug log(`bindFrameworkToJsonql`, ee.name, nspMap) - // console.log(`contract`, opts.contract) - return createNsp(opts, nspMap, ee) + // @2020-03-20 @NOTE + // now we don't run the connection straight away + // instead we only set it to listen to the connect event call + // this event will pass back the modified opts object + // also we pass the event emitter back with additional properties + + ee.$only(CONNECT_EVENT_NAME, function($config, $ee) { + return nspToEvtBinding($config, nspMap, $ee) + }) + // next we need to setup the login event handler + + + // we just return what comes in + return { opts, nspMap, ee } } } diff --git a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-socket-event-handler.js similarity index 84% rename from packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js rename to packages/@jsonql/ws/src/core/create-websocket-binding/bind-socket-event-handler.js index 780590fd3db28b4ffc281eb2f44a9ea3c9e01253..c4e4a108decac90c94ad1eba432de97caa6151d1 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/bind-socket-event-handler.js +++ b/packages/@jsonql/ws/src/core/create-websocket-binding/bind-socket-event-handler.js @@ -1,15 +1,13 @@ // the WebSocket main handler import { - LOGOUT_EVENT_NAME, ACKNOWLEDGE_REPLY_TYPE, EMIT_REPLY_TYPE, ERROR_KEY, - - ON_ERROR_FN_NAME, ON_MESSAGE_FN_NAME, ON_RESULT_FN_NAME, ON_READY_FN_NAME, - ON_LOGIN_FN_NAME + ON_LOGIN_FN_NAME, + ON_ERROR_FN_NAME } from 'jsonql-constants' import { createQueryStr, @@ -17,8 +15,7 @@ import { extractWsPayload } from 'jsonql-utils/module' import { - handleNamespaceOnError, - createIntercomPayload + handleNamespaceOnError } from '../modules' /** @@ -30,7 +27,7 @@ import { * @param {object} json decoded payload or error object * @return {undefined} nothing return */ -const errorTypeHandler = (ee, namespace, resolverName, json) => { +export const errorTypeHandler = (ee, namespace, resolverName, json) => { let evt = [namespace] if (resolverName) { evt.push(resolverName) @@ -42,26 +39,6 @@ const errorTypeHandler = (ee, namespace, resolverName, json) => { ee.$trigger(evtName, [payload]) } -/** - * Handle the logout event when it's enableAuth - * @param {object} ee eventEmitter - * @param {object} ws the WebSocket instance - * @return {void} - */ -const logoutEventListener = (ee, ws) => { - // listen to the LOGOUT_EVENT_NAME when this is a private nsp - ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { - try { - // @TODO we need find a way to get the userdata - ws.send(createIntercomPayload(LOGOUT_EVENT_NAME)) - log('terminate ws connection') - ws.terminate() - } catch(e) { - console.error('ws.terminate error', e) - } - }) -} - /** * Binding the event to socket normally * @param {string} namespace @@ -80,7 +57,7 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { log('=== ws.onopen listened -->', namespace) // we just call the onReady - ee.$call(ON_READY_FN_NAME)(namespace) + ee.$trigger(ON_READY_FN_NAME, [namespace]) // we only want to allow it get call twice (number of namespaces) --onReadCalls if (onReadCalls === 0) { @@ -101,7 +78,6 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { * @param {array} args NEED TO CHECK HOW WE PASS THIS! */ function wsMainOnEvtHandler(resolverName, args) { - const payload = createQueryStr(resolverName, args) log('ws.onopen.send', resolverName, args, payload) @@ -166,9 +142,7 @@ export function bindSocketEventHandler(namespace, ws, ee, isPrivate, opts) { log(`ws.onerror`, err) handleNamespaceOnError(ee, namespace, err) } - - if (isPrivate) { - logoutEventListener(ee, ws) - } - + + // we don't bind the logut here and just return the ws + return ws } diff --git a/packages/@jsonql/ws/src/core/create-nsp/disconnect.js b/packages/@jsonql/ws/src/core/handlers/disconnect.js similarity index 100% rename from packages/@jsonql/ws/src/core/create-nsp/disconnect.js rename to packages/@jsonql/ws/src/core/handlers/disconnect.js diff --git a/packages/@jsonql/ws/src/core/create-nsp/index.js b/packages/@jsonql/ws/src/core/handlers/index.js similarity index 71% rename from packages/@jsonql/ws/src/core/create-nsp/index.js rename to packages/@jsonql/ws/src/core/handlers/index.js index 076f18c4200085e7c49a2a41db8db03439296be1..6c148ae012f215e88b58d5fa35c08975cbba4506 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/index.js +++ b/packages/@jsonql/ws/src/core/handlers/index.js @@ -1,5 +1,5 @@ // breaking up the create-nsp.js file // then regroup them back together here -import { createNsp } from './create-nsp' +import { createNsp } from '../create-nsp' export default createNsp diff --git a/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js b/packages/@jsonql/ws/src/core/handlers/login-event-listener.js similarity index 91% rename from packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js rename to packages/@jsonql/ws/src/core/handlers/login-event-listener.js index f611d76c7be1b61fd4b4fe47544b58a7d280ce35..2151c42abef32e8c061ffb5abf8d24dd10c01661 100644 --- a/packages/@jsonql/ws/src/core/create-nsp/login-event-listener.js +++ b/packages/@jsonql/ws/src/core/handlers/login-event-listener.js @@ -5,9 +5,6 @@ import { LOGIN_EVENT_NAME } from 'jsonql-constants' import { clearMainEmitEvt } from '../modules' -import { clientEventListener } from '../modules' -import { bindSocketEventHandler } from './bind-socket-event-handler' - /** * create a login event handler, that will unbind all existing ws --> event * then rebind them together, so this is a re-run of the create-nsp diff --git a/packages/@jsonql/ws/src/core/handlers/logout-event-handler.js b/packages/@jsonql/ws/src/core/handlers/logout-event-handler.js new file mode 100644 index 0000000000000000000000000000000000000000..f88d4bee3a31a9eb80bfa3184a88b60ace225fed --- /dev/null +++ b/packages/@jsonql/ws/src/core/handlers/logout-event-handler.js @@ -0,0 +1,24 @@ +// taken out from the bind-socket-event-handler +import { LOGOUT_EVENT_NAME } from 'jsonql-constants' +import { createIntercomPayload } from '../modules' + +/** + * This is the actual logout (terminate socket connection) handler + * There is another one that is handle what should do when this happen + * @param {object} ee eventEmitter + * @param {object} ws the WebSocket instance + * @return {void} + */ +export const logoutEventListener = (ee, ws) => { + // listen to the LOGOUT_EVENT_NAME when this is a private nsp + ee.$on(LOGOUT_EVENT_NAME, function closeEvtHandler() { + try { + // @TODO we need find a way to get the userdata + ws.send(createIntercomPayload(LOGOUT_EVENT_NAME)) + log('terminate ws connection') + ws.terminate() + } catch(e) { + console.error('ws.terminate error', e) + } + }) +} \ No newline at end of file diff --git a/packages/@jsonql/ws/src/node-ws-client.js b/packages/@jsonql/ws/src/node-ws-client.js index 8d1384b2664939d7995723f457872a201c7fad84..1e64c048b6dc6668e4c4bf443604f9e029c57c78 100644 --- a/packages/@jsonql/ws/src/node-ws-client.js +++ b/packages/@jsonql/ws/src/node-ws-client.js @@ -4,14 +4,14 @@ import { } from './core/modules' import { wsClientConstProps } from './options' -import nodeFrameworkSocketEngine from './node/node-framework-socket-engine' +import setupSocketClientListener from './node/setup-socket-client-listener' // export back the function and that's it export default function wsNodeClient(config = {}, constProps = {}) { - const initClientMethod = wsClientCore( - nodeFrameworkSocketEngine, + + return wsClientCore( + setupSocketClientListener, {}, Object.assign({}, wsClientConstProps, constProps) - ) - return initClientMethod(config) + )(config) } diff --git a/packages/@jsonql/ws/src/node/node-framework-socket-engine.js b/packages/@jsonql/ws/src/node/setup-socket-client-listener.js similarity index 100% rename from packages/@jsonql/ws/src/node/node-framework-socket-engine.js rename to packages/@jsonql/ws/src/node/setup-socket-client-listener.js diff --git a/packages/constants/README.md b/packages/constants/README.md index 4c936c6cf995dbaf31fac333051e363be7fcd49d..ce7e3434f8eac4a54c02714fb6fcfabbbd4dac88 100755 --- a/packages/constants/README.md +++ b/packages/constants/README.md @@ -181,6 +181,7 @@ Please consult the detail break down below. - SOCKET_CLIENT_ID_KEY - SOCKET_CLIENT_TS_KEY - CONNECT_EVENT_NAME +- CONNECTED_EVENT_NAME - DISCONNECT_EVENT_NAME - INTERCOM_RESOLVER_NAME - INTER_COM_EVENT_NAMES diff --git a/packages/constants/browser.js b/packages/constants/browser.js index d6a210e3ebb82b75edbd24795a349a2b3470d86d..ceb21f3dc209496a38e48dff805fb8c34b6546a4 100644 --- a/packages/constants/browser.js +++ b/packages/constants/browser.js @@ -179,6 +179,7 @@ var jsonqlConstants = { "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", "CONNECT_EVENT_NAME": "__connect__", + "CONNECTED_EVENT_NAME": "__connected__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ diff --git a/packages/constants/constants.json b/packages/constants/constants.json index 7a8e8d90df1faa139b5460ced68fc84f410e670e..ea077f2316974cbc6bd2d1cfbad34ae0625ae328 100644 --- a/packages/constants/constants.json +++ b/packages/constants/constants.json @@ -179,6 +179,7 @@ "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", "CONNECT_EVENT_NAME": "__connect__", + "CONNECTED_EVENT_NAME": "__connected__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ diff --git a/packages/constants/index.js b/packages/constants/index.js index 8989bbb9f7ba7d61f20e62075f07f8e1bd63769b..5176ec8535d10ff797f89ec327baf45a6b301057 100644 --- a/packages/constants/index.js +++ b/packages/constants/index.js @@ -269,6 +269,12 @@ export const SOCKET_CLIENT_TS_KEY = '__socket_client_ts_key__' // although it should never happens, but in some edge case might want to // disconnect from the current server, then re-establish connection later export const CONNECT_EVENT_NAME = '__connect__' +// we still need the connected event because after the connection establish +// we need to change a state within the client to let the front end know that +// it's current hook up to the server but we don't want to loop back the client +// inside the setup phrase, intead just trigger a connected event and the listener +// setup this property +export const CONNECTED_EVENT_NAME = '__connected__' export const DISCONNECT_EVENT_NAME = '__disconnect__' // instead of using an event name in place of resolverName in the param // we use this internal resolverName instead, and in type using the event names diff --git a/packages/constants/main.js b/packages/constants/main.js index 071bf0a17112e3213f400d18d726b995622631e2..8e791039e60c18c8cbc0b26492406a9a4f18bb48 100644 --- a/packages/constants/main.js +++ b/packages/constants/main.js @@ -179,6 +179,7 @@ module.exports = { "SOCKET_CLIENT_ID_KEY": "__socket_client_id_key__", "SOCKET_CLIENT_TS_KEY": "__socket_client_ts_key__", "CONNECT_EVENT_NAME": "__connect__", + "CONNECTED_EVENT_NAME": "__connected__", "DISCONNECT_EVENT_NAME": "__disconnect__", "INTERCOM_RESOLVER_NAME": "__intercom__", "INTER_COM_EVENT_NAMES": [ diff --git a/packages/constants/package.json b/packages/constants/package.json index 6a67e0118c2c85b3d234d314ff8c4baed006bc4a..0a2cfe86c7fad1beeea2371bd4d8644b734fc22e 100755 --- a/packages/constants/package.json +++ b/packages/constants/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-constants", - "version": "2.0.8", + "version": "2.0.9", "description": "All the share constants for jsonql modules", "main": "main.js", "module": "index.js", diff --git a/packages/constants/socket.js b/packages/constants/socket.js index 670e7aec349e163c347dc95165c96644e2f2a463..7fb08c13aa0b7da08f830e08497af981eaed18b2 100644 --- a/packages/constants/socket.js +++ b/packages/constants/socket.js @@ -21,6 +21,12 @@ export const SOCKET_CLIENT_TS_KEY = '__socket_client_ts_key__' // although it should never happens, but in some edge case might want to // disconnect from the current server, then re-establish connection later export const CONNECT_EVENT_NAME = '__connect__' +// we still need the connected event because after the connection establish +// we need to change a state within the client to let the front end know that +// it's current hook up to the server but we don't want to loop back the client +// inside the setup phrase, intead just trigger a connected event and the listener +// setup this property +export const CONNECTED_EVENT_NAME = '__connected__' export const DISCONNECT_EVENT_NAME = '__disconnect__' // instead of using an event name in place of resolverName in the param // we use this internal resolverName instead, and in type using the event names diff --git a/packages/ws-client-core/package.json b/packages/ws-client-core/package.json index 5c873d20758c1d23a6c6515a05924c689702ddf4..41a068830cc7c9363ee839d4274c41c729e60130 100644 --- a/packages/ws-client-core/package.json +++ b/packages/ws-client-core/package.json @@ -56,7 +56,7 @@ }, "dependencies": { "@to1source/event": "^1.0.0", - "jsonql-constants": "^2.0.4", + "jsonql-constants": "^2.0.8", "jsonql-errors": "^1.2.1", "jsonql-params-validator": "^1.6.1", "jsonql-utils": "^1.2.4" @@ -64,8 +64,8 @@ "devDependencies": { "ava": "^3.5.0", "esm": "^3.2.25", - "fs-extra": "^8.1.0", - "jsonql-contract": "^1.8.10", + "fs-extra": "^9.0.0", + "jsonql-contract": "^1.9.1", "jsonql-jwt": "^1.3.10", "jsonql-ws-server": "^1.7.7", "kefir": "^3.8.6", diff --git a/packages/ws-client-core/src/api.js b/packages/ws-client-core/src/api.js index 4e616d3c0a4798f2587e07f79f72a30e9a365bd5..46e39184a16441d2948a5d7b3ef6e9a01c2199ff 100644 --- a/packages/ws-client-core/src/api.js +++ b/packages/ws-client-core/src/api.js @@ -2,10 +2,7 @@ // The goal is to create a generic method that will able to handle // any kind of clients // import { injectToFn } from 'jsonql-utils' -import { - callersGenerator, - setupFinalStep -} from './callers' +import { callersGenerator } from './callers' import { checkConfiguration, postCheckInjectOpts, @@ -15,28 +12,25 @@ import { /** * 0.5.0 we break up the wsClientCore in two parts one without the config check - * @param {function} socketClientListener + * @param {function} setupSocketClientListener just make sure what it said it does * @return {function} to actually generate the client */ -export function wsClientCoreAction(socketClientListener) { +export function wsClientCoreAction(setupSocketClientListener) { /** * This is a breaking change, to continue the onion skin design * @param {object} config the already checked config * @return {promise} resolve the client */ - return (config = {}) => { + return function createClientAction(config = {}) { return postCheckInjectOpts(config) - // the following two moved to wsPostConfig .then(createRequiredParams) .then( - ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee) + ({opts, nspMap, ee}) => setupSocketClientListener(opts, nspMap, ee) ) .then( - ({opts, nspMap, ee}) => socketClientListener(opts, nspMap, ee) + ({opts, nspMap, ee}) => callersGenerator(opts, nspMap, ee) ) - // because it returns as an array of params - .then(result => Reflect.apply(setupFinalStep, null, result)) .catch(err => { console.error(`jsonql-ws-core-client init error`, err) }) diff --git a/packages/ws-client-core/src/callers/callers-generator.js b/packages/ws-client-core/src/callers/callers-generator.js index 862c01de68cea00260e9dfe89b092dc2fe8fcaf7..1a63417b4c11e0b91bbec1ebbe1c7949b102d9f9 100644 --- a/packages/ws-client-core/src/callers/callers-generator.js +++ b/packages/ws-client-core/src/callers/callers-generator.js @@ -1,17 +1,16 @@ // resolvers generator // we change the interface to return promise from v1.0.3 // this way we make sure the obj return is correct and timely +import { NSP_GROUP } from 'jsonql-constants' import { chainFns } from '../utils' import { setupAuthMethods } from './setup-auth-methods' +import { generateResolvers } from './generator-methods' +import { setupFinalStep } from './setup-final-step' import { - generateResolvers, setupOnReadyListener, setupNamespaceErrorListener -} from './generator-methods' +} from './global-listener' -import { - NSP_GROUP -} from 'jsonql-constants' /** * prepare the methods @@ -36,7 +35,7 @@ export function callersGenerator(opts, nspMap, ee) { // then we only return the obj (wsClient) // This has move outside of here, into the main method // the reason is we could switch around the sequence much easier - // fns.push(setupFinalStep) + fns.push(setupFinalStep) // run it const generator = Reflect.apply(chainFns, null, fns) diff --git a/packages/ws-client-core/src/callers/generator-methods.js b/packages/ws-client-core/src/callers/generator-methods.js index 9e8ea5fc446f6c142a6f4e70779a2e0d73446bac..5b29b986ad65207d3041b5f70201c1dd3ebdb518 100644 --- a/packages/ws-client-core/src/callers/generator-methods.js +++ b/packages/ws-client-core/src/callers/generator-methods.js @@ -7,38 +7,15 @@ // callable api for the developer to setup their front end // the only thing is - when they call they might get an error or // NOT_LOGIN_IN and they can react to this error accordingly -import { finalCatch } from 'jsonql-errors' -import { validateAsync } from 'jsonql-params-validator' -import { setupResolver } from './setup-resolver' -import { actionCall } from './action-call' + +import { + createResolver, + setupResolver +} from './setup-resolver' import { - createEvt, - objDefineProps, - isFunc, injectToFn } from '../utils' -import { - ON_ERROR_FN_NAME, - ON_READY_FN_NAME -} from 'jsonql-constants' -/** - * create the actual function to send message to server - * @param {object} ee EventEmitter instance - * @param {string} namespace this resolver end point - * @param {string} resolverName name of resolver as event name - * @param {object} params from contract - * @param {function} log pass the log function - * @return {function} resolver - */ -function createResolver(ee, namespace, resolverName, params, log) { - // note we pass the new withResult=true option - return function resolver(...args) { - return validateAsync(args, params.params, true) - .then(_args => actionCall(ee, namespace, resolverName, _args, log)) - .catch(finalCatch) - } -} /** * step one get the clientmap with the namespace @@ -71,58 +48,3 @@ export function generateResolvers(opts, ee, nspGroup) { return [ client, opts, ee, nspGroup ] } -/** - * The problem is the namespace can have more than one - * and we only have on onError message - * @param {object} clientthe client itself - * @param {object} opts configuration - * @param {object} ee Event Emitter - * @param {object} nspGroup namespace keys - * @return {array} [obj, opts, ee] - */ -export function setupNamespaceErrorListener(client, opts, ee, nspGroup) { - return [ - objDefineProps( - client, - ON_ERROR_FN_NAME, - function namespaceErrorCallbackHandler(namespaceErrorHandler) { - if (isFunc(namespaceErrorHandler)) { - // please note ON_ERROR_FN_NAME can add multiple listners - for (let namespace in nspGroup) { - // this one is very tricky, we need to make sure the trigger is calling - // with the namespace as well as the error - ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler) - } - } - } - ), - opts, - ee - ] -} - -/** - * This event will fire when the socket.io.on('connection') and ws.onopen - * @param {object} client client itself - * @param {object} opts configuration - * @param {object} ee Event Emitter - * @return {array} [ obj, opts, ee ] - */ -export function setupOnReadyListener(client, opts, ee) { - return [ - objDefineProps( - client, - ON_READY_FN_NAME, - function onReadyCallbackHandler(onReadyCallback) { - if (isFunc(onReadyCallback)) { - // reduce it down to just one flat level - // @2020-03-19 only allow ONE onReady callback otherwise - // it will get fire multiple times which is not what we want - ee.$only(ON_READY_FN_NAME, onReadyCallback) - } - } - ), - opts, - ee - ] -} diff --git a/packages/ws-client-core/src/callers/global-listener.js b/packages/ws-client-core/src/callers/global-listener.js new file mode 100644 index 0000000000000000000000000000000000000000..ebabec1b3009ec76c92a52b1ea9c0eb7a82fa633 --- /dev/null +++ b/packages/ws-client-core/src/callers/global-listener.js @@ -0,0 +1,68 @@ +// move from generator-methods +// they are global event listeners +import { + createEvt, + objDefineProps, + isFunc +} from '../utils' +import { + ON_ERROR_FN_NAME, + ON_READY_FN_NAME +} from 'jsonql-constants' + +/** + * This event will fire when the socket.io.on('connection') and ws.onopen + * @param {object} client client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @return {array} [ obj, opts, ee ] + */ +export function setupOnReadyListener(client, opts, ee) { + return [ + objDefineProps( + client, + ON_READY_FN_NAME, + function onReadyCallbackHandler(onReadyCallback) { + if (isFunc(onReadyCallback)) { + // reduce it down to just one flat level + // @2020-03-19 only allow ONE onReady callback otherwise + // it will get fire multiple times which is not what we want + ee.$only(ON_READY_FN_NAME, onReadyCallback) + } + } + ), + opts, + ee + ] +} + +/** + * The problem is the namespace can have more than one + * and we only have on onError message + * @param {object} clientthe client itself + * @param {object} opts configuration + * @param {object} ee Event Emitter + * @param {object} nspGroup namespace keys + * @return {array} [obj, opts, ee] + */ +export function setupNamespaceErrorListener(client, opts, ee, nspGroup) { + return [ + objDefineProps( + client, + ON_ERROR_FN_NAME, + function namespaceErrorCallbackHandler(namespaceErrorHandler) { + if (isFunc(namespaceErrorHandler)) { + // please note ON_ERROR_FN_NAME can add multiple listners + for (let namespace in nspGroup) { + // this one is very tricky, we need to make sure the trigger is calling + // with the namespace as well as the error + ee.$on(createEvt(namespace, ON_ERROR_FN_NAME), namespaceErrorHandler) + } + } + } + ), + opts, + ee + ] +} + diff --git a/packages/ws-client-core/src/callers/index.js b/packages/ws-client-core/src/callers/index.js index eeeabac44d984e760f0fd6196b22c3955cb5b975..8a2c197e7a1ae5f8deb3766f96ef6c2190b10284 100644 --- a/packages/ws-client-core/src/callers/index.js +++ b/packages/ws-client-core/src/callers/index.js @@ -9,7 +9,7 @@ import { } from './intercom-methods' import { helloWorld } from './hello' import { callersGenerator } from './callers-generator' -import { setupFinalStep } from './setup-final-step' + // just rename it export { @@ -18,6 +18,5 @@ export { extractPingResult, createIntercomPayload, extractSrvPayload, - callersGenerator, - setupFinalStep + callersGenerator } diff --git a/packages/ws-client-core/src/callers/setup-auth-methods.js b/packages/ws-client-core/src/callers/setup-auth-methods.js index df44196bec1998bd681c8eaa39932c7e8818f02c..04d367476f81c1e73463bc8be4a8d38e466b291c 100644 --- a/packages/ws-client-core/src/callers/setup-auth-methods.js +++ b/packages/ws-client-core/src/callers/setup-auth-methods.js @@ -9,8 +9,6 @@ import { injectToFn, chainFns, isString, objDefineProps, isFunc } from '../utils /** - * @TODO this is now become unnecessary because the login is a slave to the - * http-client - but keep this for now and see what we want to do with it later * @UPDATE it might be better if we decoup the two http-client only emit a login event * Here should catch it and reload the ws client @TBC * break out from createAuthMethods to allow chaining call @@ -61,6 +59,8 @@ const setupOnLoginhandler = (obj, opts, ee) => [ objDefineProps(obj, ON_LOGIN_FN_NAME, function onLoginCallbackHandler(onLoginCallback) { if (isFunc(onLoginCallback)) { // only one callback can registered with it, TBC + // Should this be a $onlyOnce listener after the logout + // we add it back? ee.$only(ON_LOGIN_FN_NAME, onLoginCallback) } }), diff --git a/packages/ws-client-core/src/callers/setup-final-step.js b/packages/ws-client-core/src/callers/setup-final-step.js index d6db23543c4692eeed54aad3bab28431c4eac45c..dfd5192453369eb6785e57df4fd725a0f3716018 100644 --- a/packages/ws-client-core/src/callers/setup-final-step.js +++ b/packages/ws-client-core/src/callers/setup-final-step.js @@ -1,5 +1,10 @@ // The final step of the setup before it returns the client import { setupInterCom } from './setup-intercom' +import { injectToFn } from '../utils' +import { + CONNECTED_PROP_KEY, + CONNECT_EVENT_NAME +} from 'jsonql-constants' /** * The final step to return the client @@ -9,10 +14,9 @@ import { setupInterCom } from './setup-intercom' * @return {object} client */ function setupFinalStep(obj, opts, ee) { - - const client = setupInterCom(obj, opts, ee) - - opts.log(`---> The final step to return the ws-client <---`) + + let client = setupInterCom(obj, opts, ee) + // opts.log(`---> The final step to return the ws-client <---`) // add some debug functions client.verifyEventEmitter = () => ee.is // we add back the two things into the client @@ -21,7 +25,11 @@ function setupFinalStep(obj, opts, ee) { client.eventEmitter = opts.eventEmitter client.log = opts.log // we just inject a helloWorld method here - // client[HELLO_FN] = + // set up the init state of the connect + client = injectToFn(client, CONNECTED_PROP_KEY , false, true) + + // now at this point, we are going to call the connect event + ee.$trigger(CONNECT_EVENT_NAME, [opts, ee]) // just passing back the entire opts object return client } diff --git a/packages/ws-client-core/src/callers/setup-resolver.js b/packages/ws-client-core/src/callers/setup-resolver.js index 4e72760b43d872a4c5fc22a7e756bd3a18779306..0b1dbed04a726c4bab9be943cb69662cb6fb21f7 100644 --- a/packages/ws-client-core/src/callers/setup-resolver.js +++ b/packages/ws-client-core/src/callers/setup-resolver.js @@ -5,17 +5,42 @@ import { ON_MESSAGE_FN_NAME, ON_RESULT_FN_NAME } from 'jsonql-constants' -// local +import { finalCatch } from 'jsonql-errors' +import { validateAsync } from 'jsonql-params-validator' +import { actionCall } from './action-call' +// local import { MY_NAMESPACE } from '../options/constants' import { chainFns, objDefineProps, injectToFn, createEvt, isFunc } from '../utils' import { respondHandler } from './respond-handler' import { setupSendMethod } from './setup-send-method' + +/** + * moved back from generator-methods + * create the actual function to send message to server + * @param {object} ee EventEmitter instance + * @param {string} namespace this resolver end point + * @param {string} resolverName name of resolver as event name + * @param {object} params from contract + * @param {function} log pass the log function + * @return {function} resolver + */ +function createResolver(ee, namespace, resolverName, params, log) { + // note we pass the new withResult=true option + return function resolver(...args) { + return validateAsync(args, params.params, true) + .then(_args => actionCall(ee, namespace, resolverName, _args, log)) + .catch(finalCatch) + } +} + + + /** * The first one in the chain, just setup a namespace prop * the rest are passing through * @param {function} fn the resolver function - * @param {object} ee the event emitter + * @param {object} ee the event emitter * @param {string} resolverName what it said * @param {object} params for resolver from contract * @param {function} log the logger function @@ -27,12 +52,12 @@ const setupNamespace = (fn, ee, namespace, resolverName, params, log) => [ namespace, resolverName, params, - log + log ] -/** +/** * onResult handler - */ + */ const setupOnResult = (fn, ee, namespace, resolverName, params, log) => [ objDefineProps(fn, ON_RESULT_FN_NAME, function(resultCallback) { if (isFunc(resultCallback)) { @@ -42,7 +67,7 @@ const setupOnResult = (fn, ee, namespace, resolverName, params, log) => [ respondHandler(result, resultCallback, (error) => { log(`Catch error: "${resolverName}"`, error) ee.$trigger( - createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), error ) }) @@ -57,9 +82,9 @@ const setupOnResult = (fn, ee, namespace, resolverName, params, log) => [ log ] -/** +/** * we do need to add the send prop back because it's the only way to deal with - * bi-directional data stream + * bi-directional data stream */ const setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [ objDefineProps(fn, ON_MESSAGE_FN_NAME, function(messageCallback) { @@ -70,14 +95,14 @@ const setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [ respondHandler(args, messageCallback, (error) => { log(`Catch error: "${resolverName}"`, error) ee.$trigger( - createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), error ) }) } // register the handler for this message event ee.$only( - createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), + createEvt(namespace, resolverName, ON_MESSAGE_FN_NAME), onMessageCallback ) } @@ -89,7 +114,7 @@ const setupOnMessage = (fn, ee, namespace, resolverName, params, log) => [ log ] -/** +/** * ON_ERROR_FN_NAME handler */ const setupOnError = (fn, ee, namespace, resolverName, params, log) => [ @@ -97,7 +122,7 @@ const setupOnError = (fn, ee, namespace, resolverName, params, log) => [ if (isFunc(resolverErrorHandler)) { // please note ON_ERROR_FN_NAME can add multiple listners ee.$only( - createEvt(namespace, resolverName, ON_ERROR_FN_NAME), + createEvt(namespace, resolverName, ON_ERROR_FN_NAME), resolverErrorHandler ) } @@ -116,21 +141,24 @@ const setupOnError = (fn, ee, namespace, resolverName, params, log) => [ * @param {object} params from contract * @param {function} fn resolver function * @param {object} ee EventEmitter - * @param {function} log function + * @param {function} log function * @return {function} resolver */ -export function setupResolver(namespace, resolverName, params, fn, ee, log) { +function setupResolver(namespace, resolverName, params, fn, ee, log) { let fns = [ - setupNamespace, - setupOnResult, - setupOnMessage, - setupOnError, + setupNamespace, + setupOnResult, + setupOnMessage, + setupOnError, setupSendMethod ] - + // get the executor const executor = Reflect.apply(chainFns, null, fns) const args = [fn, ee, namespace, resolverName, params, log] return Reflect.apply(executor, null, args) } + + +export { createResolver, setupResolver } \ No newline at end of file diff --git a/packages/ws-client-core/src/options/index.js b/packages/ws-client-core/src/options/index.js index a2bd7853b831c148c6eaab367a842b09d7b99472..b4caefd2f120350ac6028b2a60ba36d1f130bad9 100644 --- a/packages/ws-client-core/src/options/index.js +++ b/packages/ws-client-core/src/options/index.js @@ -90,7 +90,6 @@ function createRequiredParams(opts) { const ee = opts.eventEmitter // @TODO here we are going to add suspend event to the namespace related methods - return { opts, nspMap, ee } } diff --git a/packages/ws-client-core/tests/auth.test.js b/packages/ws-client-core/tests/auth.test.js index b90556038f94712a81ced134db7bd985ec9a8a80..fa8db4dd08ad159bc456b6a5466438f0d16f35b1 100644 --- a/packages/ws-client-core/tests/auth.test.js +++ b/packages/ws-client-core/tests/auth.test.js @@ -5,8 +5,6 @@ // espcially debug the event system const test = require('ava') const { mockClient, log } = require('./fixtures/lib/mock-client') - - const { ON_ERROR_FN_NAME, ON_LOGIN_FN_NAME diff --git a/packages/ws-client-core/tests/experiment.test.js b/packages/ws-client-core/tests/experiment.test.js index 068c7749c50beaa71314eac1c0121538b5662476..b2c6a2f78dd356aa6933bb4885869a2d6fd30393 100644 --- a/packages/ws-client-core/tests/experiment.test.js +++ b/packages/ws-client-core/tests/experiment.test.js @@ -6,6 +6,8 @@ const { JSONQL_PATH } = require('jsonql-constants') const Event = require('@to1source/event') const debug = require('debug') +const colors = require('colors/safe') + const logger = debug('jsonql-ws-client:test:evt:logger') const localDebug = debug('jsonql-ws-client:test:evt') @@ -104,7 +106,6 @@ test.cb.only(`Testing the fullClient with csrf`, t => { const d1 = p => c1.send(p) const d2 = p => c2.send(p) - c1.onopen = function() { helloWorld(d1) plus() diff --git a/packages/ws-client-core/tests/fixtures/lib/fake-ws-client.js b/packages/ws-client-core/tests/fixtures/lib/fake-ws-client.js index 93a42cbeaad7513db873d382340643fbd6f45666..7d3864d36e5a8bc51d34705d2ae91488e194059b 100644 --- a/packages/ws-client-core/tests/fixtures/lib/fake-ws-client.js +++ b/packages/ws-client-core/tests/fixtures/lib/fake-ws-client.js @@ -7,14 +7,9 @@ import { ON_LOGIN_FN_NAME } from 'jsonql-constants' -function fakeWsClient(...args) { - const obj = { - opts: args[0], - nspMap: args[1], - ee: args[2] - } +function fakeWsClient(opts, nspMap, ee) { - const { enableAuth } = obj.opts + const { enableAuth } = opts // log('\n/////////////////////fakeWsClient//////////////////\n') // log(obj) @@ -22,13 +17,13 @@ function fakeWsClient(...args) { // we fire the the onReady after 1/2 second setTimeout(() => { if (enableAuth) { - obj.ee.$trigger(ON_LOGIN_FN_NAME, 'You are login') + ee.$trigger(ON_LOGIN_FN_NAME, 'You are login') } else { - obj.ee.$trigger(ON_READY_FN_NAME, 'fake!') + ee.$trigger(ON_READY_FN_NAME, 'fake!') } }, 500) - return obj + return { opts, nspMap, ee } } export { fakeWsClient, log } \ No newline at end of file diff --git a/packages/ws-client-core/tests/fixtures/lib/mock-client.js b/packages/ws-client-core/tests/fixtures/lib/mock-client.js index 0d3f497eda81fcb6ffa7f92e7e4cb6d6cf6eea98..cc7344476130a6dda582e8c077abd8519ab86fad 100644 --- a/packages/ws-client-core/tests/fixtures/lib/mock-client.js +++ b/packages/ws-client-core/tests/fixtures/lib/mock-client.js @@ -20,11 +20,6 @@ function mockClient(enableAuth = false) { debugOn: true, hostname: 'http://localhost:8888' }) - .then(config => { - config.log = log - log(`mockClient opts after checkConfiguration`, config) - return config - }) .then(wsClientCoreAction(fakeWsClient)) } diff --git a/packages/ws-server-core/package.json b/packages/ws-server-core/package.json index 7f3615a4bc505f597337a2e99cd0bafec90ce59f..0e07f43b6d70305e62f2e7273d732aa20c244e43 100644 --- a/packages/ws-server-core/package.json +++ b/packages/ws-server-core/package.json @@ -31,7 +31,7 @@ "debug": "^4.1.1", "esm": "^3.2.25", "fs-extra": "^9.0.0", - "jsonql-constants": "^2.0.7", + "jsonql-constants": "^2.0.8", "jsonql-errors": "^1.2.1", "jsonql-jwt": "^1.3.10", "jsonql-params-validator": "^1.6.1", diff --git a/packages/ws-server/package.json b/packages/ws-server/package.json index a0e4f4b55cfddcae3578a790fb7702fd7de80184..f7ae3149fb9b6523f333c5f14736b741e337f704 100755 --- a/packages/ws-server/package.json +++ b/packages/ws-server/package.json @@ -33,7 +33,7 @@ "dependencies": { "colors": "^1.4.0", "debug": "^4.1.1", - "jsonql-constants": "^2.0.7", + "jsonql-constants": "^2.0.8", "jsonql-utils": "^1.2.4", "jsonql-ws-server-core": "^0.7.10", "ws": "^7.2.3" diff --git a/packages/ws-server/src/core/setup-socket-server.js b/packages/ws-server/src/core/setup-socket-server.js index 80f5fad97a9eedaba2cca9a6da12a2b985622115..4045bd5f4ef77a6d4b0d858721b08eba9ea3e8ef 100644 --- a/packages/ws-server/src/core/setup-socket-server.js +++ b/packages/ws-server/src/core/setup-socket-server.js @@ -9,7 +9,7 @@ const rdebug = getRainbowDebug('ws-setup') const { createWsServer } = require('./create-ws-server') /** - * This is the core of the communicaton engine + * This is the core of the communicaton engine * and this method get pass back to the ws-server-core to finish the setup * @param {object} opts configuration * @param {object} server the http server instance @@ -22,18 +22,18 @@ function setupSocketServer(opts, server) { nsps[namespace].on('connection', (ws, req) => { let deliverFn = msg => ws.send(msg) let userdata = getUserdata(req) - rdebug(namespace, 'connected') + rdebug(namespace, ' --> connected') // @TODO need to redo here the nspGroup can be empty??? ws.on('message', data => { let payload = parseJson(data) - rdebug(`${namespace} --> message`, payload) + rdebug(`${namespace} --> on.message -->`, payload) // we now wrap everything in one generic method getSocketHandler(opts, ws, deliverFn, req, namespace, payload, userdata) }) }) } - return nsps + return nsps }