-
-
Notifications
You must be signed in to change notification settings - Fork 590
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Give structure to dashboard app (#163)
* Separate out files for different responsibilities. 1. Add src/plugins directory. This directory holds one typescript file per plugin. Each plugin is optionally can be displayed as a tab on the UI. 2. Move WebsocketApi to ws.ts. This file contains all websocket APIs provided by dashboard.py backend. * Make dashboard pluggable * Move devtools under core too * Register tabs dynamically * Typescript fixes for abstract interfaces * Initialize plugin app body skeleton * Call activated / deactivated on tab change * Move plugin name within plugin classes and initialize plugin within proxy dashboard constructor * templatize api development plugin * eslint fixes * use globs * Remove useless constructors
- Loading branch information
1 parent
0cc4e5e
commit ee7a69b
Showing
15 changed files
with
577 additions
and
288 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
import { WebsocketApi } from './ws' | ||
|
||
export interface IDashboardPlugin { | ||
name: string | ||
initializeTab(): JQuery<HTMLElement> | ||
initializeSkeleton(): JQuery<HTMLElement> | ||
activated(): void | ||
deactivated(): void | ||
} | ||
|
||
export interface IPluginConstructor { | ||
new (websocketApi: WebsocketApi): IDashboardPlugin | ||
} | ||
|
||
export abstract class DashboardPlugin implements IDashboardPlugin { | ||
public abstract readonly name: string | ||
protected websocketApi: WebsocketApi | ||
|
||
public constructor (websocketApi: WebsocketApi) { | ||
this.websocketApi = websocketApi | ||
} | ||
|
||
public makeTab (name: string, icon: string) : JQuery<HTMLElement> { | ||
return $('<a/>') | ||
.attr({ | ||
href: '#', | ||
plugin_name: this.name | ||
}) | ||
.addClass('nav-link') | ||
.text(name) | ||
.prepend( | ||
$('<i/>') | ||
.addClass('fa') | ||
.addClass('fa-fw') | ||
.addClass(icon) | ||
) | ||
} | ||
|
||
public abstract initializeTab() : JQuery<HTMLElement> | ||
public abstract initializeSkeleton(): JQuery<HTMLElement> | ||
public abstract activated(): void | ||
public abstract deactivated(): void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
import { DashboardPlugin } from '../plugin' | ||
|
||
export class HomePlugin extends DashboardPlugin { | ||
public name: string = 'home' | ||
|
||
public initializeTab () : JQuery<HTMLElement> { | ||
return this.makeTab('Home', 'fa-home') | ||
} | ||
|
||
public initializeSkeleton (): JQuery<HTMLElement> { | ||
return $('<div></div>') | ||
} | ||
|
||
public activated (): void {} | ||
|
||
public deactivated (): void {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
import { DashboardPlugin } from '../plugin' | ||
|
||
export class InspectTrafficPlugin extends DashboardPlugin { | ||
public name: string = 'inspect_traffic' | ||
|
||
public initializeTab () : JQuery<HTMLElement> { | ||
return this.makeTab('Inspect Traffic', 'fa-binoculars') | ||
} | ||
|
||
public initializeSkeleton (): JQuery<HTMLElement> { | ||
return $('<div></div>') | ||
} | ||
|
||
public activated (): void { | ||
this.websocketApi.enableInspection() | ||
} | ||
|
||
public deactivated (): void { | ||
this.websocketApi.disableInspection() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
import { DashboardPlugin } from '../plugin' | ||
|
||
export class SettingsPlugin extends DashboardPlugin { | ||
public name: string = 'settings' | ||
|
||
public initializeTab () : JQuery<HTMLElement> { | ||
return this.makeTab('Settings', 'fa-clog') | ||
} | ||
|
||
public initializeSkeleton (): JQuery<HTMLElement> { | ||
return $('<div></div>') | ||
} | ||
|
||
public activated (): void {} | ||
|
||
public deactivated (): void {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
import { DashboardPlugin } from '../plugin' | ||
|
||
export class TrafficControlPlugin extends DashboardPlugin { | ||
public name: string = 'traffic_control' | ||
|
||
public initializeTab () : JQuery<HTMLElement> { | ||
return this.makeTab('Traffic Controls', 'fa-lock') | ||
} | ||
|
||
public initializeSkeleton (): JQuery<HTMLElement> { | ||
return $('<div></div>') | ||
} | ||
|
||
public activated (): void {} | ||
|
||
public deactivated (): void {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/* | ||
proxy.py | ||
~~~~~~~~ | ||
⚡⚡⚡ Fast, Lightweight, Programmable, TLS interception capable | ||
proxy server for Application debugging, testing and development. | ||
:copyright: (c) 2013-present by Abhinav Singh and contributors. | ||
:license: BSD, see LICENSE for more details. | ||
*/ | ||
|
||
export class WebsocketApi { | ||
private hostname: string = window.location.hostname ? window.location.hostname : 'localhost'; | ||
private port: number = window.location.port ? Number(window.location.port) : 8899; | ||
// TODO: Must map to route registered by dashboard.py, don't hardcode | ||
private wsPrefix: string = '/dashboard'; | ||
private wsScheme: string = window.location.protocol === 'http:' ? 'ws' : 'wss'; | ||
private ws: WebSocket; | ||
private wsPath: string = this.wsScheme + '://' + this.hostname + ':' + this.port + this.wsPrefix; | ||
|
||
private mid: number = 0; | ||
private lastPingId: number; | ||
private lastPingTime: number; | ||
|
||
private readonly schedulePingEveryMs: number = 1000; | ||
private readonly scheduleReconnectEveryMs: number = 5000; | ||
|
||
private serverPingTimer: number; | ||
private serverConnectTimer: number; | ||
|
||
private inspectionEnabled: boolean; | ||
|
||
constructor () { | ||
this.scheduleServerConnect(0) | ||
} | ||
|
||
public static getTime () { | ||
const date = new Date() | ||
return date.getTime() | ||
} | ||
|
||
public enableInspection () { | ||
// TODO: Set flag to true only once response has been received from the server | ||
this.inspectionEnabled = true | ||
this.ws.send(JSON.stringify({ id: this.mid, method: 'enable_inspection' })) | ||
this.mid++ | ||
} | ||
|
||
public disableInspection () { | ||
this.inspectionEnabled = false | ||
this.ws.send(JSON.stringify({ id: this.mid, method: 'disable_inspection' })) | ||
this.mid++ | ||
} | ||
|
||
private scheduleServerConnect (after_ms: number = this.scheduleReconnectEveryMs) { | ||
this.clearServerConnectTimer() | ||
this.serverConnectTimer = window.setTimeout( | ||
this.connectToServer.bind(this), after_ms) | ||
} | ||
|
||
private connectToServer () { | ||
this.ws = new WebSocket(this.wsPath) | ||
this.ws.onopen = this.onServerWSOpen.bind(this) | ||
this.ws.onmessage = this.onServerWSMessage.bind(this) | ||
this.ws.onerror = this.onServerWSError.bind(this) | ||
this.ws.onclose = this.onServerWSClose.bind(this) | ||
} | ||
|
||
private clearServerConnectTimer () { | ||
if (this.serverConnectTimer == null) { | ||
return | ||
} | ||
window.clearTimeout(this.serverConnectTimer) | ||
this.serverConnectTimer = null | ||
} | ||
|
||
private scheduleServerPing (after_ms: number = this.schedulePingEveryMs) { | ||
this.clearServerPingTimer() | ||
this.serverPingTimer = window.setTimeout( | ||
this.pingServer.bind(this), after_ms) | ||
} | ||
|
||
private pingServer () { | ||
this.lastPingId = this.mid | ||
this.lastPingTime = WebsocketApi.getTime() | ||
this.mid++ | ||
// console.log('Pinging server with id:%d', this.last_ping_id); | ||
this.ws.send(JSON.stringify({ id: this.lastPingId, method: 'ping' })) | ||
} | ||
|
||
private clearServerPingTimer () { | ||
if (this.serverPingTimer != null) { | ||
window.clearTimeout(this.serverPingTimer) | ||
this.serverPingTimer = null | ||
} | ||
this.lastPingTime = null | ||
this.lastPingId = null | ||
} | ||
|
||
private onServerWSOpen (ev: MessageEvent) { | ||
this.clearServerConnectTimer() | ||
WebsocketApi.setServerStatusSuccess('Connected...') | ||
this.scheduleServerPing(0) | ||
} | ||
|
||
private onServerWSMessage (ev: MessageEvent) { | ||
const message = JSON.parse(ev.data) | ||
if (message.id === this.lastPingId) { | ||
WebsocketApi.setServerStatusSuccess( | ||
String((WebsocketApi.getTime() - this.lastPingTime) + ' ms')) | ||
this.clearServerPingTimer() | ||
this.scheduleServerPing() | ||
} else { | ||
console.log(message) | ||
} | ||
} | ||
|
||
private onServerWSError (ev: MessageEvent) { | ||
WebsocketApi.setServerStatusDanger() | ||
} | ||
|
||
private onServerWSClose (ev: MessageEvent) { | ||
this.clearServerPingTimer() | ||
this.scheduleServerConnect() | ||
WebsocketApi.setServerStatusDanger() | ||
} | ||
|
||
public static setServerStatusDanger () { | ||
$('#proxyServerStatus').parent('div') | ||
.removeClass('text-success') | ||
.addClass('text-danger') | ||
$('#proxyServerStatusSummary').text('') | ||
} | ||
|
||
public static setServerStatusSuccess (summary: string) { | ||
$('#proxyServerStatus').parent('div') | ||
.removeClass('text-danger') | ||
.addClass('text-success') | ||
$('#proxyServerStatusSummary').text( | ||
'(' + summary + ')') | ||
} | ||
} |
Oops, something went wrong.