fix
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
import * as Back from './src/backend/RPCSocketServer';
|
||||||
|
import * as Front from './src/frontend/RPCSocket';
|
||||||
|
|
||||||
|
export {
|
||||||
|
Back as Backend,
|
||||||
|
Front as Frontend
|
||||||
|
}
|
||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rpclibrary",
|
"name": "rpclibrary",
|
||||||
"version": "1.0.1",
|
"version": "1.0.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+39
-20
@@ -18,17 +18,46 @@ export {
|
|||||||
export class Server{
|
export class Server{
|
||||||
private ws = http.createServer()
|
private ws = http.createServer()
|
||||||
private io = bsock.createServer()
|
private io = bsock.createServer()
|
||||||
|
private visibility:T.Visibility
|
||||||
|
private closeHandler:T.CloseHandler
|
||||||
|
private errorHandler: T.ErrorHandler
|
||||||
|
private connectionHandler: T.ConnectionHandler
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private port:number,
|
private port:number,
|
||||||
private exporters: I.Exporter[] = [],
|
private exporters: I.Exporter[] = [],
|
||||||
private conf: T.SocketConf = {
|
conf: T.SocketConf = {}
|
||||||
errorHandler: (socket:I.Socket) => (error:any) => { socket.destroy(); console.error(error) },
|
|
||||||
closeHandler: (socket:I.Socket) => () => { console.log("Socket closing") },
|
|
||||||
connectionHandler: (socket:I.Socket) => { console.log("New websocket connection in port "+socket.port)},
|
|
||||||
visibility: "127.0.0.1"
|
|
||||||
}
|
|
||||||
){
|
){
|
||||||
|
|
||||||
|
if(!conf.visibility) this.visibility = "127.0.0.1"
|
||||||
|
|
||||||
|
if(!conf.errorHandler) this.errorHandler =
|
||||||
|
(socket:I.Socket) => (error:any) => {
|
||||||
|
socket.destroy();
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!conf.closeHandler) this.closeHandler =
|
||||||
|
(socket:I.Socket) => () => {
|
||||||
|
console.log("Socket on port "+socket.port+"closing")
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!conf.connectionHandler) this.connectionHandler =
|
||||||
|
(socket:I.Socket) => {
|
||||||
|
console.log("New websocket connection in port "+socket.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
let badRPC
|
||||||
|
if(badRPC = exporters.flatMap(ex => ex.exportRPCs()).find(rpc => !rpc.name))
|
||||||
|
throw new Error(`
|
||||||
|
RPC did not provide a name.
|
||||||
|
\nUse funtion name(..){ .. } syntax instead.
|
||||||
|
\n
|
||||||
|
\n<------------OFFENDING RPC:
|
||||||
|
\n`+badRPC.toString()+`
|
||||||
|
\n>------------OFFENDING RPC`)
|
||||||
|
|
||||||
this.startWebsocket()
|
this.startWebsocket()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,14 +65,12 @@ export class Server{
|
|||||||
try{
|
try{
|
||||||
this.io.attach(this.ws)
|
this.io.attach(this.ws)
|
||||||
this.io.on('socket', (socket:I.Socket) => {
|
this.io.on('socket', (socket:I.Socket) => {
|
||||||
socket.on('error', this.conf.errorHandler(socket))
|
socket.on('error', this.errorHandler(socket))
|
||||||
socket.on('close', this.conf.closeHandler(socket))
|
socket.on('close', this.closeHandler(socket))
|
||||||
if(this.conf.visibility === "127.0.0.1")
|
this.connectionHandler(socket)
|
||||||
this.initRPCs(socket)
|
this.initRPCs(socket)
|
||||||
else
|
|
||||||
this.initPublicRPCs(socket)
|
|
||||||
})
|
})
|
||||||
this.ws.listen(this.port, this.conf.visibility)
|
this.ws.listen(this.port, this.visibility)
|
||||||
}catch(e){
|
}catch(e){
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
this.errorHandler(undefined)("Unable to connect to socket")
|
this.errorHandler(undefined)("Unable to connect to socket")
|
||||||
@@ -57,12 +84,4 @@ export class Server{
|
|||||||
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
|
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initPublicRPCs(socket:I.Socket){
|
|
||||||
socket.hook('info', () => rpcInfos)
|
|
||||||
|
|
||||||
const rpcInfos:T.ExtendedRpcInfo[] = [
|
|
||||||
...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter))
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+4
-6
@@ -1,6 +1,6 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
var bsock = require('bsock')
|
import bsock = require('bsock');
|
||||||
|
|
||||||
import * as T from './Types';
|
import * as T from './Types';
|
||||||
import * as U from './Utils';
|
import * as U from './Utils';
|
||||||
@@ -26,8 +26,6 @@ export class Client implements I.Socket{
|
|||||||
constructor(public port:number, private server: string, private tls: boolean = false){
|
constructor(public port:number, private server: string, private tls: boolean = false){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public hook(name: T.Name, args: T.Arg){
|
public hook(name: T.Name, args: T.Arg){
|
||||||
return this.socket.hook(name, args)
|
return this.socket.hook(name, args)
|
||||||
}
|
}
|
||||||
@@ -96,9 +94,9 @@ export class Client implements I.Socket{
|
|||||||
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
return 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.uid != null){
|
if(r.uid != null){
|
||||||
this.socket.hook(res.uid, callback)
|
this.socket.hook(r.uid, callback)
|
||||||
}
|
}
|
||||||
return res
|
return r
|
||||||
} )()` )
|
} )()` )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +109,7 @@ export class Client implements I.Socket{
|
|||||||
return eval( `( () => async (`+headerArgs+`) => {
|
return eval( `( () => async (`+headerArgs+`) => {
|
||||||
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
||||||
this.socket.unhook(`+argParams+`)
|
this.socket.unhook(`+argParams+`)
|
||||||
return res
|
return r
|
||||||
} )()` )
|
} )()` )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -3,8 +3,7 @@ import * as I from "./Interfaces"
|
|||||||
|
|
||||||
export interface Exporter{
|
export interface Exporter{
|
||||||
name: T.Name
|
name: T.Name
|
||||||
localRPCs() : T.RPC[]
|
exportRPCs() : T.RPC[]
|
||||||
publicRPCs() : T.RPC[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Socket {
|
export interface Socket {
|
||||||
|
|||||||
+10
-8
@@ -6,12 +6,14 @@ export type Any = any
|
|||||||
export type Arg = string
|
export type Arg = string
|
||||||
export type Name = Arg
|
export type Name = Arg
|
||||||
export type Owner = Name
|
export type Owner = Name
|
||||||
|
export type ConnectionHandler = (socket:I.Socket) => void
|
||||||
|
export type ErrorHandler = (socket:I.Socket) => (error:any) => void
|
||||||
|
export type CloseHandler = (socket:I.Socket) => () => void
|
||||||
export type SocketConf = {
|
export type SocketConf = {
|
||||||
connectionHandler: (socket:I.Socket) => void
|
connectionHandler?: ConnectionHandler
|
||||||
errorHandler: (socket:I.Socket) => (error:any) => void
|
errorHandler?: ErrorHandler
|
||||||
closeHandler: (socket:I.Socket) => () => void
|
closeHandler?: CloseHandler
|
||||||
visibility: Visibility
|
visibility?: Visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RPCType = 'Hook' | 'Unhook' | 'Call'
|
export type RPCType = 'Hook' | 'Unhook' | 'Call'
|
||||||
@@ -23,7 +25,7 @@ export type BaseRPC = {
|
|||||||
|
|
||||||
export type HookRPC = BaseRPC & {
|
export type HookRPC = BaseRPC & {
|
||||||
type: 'Hook'
|
type: 'Hook'
|
||||||
clbk: CallbackFunction
|
hook: CallbackFunction
|
||||||
unhook: UnhookFunction
|
unhook: UnhookFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,10 +34,10 @@ export type UnhookRPC = BaseRPC & {
|
|||||||
unhook: UnhookFunction
|
unhook: UnhookFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CallRPC = BaseRPC & {
|
export type CallRPC = (BaseRPC & {
|
||||||
type: 'Call'
|
type: 'Call'
|
||||||
call: AsyncFunction
|
call: AsyncFunction
|
||||||
}
|
} ) | Function
|
||||||
|
|
||||||
export type RPC = CallRPC | UnhookRPC | HookRPC
|
export type RPC = CallRPC | UnhookRPC | HookRPC
|
||||||
|
|
||||||
|
|||||||
+24
-4
@@ -4,6 +4,8 @@ import * as T from "./Types";
|
|||||||
import * as I from "./Interfaces";
|
import * as I from "./Interfaces";
|
||||||
|
|
||||||
export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
||||||
|
switch (typeof rpc){
|
||||||
|
case "object":
|
||||||
switch(rpc.type){
|
switch(rpc.type){
|
||||||
case "Call" :
|
case "Call" :
|
||||||
return {
|
return {
|
||||||
@@ -32,10 +34,29 @@ export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
|
|||||||
generator: generator,
|
generator: generator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
if(!rpc.name) throw new Error(`
|
||||||
|
RPC did not provide a name.
|
||||||
|
\nUse funtion name(..){ .. } syntax instead.
|
||||||
|
\n
|
||||||
|
\n<------------OFFENDING RPC:
|
||||||
|
\n`+rpc.toString()+`
|
||||||
|
\n>------------OFFENDING RPC`)
|
||||||
|
return {
|
||||||
|
type: "Call",
|
||||||
|
owner : owner,
|
||||||
|
argNames: extractArgs(rpc),
|
||||||
|
call: async(...args) => rpc.apply({}, args),
|
||||||
|
name: rpc.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Bad socketIORPC type "+ typeof rpc)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{
|
export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{
|
||||||
const owner = exporter.name
|
const owner = exporter.name
|
||||||
const RPCs = [...exporter.publicRPCs(), ...exporter.localRPCs()]
|
const RPCs = [...exporter.exportRPCs()]
|
||||||
const suffix = makeUnique?"-"+uuid().substr(0,4):""
|
const suffix = makeUnique?"-"+uuid().substr(0,4):""
|
||||||
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
|
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
|
||||||
.map(info => {
|
.map(info => {
|
||||||
@@ -59,12 +80,12 @@ export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = tr
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
|
const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
|
||||||
const argsArr = extractArgs(rpc.clbk)
|
const argsArr = extractArgs(rpc.hook)
|
||||||
argsArr.pop()
|
argsArr.pop()
|
||||||
const args = argsArr.join(',')
|
const args = argsArr.join(',')
|
||||||
|
|
||||||
return eval(`(socket) => async (`+args+`) => {
|
return eval(`(socket) => async (`+args+`) => {
|
||||||
const res = await rpc.clbk(`+args+(args.length!==0?',':'')+` (x) => {
|
const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (x) => {
|
||||||
socket.call(res.uid, x)
|
socket.call(res.uid, x)
|
||||||
})
|
})
|
||||||
if(res.result == 'Success'){
|
if(res.result == 'Success'){
|
||||||
@@ -72,7 +93,6 @@ const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
|
|||||||
const unhookRes = await rpc.unhook(res.uid)
|
const unhookRes = await rpc.unhook(res.uid)
|
||||||
console.log("Specific close handler for", rpc.name, res.uid, unhookRes)
|
console.log("Specific close handler for", rpc.name, res.uid, unhookRes)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}`)
|
}`)
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ const frontendConf = {
|
|||||||
target: "web",
|
target: "web",
|
||||||
entry: path.resolve(__dirname, '..', 'js', 'src', 'Frontend.js'),
|
entry: path.resolve(__dirname, '..', 'js', 'src', 'Frontend.js'),
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, '..', 'js', 'src'),
|
path: path.resolve(__dirname, '..', 'js', 'rpclibrary.browser.js'),
|
||||||
filename: "Frontend.js",
|
filename: "Frontend.js",
|
||||||
libraryTarget: 'commonjs',
|
libraryTarget: 'commonjs',
|
||||||
},
|
},
|
||||||
|
|||||||
+28
-3
@@ -1,11 +1,36 @@
|
|||||||
import { Server } from '../src/Backend'
|
import { Server } from '../src/Backend'
|
||||||
|
import { SubscriptionResponse } from '../src/Responses'
|
||||||
|
|
||||||
|
let subcallback
|
||||||
|
|
||||||
new Server(20000, [{
|
new Server(20000, [{
|
||||||
name: "HelloWorldRPCGroup",
|
name: "HelloWorldRPCGroup",
|
||||||
publicRPCs: () => [],
|
exportRPCs: () => [{
|
||||||
localRPCs: () => [{
|
|
||||||
type: 'Call',
|
type: 'Call',
|
||||||
name: 'echo',
|
name: 'echo',
|
||||||
call: async (s:string) => s,
|
call: async (s:string) => s,
|
||||||
}]
|
},
|
||||||
|
{
|
||||||
|
type: 'Hook',
|
||||||
|
name: 'subscribe',
|
||||||
|
hook: async (callback):Promise<any> => {
|
||||||
|
subcallback = callback
|
||||||
|
return new SubscriptionResponse(""+Math.random())
|
||||||
|
},
|
||||||
|
unhook: async (uid):Promise<any> => { subcallback = null }
|
||||||
|
},
|
||||||
|
function add(...args:number[]):number {return args.reduce((a,b)=>a+b, 0)},
|
||||||
|
function triggerCallback(message):number {return subcallback(message)},
|
||||||
|
]
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
try{
|
||||||
|
new Server(20001, [{
|
||||||
|
name: "bad",
|
||||||
|
exportRPCs: () => [
|
||||||
|
(aaa,bbb,ccc) => { return aaa+bbb+ccc }
|
||||||
|
]
|
||||||
|
}])
|
||||||
|
}catch(badRPCError){
|
||||||
|
console.log("expected bad-RPC error happened: "+ !!badRPCError)
|
||||||
|
}
|
||||||
+21
-4
@@ -1,7 +1,24 @@
|
|||||||
import { Client } from '../src/Frontend'
|
import { Client } from '../src/Frontend'
|
||||||
|
console.log(Client)
|
||||||
const client = new Client(20000, 'localhost')
|
const client = new Client(20000, 'localhost')
|
||||||
client.connect().then(_ => {
|
client.connect().then(async _ => {
|
||||||
client.info().then(console.log)
|
await client.info().then(console.log)
|
||||||
client["HelloWorldRPCGroup"].echo("x").then(console.log)
|
|
||||||
|
await client["HelloWorldRPCGroup"].echo("x")
|
||||||
|
.then(hopefullyX => console.log("echo('x') returned x: ", hopefullyX === "x", hopefullyX))
|
||||||
|
|
||||||
|
await client["HelloWorldRPCGroup"].add(1,2,3)
|
||||||
|
.then(hopefully6 => console.log("add(1,2,3) returned 6: ", hopefully6 === 6, hopefully6))
|
||||||
|
|
||||||
|
let counter = 0
|
||||||
|
const handler = (s) => {
|
||||||
|
counter++
|
||||||
|
if(counter === 3)
|
||||||
|
console.log("callback was called 3 times", counter === 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
await client["HelloWorldRPCGroup"].subscribe(handler)
|
||||||
|
client["HelloWorldRPCGroup"].triggerCallback("test1")
|
||||||
|
client["HelloWorldRPCGroup"].triggerCallback("test2")
|
||||||
|
client["HelloWorldRPCGroup"].triggerCallback("test3")
|
||||||
})
|
})
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<script src="../lib/RPCaller.min.js"></script>
|
||||||
Reference in New Issue
Block a user