WebSocket has been implemented.
This commit is contained in:
parent
2c1a524dde
commit
f461d42744
|
@ -79,6 +79,7 @@
|
|||
"redux": "^3.7.1",
|
||||
"redux-saga": "^0.15.4",
|
||||
"reselect": "^3.0.1",
|
||||
"semantic-ui-css":"^2.2.10",
|
||||
"semantic-ui-react": "^0.70.0",
|
||||
"socket.io-client": "^2.0.3"
|
||||
},
|
||||
|
|
|
@ -4,7 +4,6 @@ import { fork } from 'redux-saga/effects';
|
|||
|
||||
import { Provider } from 'react-redux';
|
||||
import { ConnectedRouter } from 'react-router-redux';
|
||||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
||||
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
||||
|
||||
|
||||
|
@ -20,8 +19,6 @@ injectTapEventPlugin();
|
|||
function* app(): any {
|
||||
const appContainer: HTMLElement = yield Platform.getAppContainer('react-placeholder');
|
||||
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<div style={{
|
||||
width: '100vw',
|
||||
|
@ -40,14 +37,13 @@ function* app(): any {
|
|||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<MuiThemeProvider muiTheme={muiTheme}>
|
||||
<ConnectedRouter history={history}>
|
||||
{routes}
|
||||
</ConnectedRouter>
|
||||
</MuiThemeProvider>
|
||||
</Provider>,
|
||||
appContainer,
|
||||
);
|
||||
}
|
||||
|
||||
sagaMiddleware.run(app);
|
||||
|
||||
|
|
136
src/ts/@overflow/commons/websocket/WebSocketRPC.ts
Normal file
136
src/ts/@overflow/commons/websocket/WebSocketRPC.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
import {
|
||||
ProtocolNotification,
|
||||
ProtocolRequest,
|
||||
ProtocolResponse,
|
||||
} from './protocol';
|
||||
|
||||
import {
|
||||
PROTOCOL_NAME as RPCProtocol,
|
||||
RPCRequest,
|
||||
RPCResponse,
|
||||
} from './protocol/rpc';
|
||||
|
||||
|
||||
export type OnConnectFunc = () => void;
|
||||
export type OnDisconnectFunc = () => void;
|
||||
export type OnResponseFunc = (response: any) => void;
|
||||
|
||||
type ID_TYPE = number;
|
||||
|
||||
interface RequestQueue {
|
||||
resolve: (value?: any) => void;
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
|
||||
export default class WebSocketRPC {
|
||||
private url: string;
|
||||
private conn: WebSocket;
|
||||
private isReady: boolean;
|
||||
private requestID: ID_TYPE = 0;
|
||||
|
||||
private onConnectListeners: OnConnectFunc[] = [];
|
||||
private onDisconnectListeners: OnDisconnectFunc[] = [];
|
||||
private onResponseListeners: Map<string, OnResponseFunc[]>;
|
||||
|
||||
private requestQueue: Map<ID_TYPE, RequestQueue>;
|
||||
/**
|
||||
* name
|
||||
*/
|
||||
public constructor(url: string) {
|
||||
this.isReady = false;
|
||||
this.url = url;
|
||||
this.onResponseListeners = new Map();
|
||||
this.requestQueue = new Map();
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
public Call(method: string, params: any[]): Promise<any> {
|
||||
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
const requestID = this.getRequestID();
|
||||
let request = new ProtocolRequest<ID_TYPE>(RPCProtocol, requestID);
|
||||
let req = new RPCRequest(method, params);
|
||||
request.setBody(req.toJSON());
|
||||
this.conn.send(request.toJSON());
|
||||
this.requestQueue.set(requestID, {resolve: resolve, reject: reject});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public OnConnect(cb: OnConnectFunc): void {
|
||||
if (this.isReady) {
|
||||
cb();
|
||||
}
|
||||
this.onConnectListeners.push(cb);
|
||||
}
|
||||
|
||||
public OnDisconnect(cb: OnDisconnectFunc): void {
|
||||
this.onDisconnectListeners.push(cb);
|
||||
}
|
||||
|
||||
private initialize(): void {
|
||||
this.conn = new WebSocket(this.url);
|
||||
this.conn.onopen = (e: Event): any => {
|
||||
this.fireOnConnect();
|
||||
this.isReady = true;
|
||||
return null;
|
||||
};
|
||||
|
||||
this.conn.onclose = (e: CloseEvent): any => {
|
||||
this.fireOnDisconnect();
|
||||
return null;
|
||||
};
|
||||
|
||||
this.conn.onmessage = (e: MessageEvent): any => {
|
||||
let response: ProtocolResponse<ID_TYPE> = JSON.parse(e.data);
|
||||
let res: RPCResponse = JSON.parse(response.getBody());
|
||||
const requestID = response.getID();
|
||||
const error = response.getError();
|
||||
const result = res.getResult();
|
||||
|
||||
if (this.requestQueue.has(requestID)) {
|
||||
let promise = this.requestQueue.get(requestID);
|
||||
this.requestQueue.delete(requestID);
|
||||
if (null != result) {
|
||||
promise.resolve(result);
|
||||
} else if (null != error) {
|
||||
promise.reject(error);
|
||||
} else {
|
||||
console.log('??????');
|
||||
}
|
||||
} else {
|
||||
// perhaps sever side send message
|
||||
}
|
||||
|
||||
this.fireOnMessage(e);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private fireOnConnect(): void {
|
||||
for (let i = 0; i < this.onConnectListeners.length; i++) {
|
||||
this.onConnectListeners[i]();
|
||||
}
|
||||
}
|
||||
|
||||
private fireOnDisconnect(): void {
|
||||
for (let i = 0; i < this.onDisconnectListeners.length; i++) {
|
||||
this.onDisconnectListeners[i]();
|
||||
}
|
||||
}
|
||||
|
||||
private fireOnMessage(e: MessageEvent): void {
|
||||
|
||||
|
||||
for (let i = 0; i < this.onDisconnectListeners.length; i++) {
|
||||
this.onDisconnectListeners[i]();
|
||||
}
|
||||
}
|
||||
|
||||
private getRequestID(): number {
|
||||
return ++this.requestID;
|
||||
}
|
||||
|
||||
}
|
46
src/ts/@overflow/commons/websocket/protocol/ProtocolError.ts
Normal file
46
src/ts/@overflow/commons/websocket/protocol/ProtocolError.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
export const enum ErrorCode {
|
||||
E_PARSE = -32700,
|
||||
E_INVALID_REQ = -32600,
|
||||
E_NO_METHOD = -32601,
|
||||
E_BAD_PARAMS = -32602,
|
||||
E_INTERNAL = -32603,
|
||||
E_SERVER = -32000,
|
||||
|
||||
}
|
||||
|
||||
export class ProtocolError {
|
||||
private code: ErrorCode;
|
||||
private message: string;
|
||||
private data: any;
|
||||
|
||||
public constructor(code: ErrorCode, message: string, data: any) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* getID
|
||||
*/
|
||||
public getCode(): ErrorCode {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* getBody
|
||||
*/
|
||||
public getMessage(): string {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
/**
|
||||
* getError
|
||||
*/
|
||||
public getData(): any {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public static newError(json: string): ProtocolError {
|
||||
return JSON.parse(json);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
export class ProtocolHeader<ID> {
|
||||
private readonly protocol: string;
|
||||
private readonly id: ID;
|
||||
private body: string;
|
||||
|
||||
public constructor(protocol: string, id: ID) {
|
||||
this.protocol = protocol;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* getProtocol
|
||||
*/
|
||||
public getProtocol(): string {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* getID
|
||||
*/
|
||||
public getID(): ID {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* setID
|
||||
*/
|
||||
public setBody(body: string): void {
|
||||
this.body = body;
|
||||
}
|
||||
/**
|
||||
* getID
|
||||
*/
|
||||
public getBody(): string {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
/**
|
||||
* toJSON
|
||||
*/
|
||||
public toJSON(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
export class ProtocolNotification {
|
||||
private readonly protocol: string;
|
||||
private body: string;
|
||||
|
||||
public constructor(protocol: string) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* getProtocol
|
||||
*/
|
||||
public getProtocol(): string {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* setBody
|
||||
*/
|
||||
public setBody(body: string): void {
|
||||
this.body = body;
|
||||
}
|
||||
/**
|
||||
* getBody
|
||||
*/
|
||||
public getBody(): string {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
/**
|
||||
* toJSON
|
||||
*/
|
||||
public toJSON(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { ProtocolHeader } from './ProtocolHeader';
|
||||
|
||||
export class ProtocolRequest<ID> extends ProtocolHeader<ID> {
|
||||
public constructor(protocol: string, id: ID) {
|
||||
super(protocol, id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { ProtocolHeader } from './ProtocolHeader';
|
||||
import { ProtocolError } from './ProtocolError';
|
||||
|
||||
export class ProtocolResponse<ID> extends ProtocolHeader<ID> {
|
||||
private error: ProtocolError;
|
||||
|
||||
public constructor(protocol: string, id: ID) {
|
||||
super(protocol, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* setError
|
||||
*/
|
||||
public setError(error: ProtocolError): void {
|
||||
this.error = error;
|
||||
}
|
||||
/**
|
||||
* getError
|
||||
*/
|
||||
public getError(): ProtocolError {
|
||||
return this.error;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export abstract class ProtocolSub {
|
||||
/**
|
||||
* toJSON
|
||||
*/
|
||||
public abstract toJSON(): string;
|
||||
}
|
6
src/ts/@overflow/commons/websocket/protocol/index.ts
Normal file
6
src/ts/@overflow/commons/websocket/protocol/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export * from './ProtocolError';
|
||||
export * from './ProtocolHeader';
|
||||
export * from './ProtocolNotification';
|
||||
export * from './ProtocolRequest';
|
||||
export * from './ProtocolResponse';
|
||||
export * from './ProtocolSub';
|
|
@ -0,0 +1,33 @@
|
|||
import { ProtocolSub } from '../ProtocolSub';
|
||||
|
||||
export class RPCRequest extends ProtocolSub {
|
||||
private readonly method: string;
|
||||
private readonly params: any[];
|
||||
|
||||
public constructor(method: string, params: any[]) {
|
||||
super();
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMethod
|
||||
*/
|
||||
public getMethod(): string {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
/**
|
||||
* getParams
|
||||
*/
|
||||
public getParams(): any[] {
|
||||
return this.params;
|
||||
}
|
||||
|
||||
/**
|
||||
* toJSON
|
||||
*/
|
||||
public toJSON(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { ProtocolSub } from '../ProtocolSub';
|
||||
|
||||
export class RPCResponse extends ProtocolSub {
|
||||
private readonly result: any;
|
||||
|
||||
public constructor(result: any) {
|
||||
super();
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* getResult
|
||||
*/
|
||||
public getResult(): any {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
/**
|
||||
* toJSON
|
||||
*/
|
||||
public toJSON(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
5
src/ts/@overflow/commons/websocket/protocol/rpc/index.ts
Normal file
5
src/ts/@overflow/commons/websocket/protocol/rpc/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export * from './RPCRequest';
|
||||
export * from './RPCResponse';
|
||||
|
||||
export const PROTOCOL_NAME = 'jsonrpc';
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import Service from '@overflow/commons/api/Service';
|
||||
import Member from '../model/Member';
|
||||
|
||||
@ServiceClass
|
||||
export class MemberService extends Service {
|
||||
|
||||
public constructor() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": "src/ts",
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
|
@ -11,7 +11,7 @@
|
|||
"es5",
|
||||
"es6"
|
||||
],
|
||||
"module": "esnext",
|
||||
"module": "umd",
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"noImplicitAny": false,
|
||||
|
@ -19,6 +19,12 @@
|
|||
"outDir": "dist/ts/",
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"paths": {
|
||||
"*": [
|
||||
"./src/ts/*",
|
||||
"./types/*"
|
||||
]
|
||||
},
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"target": "es5",
|
||||
|
@ -34,6 +40,7 @@
|
|||
"build",
|
||||
"config",
|
||||
"node_modules",
|
||||
"public"
|
||||
"public",
|
||||
"types"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user