fix subscribe+sesame

This commit is contained in:
2020-01-18 20:54:34 +01:00
parent 367d42a965
commit ae843d341e
5 changed files with 90 additions and 33 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "rpclibrary", "name": "rpclibrary",
"version": "1.5.1", "version": "1.5.2",
"description": "rpclibrary is a websocket on steroids!", "description": "rpclibrary is a websocket on steroids!",
"main": "./js/Index.js", "main": "./js/Index.js",
"repository": { "repository": {
-1
View File
@@ -37,7 +37,6 @@ export class RPCServer<
if(!conf.visibility) this.visibility = "127.0.0.1" if(!conf.visibility) this.visibility = "127.0.0.1"
if(conf.sesame){ if(conf.sesame){
console.log("Setting Sesame")
this.sesame = U.makeSesameFunction(conf.sesame) this.sesame = U.makeSesameFunction(conf.sesame)
} }
+12 -5
View File
@@ -106,7 +106,7 @@ export class RPCSocket implements I.Socket{
f = this.callGenerator(i.uniqueName, i.argNames, sesame) f = this.callGenerator(i.uniqueName, i.argNames, sesame)
break break
case 'Hook': case 'Hook':
f = this.hookGenerator(i.uniqueName, i.argNames, sesame) f = this.frontEndHookGenerator(i.uniqueName, i.argNames, sesame)
break break
} }
if(this[i.owner] == null) if(this[i.owner] == null)
@@ -143,21 +143,28 @@ export class RPCSocket implements I.Socket{
* @param fnName The function name * @param fnName The function name
* @param fnArgs A string-list of parameters * @param fnArgs A string-list of parameters
*/ */
private hookGenerator(fnName: string, fnArgs:string[], sesame?:string): T.HookFunction{ private frontEndHookGenerator(fnName: string, fnArgs:string[], sesame?:string): T.HookFunction{
fnArgs.pop()
const headerArgs = fnArgs.join(",") const headerArgs = fnArgs.join(",")
const argParams = fnArgs.map(stripAfterEquals).join(",") const argParams = fnArgs.map(stripAfterEquals).join(",")
if(!sesame){ if(!sesame){
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => { const headerArgs = fnArgs.join(",")
const argParams = fnArgs.map(stripAfterEquals).join(",")
const f = eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
const r = await this.socket.call("`+fnName+`", `+argParams+`) const r = await this.socket.call("`+fnName+`", `+argParams+`)
if(r.result === 'Success'){ if(r && r.result === 'Success'){
this.socket.hook(r.uuid, callback) this.socket.hook(r.uuid, callback)
} }
return r return r
} )()` ) } )()` )
return f
}else{ }else{
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => { return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
const r = await this.socket.call("`+fnName+`", "`+sesame+`", `+argParams+`) const r = await this.socket.call("`+fnName+`", "`+sesame+`", `+argParams+`)
if(r.result === 'Success'){ if(r && r.result === 'Success'){
this.socket.hook(r.uuid, callback) this.socket.hook(r.uuid, callback)
} }
return r return r
+20 -18
View File
@@ -82,37 +82,38 @@ export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter
}) })
} }
/** /**
* Utility function to generate {@link HookFunction} from a RPC * Utility function to generate {@link HookFunction} from a RPC for backend
* @param rpc The RPC to transform * @param rpc The RPC to transform
* @returns A {@link HookFunction} * @returns A {@link HookFunction}
*/ */
const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesame?:T.SesameFunction): T.HookInfo['generator'] => { const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesameFn?: T.SesameFunction): T.HookInfo['generator'] => {
const argsArr = extractArgs(rpc.hook) const argsArr = extractArgs(rpc.hook)
if(sesame){
const _sesame = argsArr.shift()
if(!sesame(_sesame!)){
throw new Error('Bad sesame')
}
}
argsArr.pop() //remove 'callback' from the end argsArr.pop() //remove 'callback' from the end
const args = argsArr.join(',') const argsStr = argsArr.join(',')
return eval(`(socket) => async (`+args+`) => { if(sesameFn){
const args = ['sesame', ...argsArr].join(',')
const f = eval(`(socket) => async (`+args+`) => {
if(!sesameFn(sesame)) return
const res = await rpc.hook(`+argsStr+(argsStr.length!==0?',':'')+` (...cbargs) => {
if(rpc.onCallback) rpc.onCallback.apply({}, cbargs)
socket.call.apply(socket, [res.uuid, ...cbargs])
})
return res
}`)
return f
}
const args = argsArr.join(',')
return eval(`(socket) => async (`+args+`) => {
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (...cbargs) => { const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (...cbargs) => {
if(rpc.onCallback) rpc.onCallback.apply({}, cbargs) if(rpc.onCallback) rpc.onCallback.apply({}, cbargs)
socket.call.apply(socket, [res.uuid, ...cbargs]) socket.call.apply(socket, [res.uuid, ...cbargs])
}) })
if(res.result === 'Success'){
if(rpc.onClose){
socket.on('close', async () => {
rpc.onClose(res, rpc)
})
}
}
return res return res
}`) }`)
} }
/** /**
* Extract a string list of parameters from a function * Extract a string list of parameters from a function
* @param f The source function * @param f The source function
@@ -134,6 +135,7 @@ export function makeSubResponse<T extends {} = {}>(extension:T):SubscriptionResp
} }
} }
export function makeSesameFunction (sesame : T.SesameFunction | string) : T.SesameFunction { export function makeSesameFunction (sesame : T.SesameFunction | string) : T.SesameFunction {
if(typeof sesame === 'function'){ if(typeof sesame === 'function'){
return sesame return sesame
@@ -142,4 +144,4 @@ export function makeSesameFunction (sesame : T.SesameFunction | string) : T.Sesa
return (testSesame : string) => { return (testSesame : string) => {
return testSesame === sesame return testSesame === sesame
} }
} }
+57 -8
View File
@@ -1,4 +1,4 @@
import { describe, it } from "mocha"; import { describe, it, Func } from "mocha";
import { RPCServer, RPCSocket, SubscriptionResponse, makeSubResponse } from '../Index' import { RPCServer, RPCSocket, SubscriptionResponse, makeSubResponse } from '../Index'
import * as uuidv4 from "uuid/v4" import * as uuidv4 from "uuid/v4"
@@ -226,18 +226,35 @@ describe('It should do unhook', () => {
}) })
type SesameTestIfc = { test: { checkCandy: ()=>Promise<string>} } type SesameTestIfc = {
test: {
checkCandy: ()=>Promise<string>
subscribe: (callback) => Promise<SubscriptionResponse<{ topic: string; }>>
}
}
describe('Sesame should unlock the socket', () => { describe('Sesame should unlock the socket', () => {
let candy = "OK" let candy = "OK"
let client: RPCSocket & SesameTestIfc let client: RPCSocket & SesameTestIfc
let server: RPCServer<{topic: string}, SesameTestIfc> let server: RPCServer
let cb = (...args) => {}
before(async() => { before(async() => {
server = new RPCServer<{ topic: string }, SesameTestIfc>(20004, [{ server = new RPCServer(20004, [{
name: "test", name: "test",
exportRPCs: () => [ exportRPCs: () => [
async function checkCandy():Promise<string> { return candy }, {
name: 'subscribe',
hook: async(callback) => {
cb = callback
return <SubscriptionResponse>{
result: "Success",
uuid: uuidv4(),
topic: 'test'
}
}
},
async function checkCandy():Promise<string> { cb(candy); cb=()=>{}; return candy },
]} ]}
],{ ],{
sesame: (_sesame) => _sesame === 'sesame!' sesame: (_sesame) => _sesame === 'sesame!'
@@ -251,6 +268,10 @@ describe('Sesame should unlock the socket', () => {
server.destroy() server.destroy()
}) })
it('should work with sesame', (done) => {
client.test.checkCandy().then(c => done())
})
it('should not work without sesame', (done) => { it('should not work without sesame', (done) => {
const sock = new RPCSocket(20004, "localhost") const sock = new RPCSocket(20004, "localhost")
sock.connect<SesameTestIfc>( /* no sesame */).then(async (c) => { sock.connect<SesameTestIfc>( /* no sesame */).then(async (c) => {
@@ -264,7 +285,35 @@ describe('Sesame should unlock the socket', () => {
}) })
}) })
it('should work with sesame', (done) => { it('callback should work with sesame', (done) => {
client.test.checkCandy().then(c => done()) client.test.subscribe((c) => {
if(c === candy){
done()
}
}).then(d => {
if(d.result !== 'Success')
done('expected valid response')
client.test.checkCandy()
})
}) })
})
it('callback should not work without sesame', (done) => {
const sock = new RPCSocket(20004, "localhost")
sock.connect<SesameTestIfc>( /* no sesame */).then(async (c) => {
c.test.subscribe((c) => {
console.log("CALLBACK TRIGGERED UNEXPECTED");
if(c === candy)
done("super not")
}).then(async d => {
await client.test.checkCandy()
if(d == null){
done()
}else
done('unexpected valid response '+(d) )
c.destroy()
})
})
})
})