fix
This commit is contained in:
@@ -1,11 +1,49 @@
|
||||
import { SubscriptionResponse, SuccessResponse, ErrorResponse } from "../../../../vendor/generic/Types";
|
||||
import http = require('http');
|
||||
import bsock = require('bsock');
|
||||
|
||||
import * as uuid from "uuid/v4"
|
||||
import { Socket } from "./RPCSocketServer"
|
||||
|
||||
type rpcType = 'hook' | 'unhook' | 'call'
|
||||
type visibility = 'public' | 'private'
|
||||
|
||||
export type Outcome = "Success" | "Error"
|
||||
|
||||
/* Responses */
|
||||
export class Response{
|
||||
constructor(
|
||||
public message?:string
|
||||
){}
|
||||
}
|
||||
|
||||
export class SuccessResponse extends Response{
|
||||
result:Outcome = "Success"
|
||||
|
||||
constructor(
|
||||
message?:string
|
||||
){
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
export class ErrorResponse extends Response{
|
||||
result:Outcome = "Error"
|
||||
|
||||
constructor(
|
||||
message: string = "Unknown error"
|
||||
){
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
export class SubscriptionResponse extends SuccessResponse{
|
||||
constructor(
|
||||
public uid: string,
|
||||
message?:string
|
||||
){
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
export type UnhookFunction = (uid:string) => Promise<SuccessResponse | ErrorResponse>
|
||||
export type callbackFunction = (...args) => Promise<SubscriptionResponse | ErrorResponse>
|
||||
export type AsyncFunction = (...args) => Promise<any>
|
||||
@@ -98,7 +136,7 @@ export const rpcToRpcinfo = (rpc : socketioRPC, owner: string):RpcInfo => {
|
||||
}
|
||||
}
|
||||
|
||||
export const rpcHooker = (socket, owner:string, RPCs: socketioRPC[], makeUnique = true):ExtendedRpcInfo[] => {
|
||||
export const rpcHooker = (socket: Socket, owner:string, RPCs: socketioRPC[], makeUnique = true):ExtendedRpcInfo[] => {
|
||||
const suffix = makeUnique?"-"+uuid().substr(0,4):""
|
||||
return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
|
||||
.map(info => {
|
||||
@@ -137,10 +175,79 @@ const hookGenerator = (rpc:hookRPC): HookInfo['generator'] => {
|
||||
}`)
|
||||
}
|
||||
|
||||
function extractArgs(f:Function):string[]{
|
||||
const extractArgs = (f:Function):string[] => {
|
||||
let fn = String(f)
|
||||
let args = fn.substr(0, fn.indexOf(")"))
|
||||
args = args.substr(fn.indexOf("(")+1)
|
||||
let ret = args.split(",")
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
type OnFunction = (type: 'error' | 'close', f: (e?:any)=>void) => Socket
|
||||
|
||||
export type Socket = {
|
||||
port: number
|
||||
hook: (rpcname: string, ...args: any[]) => Socket
|
||||
unhook: (rpcname:string) => Socket
|
||||
call: (rpcname:string, ...args: any[]) => Promise<any>
|
||||
fire: (rpcname:string, ...args: any[]) => Promise<any>
|
||||
on: OnFunction
|
||||
destroy: ()=>void
|
||||
close: ()=>void
|
||||
}
|
||||
|
||||
export type RPCSocketConf = {
|
||||
connectionHandler: (socket:Socket) => void
|
||||
errorHandler: (socket:Socket) => (error:any) => void
|
||||
closeHandler: (socket:Socket) => () => void
|
||||
}
|
||||
|
||||
export class RPCSocketServer{
|
||||
|
||||
private io = bsock.createServer()
|
||||
private wsServer = http.createServer()
|
||||
|
||||
constructor(
|
||||
private port:number,
|
||||
private rpcExporters: RPCExporter[] = [],
|
||||
private conf: RPCSocketConf = {
|
||||
errorHandler: (socket:Socket) => (error:any) => { socket.destroy(); console.error(error) },
|
||||
closeHandler: (socket:Socket) => () => { console.log("Socket closing") },
|
||||
connectionHandler: (socket:Socket) => { console.log("New websocket connection in port "+socket.port) }
|
||||
}
|
||||
){
|
||||
this.startWebsocket()
|
||||
}
|
||||
|
||||
private startWebsocket(){
|
||||
try{
|
||||
this.io.attach(this.wsServer)
|
||||
this.io.on('socket', (socket:Socket) => {
|
||||
socket.on('error', this.conf.errorHandler(socket))
|
||||
socket.on('close', this.conf.closeHandler(socket))
|
||||
this.initApis(socket)
|
||||
})
|
||||
this.wsServer.listen(this.port)
|
||||
}catch(e){
|
||||
//@ts-ignore
|
||||
this.errorHandler(undefined)("Unable to connect to socket")
|
||||
}
|
||||
}
|
||||
|
||||
protected initApis(socket){
|
||||
const adminRPCs:socketioRPC[] = [
|
||||
{
|
||||
name: 'info',
|
||||
type: 'call',
|
||||
visibility: 'private',
|
||||
func: async () => rpcInfos
|
||||
}
|
||||
]
|
||||
|
||||
const rpcInfos:ExtendedRpcInfo[] = [
|
||||
...rpcHooker(socket, "Admin", adminRPCs, false),
|
||||
...this.rpcExporters.flatMap(exporter => rpcHooker(socket, exporter.name, exporter.exportRPCs()))
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { parseSubResponse, parseResponse } from "frontblock-generic/Types";
|
||||
import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction } from "frontblock-generic/RPC";
|
||||
import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction } from "../backend/RPCSocketServer";
|
||||
var bsock = require('bsock')
|
||||
|
||||
//fix args with defaults like "force = true" -> "force"
|
||||
@@ -7,6 +6,10 @@ function stripAfterEquals(str:string){
|
||||
return str.split("=")[0]
|
||||
}
|
||||
|
||||
type RPCReceiver = {
|
||||
[RPCGroup in string]: any
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic library to communicate with FrontblockService remotely
|
||||
*
|
||||
@@ -14,20 +17,14 @@ function stripAfterEquals(str:string){
|
||||
* Will ask it's service for available RPCs and parse them into methods of this object
|
||||
* for convenient access.
|
||||
*/
|
||||
export class RPCallable{
|
||||
export class RPCaller implements RPCReceiver{
|
||||
private socket
|
||||
|
||||
constructor(){
|
||||
this.socket = bsock.connect(20000, 'localhost', false/*tls*/)
|
||||
this.init()
|
||||
constructor(port:number, server: string, tls: boolean = false){
|
||||
this.socket = bsock.connect(port, server, tls)
|
||||
}
|
||||
|
||||
// need this-context for eval-magic below
|
||||
// DO NOT REMOVE. They're not really unused
|
||||
private parseSubResponse = parseSubResponse
|
||||
private parseResponse = parseResponse
|
||||
|
||||
private async init(){
|
||||
async connect(){
|
||||
const info:ExtendedRpcInfo[] = await this.info()
|
||||
info.forEach(i => {
|
||||
let f: any
|
||||
@@ -64,8 +61,7 @@ export class RPCallable{
|
||||
const argParams = fnArgs.map(stripAfterEquals).join(",")
|
||||
return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
|
||||
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
||||
const res = await this.parseSubResponse(r);
|
||||
if(res.uid != null){
|
||||
if(r.uid != null){
|
||||
this.socket.hook(res.uid, callback)
|
||||
}
|
||||
return res
|
||||
@@ -80,12 +76,9 @@ export class RPCallable{
|
||||
|
||||
return eval( `( () => async (`+headerArgs+`) => {
|
||||
const r = await this.socket.call("`+fnName+`", `+argParams+`)
|
||||
const res = await this.parseResponse(r)
|
||||
this.socket.unhook(`+argParams+`)
|
||||
return res
|
||||
} )()` )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window['rpc'] = new RPCallable()
|
||||
}
|
||||
@@ -4,10 +4,10 @@ const TerserPlugin = require('terser-webpack-plugin');
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
target: "web",
|
||||
entry: path.resolve(__dirname, 'module.ts'),
|
||||
entry: path.resolve(__dirname, 'RPCaller.ts'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, '../../dist'),
|
||||
filename: 'FrontendPlugin.js',
|
||||
path: path.resolve(__dirname, '../../lib'),
|
||||
filename: 'RPCaller.min.js',
|
||||
libraryTarget: 'commonjs',
|
||||
},
|
||||
resolve: {
|
||||
@@ -30,11 +30,5 @@ module.exports = {
|
||||
],
|
||||
},
|
||||
externals: {
|
||||
'@angular/core': '@angular/core',
|
||||
'@angular/common': '@angular/common',
|
||||
'@angular/router': '@angular/router',
|
||||
'@angular/animations': '@angular/animations',
|
||||
'@angular/forms': '@angular/forms',
|
||||
'@clr/angular': '@clr/angular'
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user