diff --git a/src/ts/@overflow/app/router/index.tsx b/src/ts/@overflow/app/router/index.tsx index 70ee64a..e5afd67 100644 --- a/src/ts/@overflow/app/router/index.tsx +++ b/src/ts/@overflow/app/router/index.tsx @@ -5,11 +5,124 @@ import Signin from '../views/member/Signin'; const routes = ( + - - + ); export default routes; + +const _routes = [ + { + path: '/signin', + component: Signin, + }, + { + path: '/signup', + component: Signup, + }, + { + path: '/forgot_password', + component: ForgotPassword, + }, + { + path: '/email_confirm', + component: EmailConfirm, + }, + { + path: '/', + component: Home, + routes: [ + { + path: '/monitoring', + component: Monitoring, + routes: [ + { + path: '/probe', + component: Probe, + routes: [ + { + path: '/list', + component: Probe, + }, + { + path: '/noauth', + component: NoAuthProbe, + }, + { + path: '/setup', + component: ProbeSetup, + }, + ], + }, + { + path: '/sensor', + component: Sensor, + }, + ], + }, + { + path: '/infrastructure', + component: , + routes: [ + { + path: '/maps', + component: InfrastructureMaps, + }, + { + path: '/targets', + component: Targets, + }, + ], + }, + { + path: '/dashboard', + component: Dashboard, + }, + { + path: '/metrics', + component: Metrics, + }, + { + path: '/alerts', + component: Alerts, + }, + { + path: '/history', + component: History, + }, + { + path: '/settings', + component: Settings, + }, + { + path: '/notifications', + component: Notifications, + }, + { + path: '/account', + component: , + routes: [ + { + path: '/signout', + component: Signout, + }, + { + path: '/profile', + component: Profile, + }, + { + path: '/preferences', + component: Preferences, + }, + { + path: '/help', + component: Help, + }, + ], + }, + ], + }, +]; diff --git a/src/ts/@overflow/app/views/Home.tsx b/src/ts/@overflow/app/views/Home.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/alert/Alert.tsx b/src/ts/@overflow/app/views/alert/Alert.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/dashboard/Dashboard.tsx b/src/ts/@overflow/app/views/dashboard/Dashboard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/help/Help.tsx b/src/ts/@overflow/app/views/help/Help.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/history/History.tsx b/src/ts/@overflow/app/views/history/History.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/infrastructure/maps/Maps.tsx b/src/ts/@overflow/app/views/infrastructure/maps/Maps.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/infrastructure/target/List.tsx b/src/ts/@overflow/app/views/infrastructure/target/List.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/member/EmailConfirm.tsx b/src/ts/@overflow/app/views/member/EmailConfirm.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/member/ForgotPassword.tsx b/src/ts/@overflow/app/views/member/ForgotPassword.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/member/Signout.tsx b/src/ts/@overflow/app/views/member/Signout.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/member/Signup.tsx b/src/ts/@overflow/app/views/member/Signup.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/metric/Metric.tsx b/src/ts/@overflow/app/views/metric/Metric.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/monitoring/probe/List.tsx b/src/ts/@overflow/app/views/monitoring/probe/List.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/monitoring/probe/NoAuth.tsx b/src/ts/@overflow/app/views/monitoring/probe/NoAuth.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/monitoring/probe/Setup.tsx b/src/ts/@overflow/app/views/monitoring/probe/Setup.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/monitoring/sensor/List.tsx b/src/ts/@overflow/app/views/monitoring/sensor/List.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/notification/Notification.tsx b/src/ts/@overflow/app/views/notification/Notification.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/app/views/setting/Setting.tsx b/src/ts/@overflow/app/views/setting/Setting.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/commons/api/Client.ts b/src/ts/@overflow/commons/api/Client.ts index de07fea..1d70be4 100644 --- a/src/ts/@overflow/commons/api/Client.ts +++ b/src/ts/@overflow/commons/api/Client.ts @@ -1,13 +1,256 @@ +export type OnConnectFunc = () => void; +export type OnWebsocketDisconnectFunc = () => void; +export type OnWebsocketNativeMessageFunc = (websocketMessage: string) => void; +export type OnMessageFunc = (message: any) => void; + +enum MessageType { + STRING = 1, + INT, + BOOLEAN, + JSON, +} + class Client { - private wss: WebSocket; + private conn: WebSocket; + private isReady: boolean; + // events listeners + private connectListeners: OnConnectFunc[] = []; + private disconnectListeners: OnWebsocketDisconnectFunc[] = []; + private nativeMessageListeners: OnWebsocketNativeMessageFunc[] = []; + private messageListeners: { [event: string]: OnMessageFunc[] } = {}; + + constructor(endpoint: string, protocols?: string[]) { + // if (!window.WebSocket) { + // return; + // } + + if (endpoint.indexOf('ws') === -1) { + endpoint = 'ws://' + endpoint; + } + + if (protocols != null && protocols.length > 0) { + this.conn = new WebSocket(endpoint, protocols); + } else { + this.conn = new WebSocket(endpoint); + } + + this.conn.onopen = ((evt: Event): any => { + this.fireConnect(); + this.isReady = true; + return null; + }); + + this.conn.onclose = ((evt: Event): any => { + this.fireDisconnect(); + return null; + }); + + this.conn.onmessage = ((evt: MessageEvent) => { + this.messageReceivedFromConn(evt); + }); + + this.conn.onerror = ((evt: MessageEvent) => { + this.errorReceivedFromConn(evt); + }); + } + + public OnConnect(fn: OnConnectFunc): void { + if (this.isReady) { + fn(); + } + this.connectListeners.push(fn); + } + public OnDisconnect(fn: OnWebsocketDisconnectFunc): void { + this.disconnectListeners.push(fn); + } + public OnMessage(cb: OnWebsocketNativeMessageFunc): void { + this.nativeMessageListeners.push(cb); + } + public On(event: string, cb: OnMessageFunc): void { + if (this.messageListeners[event] == null || this.messageListeners[event] === undefined) { + this.messageListeners[event] = []; + } + this.messageListeners[event].push(cb); + } + + // + + // Ws Actions + public Disconnect(): void { + this.conn.close(); + } + + // EmitMessage sends a native websocket message + public EmitMessage(websocketMessage: string): void { + this.conn.send(websocketMessage); + } + + protected fireConnect(): void { + for (let i = 0; i < this.connectListeners.length; i++) { + this.connectListeners[i](); + } + } + + protected fireDisconnect(): void { + for (let i = 0; i < this.disconnectListeners.length; i++) { + this.disconnectListeners[i](); + } + } + + protected fireNativeMessage(websocketMessage: string): void { + for (let i = 0; i < this.nativeMessageListeners.length; i++) { + this.nativeMessageListeners[i](websocketMessage); + } + } + + protected fireMessage(event: string, message: any): void { + for (let key in this.messageListeners) { + if (this.messageListeners.hasOwnProperty(key)) { + if (key === event) { + for (let i = 0; i < this.messageListeners[key].length; i++) { + this.messageListeners[key][i](message); + } + } + } + } + } + + // utils + private isNumber(obj: any): boolean { + return !isNaN(obj - 0) && obj !== null && obj !== '' && obj !== false; + } + + private isString(obj: any): boolean { + return Object.prototype.toString.call(obj) === '[object String]'; + } + + private isBoolean(obj: any): boolean { + return typeof obj === 'boolean' || + (typeof obj === 'object' && typeof obj.valueOf() === 'boolean'); + } + + private isJSON(obj: any): boolean { + return typeof obj === 'object'; + } + + // + + // messages + private _msg(event: string, messageType: MessageType, dataMessage: string): string { + + return websocketMessagePrefix + event + websocketMessageSeparator + String(websocketMessageType) + websocketMessageSeparator + dataMessage; + } + + private encodeMessage(event: string, data: any): string { + let m = ''; + let t: MessageType = MessageType.STRING; + if (this.isNumber(data)) { + t = MessageType.INT; + m = data.toString(); + } else if (this.isBoolean(data)) { + t = MessageType.BOOLEAN; + m = data.toString(); + } else if (this.isString(data)) { + t = MessageType.STRING; + m = data.toString(); + } else if (this.isJSON(data)) { + // propably json-object + t = MessageType.JSON; + m = JSON.stringify(data); + } else { + console.log('Invalid, javascript-side should contains an empty second parameter.'); + } + + return this._msg(event, t, m); + } + + private decodeMessage(event: string, websocketMessage: string): T | any { + // q-websocket-message;user;4;themarshaledstringfromajsonstruct + let skipLen = websocketMessagePrefixLen + websocketMessageSeparatorLen + event.length + 2; + if (websocketMessage.length < skipLen + 1) { + return null; + } + let websocketMessageType = parseInt(websocketMessage.charAt(skipLen - 2)); + let theMessage = websocketMessage.substring(skipLen, websocketMessage.length); + if (websocketMessageType === MessageType.INT) { + return parseInt(theMessage); + } else if (websocketMessageType === MessageType.BOOLEAN) { + return Boolean(theMessage); + } else if (websocketMessageType === MessageType.STRING) { + return theMessage; + } else if (websocketMessageType === MessageType.JSON) { + return JSON.parse(theMessage); + } else { + return null; // invalid + } + } + + private getWebsocketCustomEvent(websocketMessage: string): string { + if (websocketMessage.length < websocketMessagePrefixAndSepIdx) { + return ''; + } + let s = websocketMessage.substring(websocketMessagePrefixAndSepIdx, websocketMessage.length); + let evt = s.substring(0, s.indexOf(websocketMessageSeparator)); + + return evt; + } + + private getCustomMessage(event: string, websocketMessage: string): string { + let eventIdx = websocketMessage.indexOf(event + websocketMessageSeparator); + let s = websocketMessage.substring(eventIdx + event.length + websocketMessageSeparator.length + 2, websocketMessage.length); + return s; + } + + // + + // Ws Events + + // messageReceivedFromConn this is the func which decides + // if it's a native websocket message or a custom qws message + // if native message then calls the fireNativeMessage + // else calls the fireMessage + // + // remember q gives you the freedom of native websocket messages if you don't want to use this client side at all. + private messageReceivedFromConn(evt: MessageEvent): void { + // check if qws message + let message = evt.data; + if (message.indexOf(websocketMessagePrefix) !== -1) { + let event = this.getWebsocketCustomEvent(message); + if (event !== '') { + // it's a custom message + this.fireMessage(event, this.getCustomMessage(event, message)); + return; + } + } + + // it's a native websocket message + this.fireNativeMessage(message); + } + + // errorReceivedFromConn this is the func which decides + // if it's a native websocket message or a custom qws message + // if native message then calls the fireNativeMessage + // else calls the fireMessage + // + // remember q gives you the freedom of native websocket messages if you don't want to use this client side at all. + private errorReceivedFromConn(evt: MessageEvent): void { + // check if qws message + let message = evt.data; + if (message.indexOf(websocketMessagePrefix) !== -1) { + let event = this.getWebsocketCustomEvent(message); + if (event !== '') { + // it's a custom message + this.fireMessage(event, this.getCustomMessage(event, message)); + return; + } + } + + // it's a native websocket message + this.fireNativeMessage(message); + } } -export interface Protocol { - serviceName: string; - methodName: string; - params?: string[]; -} export default Client; diff --git a/src/ts/@overflow/help/react/Help.tsx b/src/ts/@overflow/help/react/Help.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/@overflow/help/react/components/Help.tsx b/src/ts/@overflow/help/react/components/Help.tsx new file mode 100644 index 0000000..e69de29