parent
8dac30d2a1
commit
88d004d3cb
@ -0,0 +1,88 @@ |
||||
import { isWs } from '@harmony/utils'; |
||||
import mitt from 'mitt'; |
||||
import { BaseProvider } from './baseProvider'; |
||||
|
||||
export const enum SocketConnection { |
||||
READY = 'ready', |
||||
CONNECT = 'connect', |
||||
ERROR = 'error', |
||||
CLOSE = 'close', |
||||
} |
||||
|
||||
export const enum SocketState { |
||||
SOCKET_MESSAGE = 'socket_message', |
||||
SOCKET_READY = 'socket_ready', |
||||
SOCKET_CLOSE = 'socket_close', |
||||
SOCKET_ERROR = 'socket_error', |
||||
SOCKET_CONNECT = 'socket_connect', |
||||
SOCKET_NETWORK_CHANGED = 'socket_networkChanged', |
||||
SOCKET_ACCOUNTS_CHANGED = 'socket_accountsChanged', |
||||
} |
||||
|
||||
class BaseSocket extends BaseProvider { |
||||
url: string; |
||||
emitter: mitt.Emitter; |
||||
subscriptions: any = {}; |
||||
handlers: any = {}; |
||||
constructor(url: string) { |
||||
super(url); |
||||
if (!isWs(url)) { |
||||
throw new Error(`${url} is not websocket`); |
||||
} |
||||
this.url = url; |
||||
this.emitter = new mitt(this.handlers); |
||||
} |
||||
resetHandlers() { |
||||
// tslint:disable-next-line: forin
|
||||
for (const i in this.handlers) { |
||||
delete this.handlers[i]; |
||||
} |
||||
} |
||||
|
||||
once(type: string, handler: mitt.Handler) { |
||||
this.emitter.on(type, handler); |
||||
this.removeListener(type); |
||||
} |
||||
|
||||
removeListener(type?: string, handler?: mitt.Handler) { |
||||
if (!type) { |
||||
this.handlers = {}; |
||||
return; |
||||
} |
||||
if (!handler) { |
||||
delete this.handlers[type]; |
||||
} else { |
||||
return this.emitter.off(type, handler); |
||||
} |
||||
} |
||||
reset() { |
||||
this.removeListener('*'); |
||||
// this.registerEventListeners();
|
||||
} |
||||
removeAllSocketListeners() { |
||||
this.removeListener(SocketState.SOCKET_MESSAGE); |
||||
this.removeListener(SocketState.SOCKET_READY); |
||||
this.removeListener(SocketState.SOCKET_CLOSE); |
||||
this.removeListener(SocketState.SOCKET_ERROR); |
||||
this.removeListener(SocketState.SOCKET_CONNECT); |
||||
} |
||||
|
||||
onReady(event: any) { |
||||
this.emitter.on(SocketConnection.READY, () => event); |
||||
this.emitter.on(SocketState.SOCKET_READY, () => event); |
||||
} |
||||
onError(error: any) { |
||||
this.emitter.on(SocketConnection.ERROR, () => error); |
||||
this.emitter.on(SocketState.SOCKET_ERROR, () => error); |
||||
this.removeAllSocketListeners(); |
||||
this.removeListener('*'); |
||||
} |
||||
onClose(error = null) { |
||||
this.emitter.on(SocketConnection.CLOSE, () => error); |
||||
this.emitter.on(SocketState.SOCKET_CLOSE, () => error); |
||||
this.removeAllSocketListeners(); |
||||
this.removeListener('*'); |
||||
} |
||||
} |
||||
|
||||
export { BaseSocket }; |
@ -0,0 +1,86 @@ |
||||
// TODO: implement Websocket Provider
|
||||
import { w3cwebsocket as W3CWebsocket } from 'websocket'; |
||||
import { BaseSocket } from './baseSocket'; |
||||
import { isWs } from '@harmony/utils'; |
||||
import { JsonRpc } from '../rpcMethod/rpcbuilder'; |
||||
import { composeMiddleware } from '../rpcMethod/net'; |
||||
import { RPCRequestPayload } from '../types'; |
||||
|
||||
class WSProvider extends BaseSocket { |
||||
url: string; |
||||
subscriptions: any = {}; |
||||
options: any = {}; |
||||
connection: W3CWebsocket | WebSocket; |
||||
jsonRpc: JsonRpc; |
||||
// ws: w3cwebsocket;
|
||||
constructor(url: string, options: any = {}) { |
||||
super(url); |
||||
if (!isWs(url)) { |
||||
throw new Error(`${url} is not websocket`); |
||||
} |
||||
this.url = url; |
||||
this.options = options; |
||||
this.connection = this.createWebsocketProvider(this.url, this.options); |
||||
this.jsonRpc = new JsonRpc(); |
||||
} |
||||
|
||||
createWebsocketProvider(url: string, options: any = {}) { |
||||
// tslint:disable-next-line: no-string-literal
|
||||
if (typeof window !== 'undefined' && (<any>window).WebSocket) { |
||||
// tslint:disable-next-line: no-string-literal
|
||||
return new WebSocket(url, options.protocol); |
||||
} else { |
||||
const headers = options.headers || {}; |
||||
const urlObject = new URL(url); |
||||
|
||||
if (!headers.authorization && urlObject.username && urlObject.password) { |
||||
const authToken = Buffer.from( |
||||
`${urlObject.username}:${urlObject.password}`, |
||||
).toString('base64'); |
||||
headers.authorization = `Basic ${authToken}`; |
||||
} |
||||
|
||||
return new W3CWebsocket( |
||||
url, |
||||
options.protocol, |
||||
undefined, |
||||
headers, |
||||
undefined, |
||||
options.clientConfig, |
||||
); |
||||
} |
||||
} |
||||
|
||||
get connected() { |
||||
return this.connection.readyState === this.connection.OPEN; |
||||
} |
||||
|
||||
isConnecting() { |
||||
return this.connection.readyState === this.connection.CONNECTING; |
||||
} |
||||
|
||||
send(payload: RPCRequestPayload<object>): Promise<any> { |
||||
const [tReq, tRes] = this.getMiddleware(payload.method); |
||||
const reqMiddleware = composeMiddleware(...tReq); |
||||
const resMiddleware = composeMiddleware(...tRes); |
||||
|
||||
return new Promise((resolve, reject) => { |
||||
this.connection.send(reqMiddleware(JSON.stringify(payload))); |
||||
this.connection.onmessage = (msg: MessageEvent) => { |
||||
if (msg && msg.data) { |
||||
let result; |
||||
try { |
||||
result = JSON.parse(msg.data); |
||||
resolve(resMiddleware(result)); |
||||
} catch (error) { |
||||
reject(error); |
||||
} |
||||
} else { |
||||
reject('provider error'); |
||||
} |
||||
}; |
||||
}); |
||||
} |
||||
} |
||||
|
||||
export { WSProvider }; |
@ -0,0 +1,4 @@ |
||||
export interface Window { |
||||
WebSocket: any; |
||||
MozWebSocket: any; |
||||
} |
Loading…
Reference in new issue