diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 47fa13110723a19b813c7104953e599c6173661e..3d644b4f27c82af3c539dab537d3dd8919a2ef30 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.8.7", + "version": "1.8.8", "description": "JS API / command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ @@ -36,7 +36,7 @@ "nodejs", "node" ], - "author": "to1soure ", + "author": "to1soure ", "contributors": [ "Joel Chu " ], @@ -45,24 +45,24 @@ "jsonql-contract": "./cli.js" }, "dependencies": { - "acorn": "^7.1.0", + "acorn": "^7.1.1", "chokidar": "^3.3.1", "colors": "^1.4.0", "debug": "^4.1.1", "fs-extra": "^8.1.0", "glob": "^7.1.6", "jsdoc-api": "^5.0.4", - "jsonql-constants": "^1.8.14", + "jsonql-constants": "^1.9.8", "jsonql-errors": "^1.1.10", "jsonql-params-validator": "^1.5.2", - "jsonql-utils": "^0.9.7", + "jsonql-utils": "^1.0.6", "kefir": "^3.8.6", "lodash": "^4.17.15", "nb-split-tasks": "^0.6.0", - "yargs": "^15.1.0" + "yargs": "^15.3.0" }, "devDependencies": { - "ava": "^3.3.0", + "ava": "^3.5.0", "nyc": "^15.0.0" }, "ava": { diff --git a/packages/contract-cli/src/options/constants.js b/packages/contract-cli/src/options/constants.js new file mode 100644 index 0000000000000000000000000000000000000000..cf8d1cf0a16781a584bee67dc6dbf0b6daa35dc3 --- /dev/null +++ b/packages/contract-cli/src/options/constants.js @@ -0,0 +1,23 @@ +// take those inline value out and create constants here +// to keep the no magic value +const BASE_DIR = process.cwd() +const AUTH_ALIAS = 'auth' +const IN_DIR_ALIAS = 'inDir' +const OUT_DIR_ALIAS = 'outDir' +const WATCH_ALIAS = 'w' +const INTERVAL_ALIAS = 'i' +const CONFIG_FILE_ALIAS = 'c' +const TMP_DIR = 'tmp' +const STANDALONE_ALIAS = 'standaloneSocketMode' + +module.exports = { + BASE_DIR, + AUTH_ALIAS, + IN_DIR_ALIAS, + OUT_DIR_ALIAS, + WATCH_ALIAS, + INTERVAL_ALIAS, + CONFIG_FILE_ALIAS, + TMP_DIR, + STANDALONE_ALIAS +} diff --git a/packages/contract-cli/src/options.js b/packages/contract-cli/src/options/index.js similarity index 70% rename from packages/contract-cli/src/options.js rename to packages/contract-cli/src/options/index.js index a017211677a1d725684b353f113510b68839e9d2..8080c85b3cd6611a6fac75bb5c3363e1bbb88da0 100644 --- a/packages/contract-cli/src/options.js +++ b/packages/contract-cli/src/options/index.js @@ -1,8 +1,11 @@ // default options @TODO add in the next upgrade - -const { resolve, join } = require('path') const fs = require('fs') -const { checkConfigAsync, constructConfig, createConfig } = require('jsonql-params-validator') +const { resolve, join } = require('path') +const { + checkConfigAsync, + constructConfig, + createConfig +} = require('jsonql-params-validator') const { DEFAULT_RESOLVER_DIR, DEFAULT_CONTRACT_DIR, @@ -19,30 +22,40 @@ const { ENUM_KEY, RETURN_AS_FILE, RETURN_AS_ENUM, - ISSUER_NAME, + LOGIN_NAME, LOGOUT_NAME, VALIDATOR_NAME, DEFAULT_CONTRACT_FILE_NAME } = require('jsonql-constants') +const { + BASE_DIR, + AUTH_ALIAS, + IN_DIR_ALIAS, + OUT_DIR_ALIAS, + WATCH_ALIAS, + INTERVAL_ALIAS, + CONFIG_FILE_ALIAS, + TMP_DIR, + STANDALONE_ALIAS +} = require('./constants') -const BASE_DIR = process.cwd() - +// injecter after check const constProps = { BASE_DIR, outputFilename: DEFAULT_CONTRACT_FILE_NAME } - +// base checking map const defaultOptions = { // give the contract an expired time expired: createConfig(0, [NUMBER_TYPE]), - // passing extra props to the contract.json + // passing extra props to the contract.json extraContractProps: createConfig(false, [OBJECT_TYPE], {[OPTIONAL_KEY]: true}), - // Auth related props - loginHandlerName: createConfig(ISSUER_NAME, [STRING_TYPE]), + // Auth related props + loginHandlerName: createConfig(LOGIN_NAME, [STRING_TYPE]), logoutHandlerName: createConfig(LOGOUT_NAME, [STRING_TYPE]), validatorHandlerName: createConfig(VALIDATOR_NAME, [STRING_TYPE, BOOLEAN_TYPE]), - enableAuth: createConfig(false, BOOLEAN_TYPE, {[ALIAS_KEY]: 'auth'}), + enableAuth: createConfig(false, BOOLEAN_TYPE, {[ALIAS_KEY]: AUTH_ALIAS}), // file or json returnAs: createConfig(RETURN_AS_FILE, STRING_TYPE, {[ENUM_KEY]: RETURN_AS_ENUM}), // we need to force it to use useDoc = true for using jsdoc API now @@ -50,8 +63,8 @@ const defaultOptions = { // there will be cjs, es, ts for different parser jsType: constructConfig(CJS_TYPE , STRING_TYPE, false, ACCEPTED_JS_TYPES), // matching the name across the project - the above two will become alias to this - resolverDir: createConfig(resolve(join(BASE_DIR, DEFAULT_RESOLVER_DIR)) , STRING_TYPE, {[ALIAS_KEY]: 'inDir'}), - contractDir: createConfig(resolve(join(BASE_DIR, DEFAULT_CONTRACT_DIR)), STRING_TYPE, {[ALIAS_KEY]: 'outDir'}), + resolverDir: createConfig(resolve(join(BASE_DIR, DEFAULT_RESOLVER_DIR)) , STRING_TYPE, {[ALIAS_KEY]: IN_DIR_ALIAS}), + contractDir: createConfig(resolve(join(BASE_DIR, DEFAULT_CONTRACT_DIR)), STRING_TYPE, {[ALIAS_KEY]: OUT_DIR_ALIAS}), // show or hide the description field in the public contract // contractWithDesc: createConfig(false, [BOOLEAN_TYPE]), @1.7.6 move to Koa // remove the old one and always create a new one - useful during development @@ -63,18 +76,22 @@ const defaultOptions = { public: constructConfig(false, [BOOLEAN_TYPE]), banner: constructConfig(true, [BOOLEAN_TYPE]), // this are for the cmd mostly - watch: createConfig(false, [BOOLEAN_TYPE, STRING_TYPE, NUMBER_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: 'w'}), - interval: createConfig(10000, [NUMBER_TYPE, STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: 'i'}), - configFile: createConfig(false, [STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: 'c'}), - announceUrl: createConfig(false, [STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: 'a'}), + watch: createConfig(false, [BOOLEAN_TYPE, STRING_TYPE, NUMBER_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: WATCH_ALIAS}), + interval: createConfig(10000, [NUMBER_TYPE, STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: INTERVAL_ALIAS}), + configFile: createConfig(false, [STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: CONFIG_FILE_ALIAS}), + // announceUrl: createConfig(false, [STRING_TYPE], {[OPTIONAL_KEY]: true, [ALIAS_KEY]: 'a'}), + logDirectory: constructConfig(false, [STRING_TYPE], true), - tmpDir: createConfig(join(BASE_DIR, 'tmp'), [STRING_TYPE]), + + tmpDir: createConfig(join(BASE_DIR, TMP_DIR), [STRING_TYPE]), // ported from jsonql-koa buildContractOnStart: constructConfig(false, [BOOLEAN_TYPE], true), // @1.8.x enable or disable the split tasks enableSplitTask: createConfig(false, [BOOLEAN_TYPE]), - // add 1.8.7 to determine if we clean out the contract folder or not - development: createConfig(false, [BOOLEAN_TYPE]) + // add 1.8.7 to determine if we clean out the contract folder or not + development: createConfig(false, [BOOLEAN_TYPE]), + standalone: createConfig(false, [BOOLEAN_TYPE], {[ALIAS_KEY]: STANDALONE_ALIAS}) } + // export it module.exports = config => checkConfigAsync(config, defaultOptions, constProps) diff --git a/packages/contract-cli/tests/fixtures/es/auth/login.js b/packages/contract-cli/tests/fixtures/es/auth/login.js new file mode 100644 index 0000000000000000000000000000000000000000..61dceb165c61eb6a4d352277ed6722363de2345f --- /dev/null +++ b/packages/contract-cli/tests/fixtures/es/auth/login.js @@ -0,0 +1,8 @@ +/** + * @param {string} username username + * @param {string} password password + * @return {object} user object + */ +export default function login(username, password) { + return { username, ts: Date.now() } +} diff --git a/packages/contract-cli/tests/fixtures/resolvers/auth/login.js b/packages/contract-cli/tests/fixtures/resolvers/auth/login.js index 9ffab69df7b204194f9a7792eae33bf07deae889..fba911acc112545bb21fffecae7585acf14f9e9b 100755 --- a/packages/contract-cli/tests/fixtures/resolvers/auth/login.js +++ b/packages/contract-cli/tests/fixtures/resolvers/auth/login.js @@ -5,5 +5,5 @@ * @return {boolean} result */ module.exports = function(username, password) { - return true; + return true } diff --git a/packages/contract-cli/tests/fixtures/resolvers/socket/auth/login.js b/packages/contract-cli/tests/fixtures/resolvers/socket/auth/login.js new file mode 100644 index 0000000000000000000000000000000000000000..853afcc0377cf8d671e0eacce5372521ad842dc2 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/resolvers/socket/auth/login.js @@ -0,0 +1,9 @@ +/** + * When the socket in standalone mode this should get take into the contract as well + * @param {string} username username + * @param {string} password password + * @return {object} userdata + */ +module.exports = function login(username, password) { + return { username, ts: Date.now() } +} diff --git a/packages/contract-cli/tests/fixtures/resolvers/socket/auth/logout.js b/packages/contract-cli/tests/fixtures/resolvers/socket/auth/logout.js new file mode 100644 index 0000000000000000000000000000000000000000..81e94eae9526eba6f547779d74b6f71495ed160c --- /dev/null +++ b/packages/contract-cli/tests/fixtures/resolvers/socket/auth/logout.js @@ -0,0 +1,11 @@ +/** + * logout interceptor + * @param {object} userdata the user that just logout + * @return {void} + */ +module.exports = function logout(userdata) { + // when user logout from the nsp, they will send one last call with their userdata + // to notify the server that this user has logout + // if this file presented then this interceptor will get call + console.log(userdata, 'just logout') +} diff --git a/packages/contract-cli/tests/generator.test.js b/packages/contract-cli/tests/generator.test.js index 509b0f14c39ada61254708d0eefac8085a438a99..7adf0c8b16e3fb69a445a073a6de29868f14b3c8 100755 --- a/packages/contract-cli/tests/generator.test.js +++ b/packages/contract-cli/tests/generator.test.js @@ -10,25 +10,25 @@ const { DEFAULT_RESOLVER_LIST_FILE_NAME, DEFAULT_RESOLVER_IMPORT_FILE_NAME } = require('jsonql-constants'); -const resolverDir = join(__dirname, 'fixtures', 'resolvers') -const contractDir = join(__dirname, 'fixtures', 'tmp', 'with-auth') + const debug = require('debug')('jsonql-contract:test:generator') const fsx = require('fs-extra') const generator = require('../index') +const resolverDir = join(__dirname, 'fixtures', 'resolvers') +const contractDir = join(__dirname, 'fixtures', 'tmp', 'with-auth') const baseContractFile = join(contractDir, DEFAULT_CONTRACT_FILE_NAME) const publicContractFile = join(contractDir, PUBLIC_CONTRACT_FILE_NAME) const esContractDir = join(__dirname, 'fixtures', 'tmp', 'es') const esResolverDir = join(__dirname, 'fixtures', 'es') - -const expired = Date.now() + 60*365*1000; +const expired = Date.now() + 60*365*1000 test.after(async t => { - fsx.removeSync(contractDir) - fsx.removeSync(esContractDir) + // fsx.removeSync(contractDir) + // fsx.removeSync(esContractDir) // remove the two generate files // @NOTE remove these two files in 1.7.21 // fsx.removeSync( join(esResolverDir, DEFAULT_RESOLVER_LIST_FILE_NAME) ) @@ -53,8 +53,8 @@ test.serial('There should be a contract.json output to the contractDir', async t }) t.is(true, fsx.existsSync( baseContractFile )) }) - -test.serial('Should able to create a public-contract.json', async t => { +// serial. +test.only('Should able to create a public-contract.json', async t => { const result = await generator({ resolverDir, contractDir, @@ -63,15 +63,18 @@ test.serial('Should able to create a public-contract.json', async t => { public: true }) + debug('public-contract.json', result) + t.true(fsx.existsSync(publicContractFile)) const json = fsx.readJsonSync(publicContractFile) - t.is(json.expired, expired) + t.is(json.expired, expired, 'Expired field should be the same as what is given') - t.false(!!json.auth.validator) - t.true(json.auth.login !== undefined) + t.false(!!json.auth.validator, 'should not have a validator field') + // there is no auth in there + t.true(json.auth.login !== undefined, 'should have a login') // now check if certain method is public - t.true(json.query.anyoneCanGetThis.public) + t.true(json.query.anyoneCanGetThis.public, 'anyoneCanGetThis should be public') // now check if certain method in private folder is included // t.truthy(json.query.privateFn) // check for namespace diff --git a/packages/contract-cli/tests/socket.test.js b/packages/contract-cli/tests/socket.test.js new file mode 100644 index 0000000000000000000000000000000000000000..ec7ac4aebd10ddce350202f5632b0a5caebc0e92 --- /dev/null +++ b/packages/contract-cli/tests/socket.test.js @@ -0,0 +1,9 @@ +// develop the new socket auth feature for contract +const test = require('ava') +const { join } = require('path') +const fsx = require('fs-extra') + +const resolverDir = join(__dirname, 'fixtures', 'resolvers') + + +test.todo(`It should able to generate new entry when socket/auth has content`) diff --git a/packages/node-client/tests/fixtures/jwt/contract.json b/packages/node-client/tests/fixtures/jwt/contract.json index 136cadac9efdacdbe5bbf2dcc7a8ade5eb351f8d..b59ec20a638ce4797e74cf99686612be43cb1990 100644 --- a/packages/node-client/tests/fixtures/jwt/contract.json +++ b/packages/node-client/tests/fixtures/jwt/contract.json @@ -102,7 +102,7 @@ ] } }, - "timestamp": 1582268247, + "timestamp": 1583829857, "sourceType": "script", "socket": { "gateway": { diff --git a/packages/ws-server-core/index.js b/packages/ws-server-core/index.js index 31e0bb53f60192b5dcca5027d3a2f4dfd3f19dc4..f9ef9a3f17816a7df5c98f59eb9dea9bf8463053 100644 --- a/packages/ws-server-core/index.js +++ b/packages/ws-server-core/index.js @@ -16,10 +16,6 @@ const { const { addProperty } = require('./src/share/add-property') const { getContract } = require('./src/share/get-contract') - -const { resolveSocketMethod } = require('./src/share/resolve-socket-method') -const { runResolver } = require('./src/share/run-resolver') - const { createWsReply, getDebug, @@ -37,11 +33,7 @@ const { const jsonqlWsCoreConstants = require('./src/options/constants') const { - handleInterCom, - handleLogout, - handleStandaloneLogin, - handleUnknownPayload, - handleNspResolvers + getSocketHandler } = require('./src/handles') // export every bits out then the downstream build as they want @@ -60,8 +52,7 @@ module.exports = { getUserdata, isUserdata, prepareUserdata, - resolveSocketMethod, - runResolver, + // just uniform until method, really should be in the jsonql-utils/node getDebug, getRainbowDebug, @@ -76,9 +67,5 @@ module.exports = { jsonqlWsServerCore, jsonqlWsServerCoreAction, // @0.6.0 - handleInterCom, - handleLogout, - handleStandaloneLogin, - handleUnknownPayload, - handleNspResolvers + getSocketHandler } diff --git a/packages/ws-server-core/package.json b/packages/ws-server-core/package.json index 0f5026fa125a1aca9c8666a22e8d9a661ce8b9ed..9188b1e8038b24b77effcfa23a7c4ebd80f70d8c 100644 --- a/packages/ws-server-core/package.json +++ b/packages/ws-server-core/package.json @@ -34,7 +34,7 @@ "jsonql-jwt": "^1.3.9", "jsonql-params-validator": "^1.5.2", "jsonql-resolver": "^1.1.1", - "jsonql-utils": "^1.0.5", + "jsonql-utils": "^1.0.6", "lodash": "^4.17.15" }, "devDependencies": { diff --git a/packages/ws-server-core/src/handles/get-socket-handler.js b/packages/ws-server-core/src/handles/get-socket-handler.js index c4ca27e6604c97a64d25517ca34d931234803195..1e4f5d32c386a6203502b01b93ac6513ea4a6d0c 100644 --- a/packages/ws-server-core/src/handles/get-socket-handler.js +++ b/packages/ws-server-core/src/handles/get-socket-handler.js @@ -1,14 +1,74 @@ +const { + LOGOUT_EVENT_NAME, + SA_LOGIN_EVENT_NAME, + INTER_COM_EVENT_NAME +} = require('jsonql-constants') +const { SOCKET_STATE_KEY } = require('../options/constants') + const { handleInterCom } = require('./handle-intercom') const { handleLogout } = require('./handle-logout') const { handleStandaloneLogin } = require('./handle-standalone-login') -const { handleUnknownPayload } = require('./handle-unknown-payload') const { handleNspResolvers } = require('./handle-nsp-resolvers') +// @TBC do we need this const { handleUnknownPayload } = require('./handle-unknown-payload') +const { getRainbowDebug } = require('../share/helpers') + +const debug = getRainbowDebug('handles:get-socket-handler') + +/** + * Make sure the resolver is belongs to this namespace + * @param {string} resolverName calling from + * @param {string} namespace currently connected namespace + * @param {object} nspGroup namespace --> resolvers object map + * @return {*} false when not found, or the params from the resolver + */ +function matchResolverByNamespace(resolverName, namespace, nspGroup) { + const g = nspGroup[namespace] + if (g && g[resolverName]) { + return g[resolverName] + } + debug(`matchResolverByNamespace`, `${resolverName} is not in ${namespace}`) + // we fail this silencely for now and see what happen + return false + // throw new Error(`nspGroup does not have this group ${namespace}`) +} + + /** * This is the generic methods that will be wrap inside the on.message (for ws) * all it takes it how to delivery the message back * @param {object} config full configuration - * + * @param {object} ws The socket server instance for injection + * @param {function} deliverFn a wrapper method to deliver the message + * @param {object} req the request object + * @param {string} connectedNamespace which namespace is this calling from + * @param {object} payload from the message call + * @param {object|boolean} userdata if any + * @return {void} unless we throw an error */ -function getSocketHandler(config) { - +function getSocketHandler(config, ws, deliverFn, req, connectedNamespace, payload, userdata) { + const { nspInfo, enableAuth } = config + const { namespaces, publicNamespace, size, nspGroup } = nspInfo + const resolverName = getNameFromPayload(payload) + const args = payload[resolverName] + // it might be the special internal event? + switch (true) { + + case resolverName === LOGOUT_EVENT_NAME: + // we don't need to send anything back @TBC do we need the config + return handleLogout(ws, req, args, config) + + case resolverName === SA_LOGIN_EVENT_NAME: + return handleStandaloneLogin(deliverFn, ws, req, args, config) + + case resolverName === INTER_COM_EVENT_NAME: + // We don't need to send anything back // @TBC do we need the config + return handleInterCom(config, ws, req, args, userdata) + + default: + + const params = matchResolverByNamespace(resolverName, namespace, nspGroup) + + handleNspResolvers(deliverFn, ws, resolverName, args, params, config, userdata) + } + } 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 69a087f982de5b0dcc8a4cbcc5a52e58022520a9..6d1335415d27dcf0d5d80ef7586466cf1cb9be4c 100644 --- a/packages/ws-server-core/src/handles/handle-nsp-resolvers.js +++ b/packages/ws-server-core/src/handles/handle-nsp-resolvers.js @@ -1,35 +1,41 @@ // make this more generic and share it to create resolver for each nsp // @TODO this property still not create correctly -const { TIMESTAMP_PARAM_NAME } = require('jsonql-constants') - -const { runResolver } = require('../share/run-resolver') -const { getDebug } = require('../share/helpers') - -const debug = getDebug('handle-nsp') +// const { TIMESTAMP_PARAM_NAME } = require('jsonql-constants') +// get the resolver to handle the request +const { validateInput, deliverMsg } = require('../share/resolver-methods') +const { resolveSocketMethod } = require('../share/resolve-socket-method') +const { getDebug } = require('./helpers') +const debug = getDebug('share:get-resolver') /** - * The default single nsp mapping to resolver + * handle resolvers * @param {function} deliverFn the final delivery message method - * @param {object} ws the socket instance inject to resolver as property - * @param {object} json data send from client - * @param {object} socketFns contract + * @param {object} ws the socket instance get add to the resolver as property + * @param {string} resolverName name of resolver + * @param {*} args from payload + * @param {object} params from contract.json * @param {object} opts configuration - * @param {*} [userdata=false] userdata if any - * @return {void} nothing - */ -const handleNspResolvers = (deliverFn, ws, json, socketFns, opts, userdata = false) => { - debug('TIMESTAMP_PARAM_NAME', json[TIMESTAMP_PARAM_NAME], TIMESTAMP_PARAM_NAME) + * @param {object} userdata userdata + * @return {promise} resolve the result + */ +const handleNspResolvers = (deliverFn, ws, resolverName, args, params, opts, userdata) => { + // debug('TIMESTAMP_PARAM_NAME', json[TIMESTAMP_PARAM_NAME], TIMESTAMP_PARAM_NAME) // const ts = json[TIMESTAMP_PARAM_NAME] // keep this for use later - for (let resolverName in json) { - if (resolverName !== TIMESTAMP_PARAM_NAME) { // dirty hack for now - debug('connection call', resolverName) - let payload = json[resolverName] - let params = socketFns[resolverName] - // we need to use the decoded token --> userdata - // and pass to the resolver - runResolver(deliverFn, ws, payload, resolverName, params, opts, userdata) - } - } + // @NOTE the params.params is from the contract + return validateInput(args, params) + .then(args => resolveSocketMethod( + deliverFn, + resolverName, + args, // this is the clean value from validateAsync + params, + opts, + ws, + userdata + ) + ) + .then( + result => deliveryMsg(deliverFn, result, resolverName) + ) } module.exports = { handleNspResolvers } diff --git a/packages/ws-server-core/src/handles/index.js b/packages/ws-server-core/src/handles/index.js index ce6a5289a7c44a4d303004960120ec82de76d194..7ce78d1e4f95894c7f4a2da037c6ef769503d1b4 100644 --- a/packages/ws-server-core/src/handles/index.js +++ b/packages/ws-server-core/src/handles/index.js @@ -1,15 +1,5 @@ // All these methods move from the ws-server // we need to make them all generic -const { handleInterCom } = require('./handle-intercom') -const { handleLogout } = require('./handle-logout') -const { handleStandaloneLogin } = require('./handle-standalone-login') -const { handleUnknownPayload } = require('./handle-unknown-payload') -const { handleNspResolvers } = require('./handle-nsp-resolvers') +const { getSocketHandler } = require('./get-socket-handler') -module.exports = { - handleInterCom, - handleLogout, - handleStandaloneLogin, - handleUnknownPayload, - handleNspResolvers // @0.6.2 rename from handleNsp make more sense -} +module.exports = { getSocketHandler } diff --git a/packages/ws-server-core/src/share/helpers.js b/packages/ws-server-core/src/share/helpers.js index b639e3f18799fd4bdf77bab64db1dd67593eb409..9ff343c0601811fefd04a13a389011cabc435dbc 100644 --- a/packages/ws-server-core/src/share/helpers.js +++ b/packages/ws-server-core/src/share/helpers.js @@ -6,7 +6,8 @@ const { WS_EVT_NAME, WS_DATA_NAME, SOCKET_CLIENT_ID_KEY, - SOCKET_CLIENT_TS_KEY + SOCKET_CLIENT_TS_KEY, + TIMESTAMP_PARAM_NAME } = require('jsonql-constants') const { MODULE_NAME, @@ -17,6 +18,7 @@ const { clientErrorsHandler } = require('jsonql-errors') const { + nil, // moved to the jsonql-utils toJson, isObjectHasKey, isFunc, @@ -37,6 +39,14 @@ const WS_KEYS = [ WS_DATA_NAME ] +// @TODO move this to jsonql-utils once its all test and done + +const getResolverFromPayload = payload => { + const keys = Object.keys(payload) + return keys.filter(key => key !== TIMESTAMP_PARAM_NAME)[0] +} + + /** * Create the debug instance @@ -112,11 +122,6 @@ const extractWsPayload = payload => { throw new JsonqlError('payload can not decoded', payload) } -// just an empty method for addProperty getter -function nil() { - return false -} - /** * Should this be elsewhere because this is * get the userdata via the decoded jwt from the request object @@ -159,13 +164,12 @@ function isUserdata(userdata) { /** * Take this out from the ws-setup because we need the same prop for the ws-create-server now + * @0.7.0 just a wrapper now but keep all the module import in one place * @param {object} opts configuration * @return {object} nspInfo */ function getNspInfo(opts) { return getNspInfoByConfig(opts) - // const { contract } = opts - // return groupByNamespace(contract) } @@ -185,5 +189,6 @@ module.exports = { nil, isFunc, + getResolverFromPayload, getNspInfo } diff --git a/packages/ws-server-core/src/share/run-resolver.js b/packages/ws-server-core/src/share/run-resolver.js deleted file mode 100644 index 29deb92a558abfa3dbd02ece67e0a88b7585bd91..0000000000000000000000000000000000000000 --- a/packages/ws-server-core/src/share/run-resolver.js +++ /dev/null @@ -1,37 +0,0 @@ -// get the resolver to handle the request -const { validateInput, deliverMsg } = require('./resolver-methods') -const { resolveSocketMethod } = require('./resolve-socket-method') -const { getDebug } = require('./helpers') -const debug = getDebug('share:get-resolver') - -/** - * handle resolvers - * @param {function} deliverFn the final delivery message method - * @param {object} ws the socket instance get add to the resolver as property - * @param {object} payload args array - * @param {string} resolverName name of resolver - * @param {object} params from contract.json - * @param {object} opts configuration - * @param {object} userdata userdata - */ -function runResolver(deliverFn, ws, payload, resolverName, params, opts, userdata) { - // @NOTE the params.params is from the contract - return validateInput(payload.args, params.params) - .then(args => resolveSocketMethod( - deliverFn, - resolverName, - args, // this is the clean value from validateAsync - params, - opts, - ws, - userdata - ) - ) - .then(result => deliveryMsg(deliverFn, result, resolverName)) -} - -module.exports = { - runResolver - // deliveryMsg, - // validateInput -} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/auth/login.js b/packages/ws-server-core/tests/fixtures/resolvers/auth/login.js new file mode 100644 index 0000000000000000000000000000000000000000..8aa2524793c6eb6f3a470482bc8e9bdea2f26002 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/auth/login.js @@ -0,0 +1,9 @@ + +/** + * create a login method for testing + * @param {string} username username + * @return {object} userdata + */ +module.exports = function login(username) { + return {name: username} +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/auth/logout.js b/packages/ws-server-core/tests/fixtures/resolvers/auth/logout.js new file mode 100644 index 0000000000000000000000000000000000000000..b5957eb2e26f4ac5a0cd0ede1e36847d5f1e6163 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/auth/logout.js @@ -0,0 +1,7 @@ +/** + * testing the logout method call + * @return {boolean} true + */ +module.exports = function logout() { + return true; +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/disconnect.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/disconnect.js new file mode 100644 index 0000000000000000000000000000000000000000..b6c7462c8de9fdb70760ef42d418da5c9fff29fe --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/disconnect.js @@ -0,0 +1,10 @@ +const debug = require('debug')('ws-client-core:fixtures:auth:disconnect') +/** + * Intercept the disconnect event + * @param {array} args + * @return {void} + */ +module.exports = function disconnect(...args) { + // @TODO + debug('intercept the disconnect event', args) +} \ No newline at end of file diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/login.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/login.js new file mode 100644 index 0000000000000000000000000000000000000000..c95e24b9622a66b340cc35bb1ba45a6b893b0c9d --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/login.js @@ -0,0 +1,17 @@ +/** + * Standalone mode to allow using the socket server to login + * @param {string} username + * @param {string} password + * @return {object} a user object then package as jwt string (internal process) + */ +module.exports = function login(username, password) { + const users = [{name: 'joel', pass: '1234'} , {name: 'davided', pass: '5678'}] + const user = users.filter(user => username === user.name && password === user.pass) + .reduce((base, user) => { + return user + }, false) + if (user !== false) { + return user + } + throw new Error(`User not found!`) +} \ No newline at end of file diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/logout.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/logout.js new file mode 100644 index 0000000000000000000000000000000000000000..354a5828fb4a828bfe469d3c1672268122287157 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/auth/logout.js @@ -0,0 +1,10 @@ +const debug = require('debug')('ws-client-core:fixtures:auth:logout') +/** + * Intercept the login event + * @param {array} args + * @return {void} + */ +module.exports = function logout(...args) { + // @TODO + debug(`Intercept the logout event`, args) +} \ No newline at end of file diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/cause-error.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/cause-error.js new file mode 100644 index 0000000000000000000000000000000000000000..c49b9ab04f6a6525b0731f3c2a4731cde7a86730 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/cause-error.js @@ -0,0 +1,10 @@ +// this method will throw an error + +/** + * @param {string} msg a message + * @return {string} a message but here we throw an error + */ +module.exports = function causeError(msg) { + causeError.send('something else') + throw new Error(msg) +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/chatroom.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/chatroom.js new file mode 100644 index 0000000000000000000000000000000000000000..0b57676e1e3a1cd3ee583eaaf249a9accea26ce6 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/chatroom.js @@ -0,0 +1,12 @@ +// a private method + +/** + * + * @param {string} msg message + * @param {number} timestamp for checking the time + * @return {string} reply + */ +module.exports = function(msg, timestamp) { + const d = Date.now() - timestamp; + return msg + ` took ${d} ms`; +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/delay-fn.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/delay-fn.js new file mode 100644 index 0000000000000000000000000000000000000000..523ed5c1640af604a093213806dcdad5da0f1422 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/delay-fn.js @@ -0,0 +1,15 @@ +// test this with a Promise return result +/** + * @param {string} msg a message + * @param {number} timestamp a timestamp + */ +module.exports = function delayFn(msg, timestamp) { + // also test the global socket instance + delayFn.send = 'I am calling from delayFn'; + + return new Promise(resolver => { + setTimeout(() => { + resolver(msg + (Date.now() - timestamp)) + }, 1000) + }) +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/private/secret-chatroom.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/private/secret-chatroom.js new file mode 100644 index 0000000000000000000000000000000000000000..34ba0ac33d945b4b01e5281e49e95acff8c6d39b --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/private/secret-chatroom.js @@ -0,0 +1,14 @@ +const { debug } = require('../../../../../src/utils') +/** + * @param {string} room room name + * @param {*} msg message to that room + * @return {*} depends + */ +module.exports = function secretChatroom(room, msg) { + + debug('secretChatroom.userdata', secretChatroom.userdata) + + let userdata = secretChatroom.userdata + // @TODO + return `send ${msg+''} to ${room} room from ${userdata.name}` +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/public/available-to-everyone/index.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/public/available-to-everyone/index.js new file mode 100644 index 0000000000000000000000000000000000000000..16b326f970dc769884dda13e36b4df9f3f924166 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/public/available-to-everyone/index.js @@ -0,0 +1,9 @@ +// This method for testing the public call + +/** + * There is no parameter require for this call + * @return {string} a message + */ +module.exports = function availableToEveryone() { + return 'You get a public message'; +} diff --git a/packages/ws-server-core/tests/fixtures/resolvers/socket/ws-handler.js b/packages/ws-server-core/tests/fixtures/resolvers/socket/ws-handler.js new file mode 100644 index 0000000000000000000000000000000000000000..7831c9cbc615719cbc45f1c97fddb582d5122851 --- /dev/null +++ b/packages/ws-server-core/tests/fixtures/resolvers/socket/ws-handler.js @@ -0,0 +1,18 @@ +// will test this one with the send property + +/** + * method just for testing the ws + * @param {string} msg message + * @param {number} timestamp timestamp + * @return {string} msg + time lapsed + */ +module.exports = function wsHandler(msg, timestamp) { + const ts = Date.now() + wsHandler.send('I am sending a message back from ws', ts) + + return new Promise(resolver => { + setTimeout(() => { + resolver(msg + ' - ' +(ts - timestamp)) + }, 1000) + }) +}