mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-06-16 18:29:08 +00:00
[bot] break out RPC and shared packages for bot service breakout
This commit is contained in:
parent
544ae65c58
commit
50b5e334a3
31 changed files with 233 additions and 111 deletions
14
packages/roleypoly-rpc-client/.babelrc
Normal file
14
packages/roleypoly-rpc-client/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"presets": [ ["@babel/preset-env", {
|
||||
"targets": {
|
||||
"node": true
|
||||
}
|
||||
}], "@babel/preset-flow" ],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-optional-chaining",
|
||||
["@babel/plugin-transform-runtime",
|
||||
{ "helpers": false }]
|
||||
]
|
||||
}
|
21
packages/roleypoly-rpc-client/error.js
Normal file
21
packages/roleypoly-rpc-client/error.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
// @flow
|
||||
import type { RPCResponse } from './index'
|
||||
|
||||
class RPCError extends Error {
|
||||
code: ?number
|
||||
extra: any[]
|
||||
remoteStack: ?string
|
||||
constructor (msg: string, code?: number, ...extra: any[]) {
|
||||
super(msg)
|
||||
this.code = code
|
||||
this.extra = extra
|
||||
}
|
||||
|
||||
static fromResponse (body: RPCResponse, status: number) {
|
||||
const e = new RPCError(body.msg, status)
|
||||
e.remoteStack = body.trace
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RPCError
|
127
packages/roleypoly-rpc-client/index.js
Normal file
127
packages/roleypoly-rpc-client/index.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
// @flow
|
||||
import superagent from 'superagent'
|
||||
import RPCError from './error'
|
||||
|
||||
export type RPCResponse = {
|
||||
response?: mixed,
|
||||
hash?: string,
|
||||
|
||||
// error stuff
|
||||
error?: boolean,
|
||||
msg: string,
|
||||
trace?: string
|
||||
}
|
||||
|
||||
export type RPCRequest = {
|
||||
fn: string,
|
||||
args: mixed[]
|
||||
}
|
||||
|
||||
export default class RPCClient {
|
||||
dev: boolean = false
|
||||
baseUrl: string
|
||||
firstKnownHash: string
|
||||
recentHash: string
|
||||
cookieHeader: string
|
||||
|
||||
headerMixins: {
|
||||
[x:string]: string
|
||||
} = {}
|
||||
|
||||
rpc: {
|
||||
[fn: string]: (...args: any[]) => Promise<any>
|
||||
} = {}
|
||||
|
||||
__rpcAvailable: Array<{
|
||||
name: string,
|
||||
args: number
|
||||
}> = []
|
||||
|
||||
constructor ({ forceDev, baseUrl = '/api/_rpc' }: { forceDev?: boolean, baseUrl?: string } = {}) {
|
||||
this.baseUrl = (process.env.APP_URL || '') + baseUrl
|
||||
|
||||
if (forceDev != null) {
|
||||
this.dev = forceDev
|
||||
} else {
|
||||
this.dev = process.env.NODE_ENV === 'development'
|
||||
}
|
||||
|
||||
this.rpc = new Proxy({}, {
|
||||
get: this.__rpcCall,
|
||||
has: this.__checkCall,
|
||||
ownKeys: this.__listCalls,
|
||||
delete: () => {}
|
||||
})
|
||||
|
||||
if (this.dev) {
|
||||
this.updateCalls()
|
||||
}
|
||||
}
|
||||
|
||||
withCookies = (h: string) => {
|
||||
this.headerMixins['Set-Cookie'] = h
|
||||
return this.rpc
|
||||
}
|
||||
|
||||
withBotAuth = (h: string) => {
|
||||
this.headerMixins['Authorization'] = `Bot ${h}`
|
||||
return this.rpc
|
||||
}
|
||||
|
||||
async updateCalls () {
|
||||
// this is for development only. doing in prod is probably dumb.
|
||||
const rsp = await superagent.get(this.baseUrl)
|
||||
if (rsp.status !== 200) {
|
||||
console.error(rsp)
|
||||
return
|
||||
}
|
||||
|
||||
const { hash, available } = rsp.body
|
||||
|
||||
this.__rpcAvailable = available
|
||||
if (this.firstKnownHash == null) {
|
||||
this.firstKnownHash = hash
|
||||
}
|
||||
|
||||
this.recentHash = hash
|
||||
|
||||
// just kinda prefill. none of these get called anyway.
|
||||
// and don't matter in prod either.
|
||||
for (let { name } of available) {
|
||||
this.rpc[name] = async () => {}
|
||||
}
|
||||
}
|
||||
|
||||
async call (fn: string, ...args: any[]): mixed {
|
||||
const req: RPCRequest = { fn, args }
|
||||
const rq = superagent.post(this.baseUrl).set({ ...this.headerMixins })
|
||||
|
||||
const rsp = await rq.send(req).ok(() => true)
|
||||
const body: RPCResponse = rsp.body
|
||||
|
||||
// console.log(body)
|
||||
if (body.error === true) {
|
||||
console.error(body)
|
||||
throw RPCError.fromResponse(body, rsp.status)
|
||||
}
|
||||
|
||||
if (body.hash != null) {
|
||||
if (this.firstKnownHash == null) {
|
||||
this.firstKnownHash = body.hash
|
||||
}
|
||||
|
||||
this.recentHash = body.hash
|
||||
|
||||
if (this.firstKnownHash !== this.recentHash) {
|
||||
this.updateCalls()
|
||||
}
|
||||
}
|
||||
|
||||
return body.response
|
||||
}
|
||||
|
||||
// PROXY HANDLERS
|
||||
__rpcCall = (_: {}, fn: string) => this.call.bind(this, fn)
|
||||
__checkCall = (_: {}, fn: string) => this.dev ? this.__listCalls(_).includes(fn) : true
|
||||
__listCalls = (_: {}): string[] => this.__rpcAvailable.map(x => x.name)
|
||||
}
|
16
packages/roleypoly-rpc-client/package.json
Normal file
16
packages/roleypoly-rpc-client/package.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "@roleypoly/rpc-client",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"postinstall": "yarn build",
|
||||
"build": "babel --delete-dir-on-start -d lib ."
|
||||
},
|
||||
"main": "./lib/index.js",
|
||||
"dependencies": {
|
||||
"superagent":"^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.4.3"
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue