diff --git a/config/webpack.dev.config.js b/config/webpack.dev.config.js
index 22488f7..8769f9b 100644
--- a/config/webpack.dev.config.js
+++ b/config/webpack.dev.config.js
@@ -14,7 +14,7 @@ var srcDir = path.join(appDir, 'src');
var options = {
entry: {
- background: path.join(srcDir, 'background.js'),
+ background: path.join(srcDir, 'background.ts'),
inspector: path.join(srcDir, 'inspector.tsx'),
},
output: {
diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js
index d36f4c7..044bfaf 100644
--- a/config/webpack.prod.config.js
+++ b/config/webpack.prod.config.js
@@ -14,7 +14,7 @@ var srcDir = path.join(appDir, "src");
var options = {
entry: {
- background: path.join(srcDir, "background.js"),
+ background: path.join(srcDir, "background.ts"),
inspector: path.join(srcDir, "inspector.tsx"),
},
output: {
diff --git a/src/FrameData.ts b/src/FrameData.ts
new file mode 100644
index 0000000..178a832
--- /dev/null
+++ b/src/FrameData.ts
@@ -0,0 +1,133 @@
+import { FrameEntryType, WebSocketFrame } from './viewer/types';
+import { checkViable, newGetName, stringToBuffer } from './viewer/Helpers/Helper';
+type INC = 'incoming';
+type OUT = 'outgoing';
+export type frameSendingType = INC | OUT;
+type JSON_TYPE = 'json';
+type BINARY_TYPE = 'binary';
+type TEXT_TYPE = 'text';
+const JSON_TYPE: JSON_TYPE = 'json',
+ BINARY_TYPE: BINARY_TYPE = 'binary',
+ TEXT_TYPE: TEXT_TYPE = 'text';
+type contentType = JSON_TYPE | BINARY_TYPE | TEXT_TYPE;
+
+interface FrameAddingProps {
+ id: string;
+ sendingType: frameSendingType;
+ contentType: contentType;
+ time: Date;
+ length: number;
+ text: string;
+ content?: string | Uint8Array | object;
+}
+// TODO to simplify by using _public_ in constructor
+export class FrameEntry {
+ id: string;
+ sendingType: frameSendingType;
+ contentType: contentType;
+ time: Date;
+ length: number;
+ text: string;
+ content?: string | Uint8Array | object;
+ constructor(args: FrameAddingProps) {
+ this.id = args.id;
+ this.sendingType = args.sendingType;
+ this.contentType = args.contentType;
+ this.time = args.time;
+ this.length = args.length;
+ this.text = args.text;
+ this.content = args.content;
+ // Here can be added keys of JSON object or other data
+ }
+}
+// Uses parameters from Network.WebSocket method to add FrameEntry to array
+export const getFrame = (
+ sendingType: frameSendingType,
+ requestId: string,
+ timestamp: number,
+ response: WebSocketFrame
+) => {
+ // Checks ContentType and assigns Content
+ const isDataTextOrObject = response.opcode === 1;
+ const isDataBinary = response.opcode === 2;
+ if (isDataTextOrObject || isDataBinary) {
+ let assignedContentType: contentType, assignedContent: string | Uint8Array | object; // TODO Default value?
+
+ if (isDataBinary) {
+ assignedContent = stringToBuffer(response.payloadData);
+ assignedContentType = BINARY_TYPE;
+ }
+ if (isDataTextOrObject) {
+ try {
+ assignedContent = JSON.parse(response.payloadData);
+ assignedContentType = JSON_TYPE;
+ } catch {
+ assignedContent = response.payloadData;
+ assignedContentType = TEXT_TYPE;
+ }
+ }
+ // Creates a new Frame Entry
+ const FrameAddingProps: FrameAddingProps = {
+ id: Date.now().toString(),
+ sendingType: sendingType,
+ contentType: assignedContentType,
+ time: timestamp, // FIXME Dependency from App
+ length: response.payloadData.length,
+ text: response.payloadData,
+ content: assignedContent,
+ };
+ const frameEntry = new FrameEntry(FrameAddingProps);
+ return frameEntry; // TODO change to FrameAddingProps?
+ }
+};
+// FrameDataArray is an array that has all registered and processed(altered) frames
+export default class FrameDataArray {
+ constructor() {
+ this.frames = [];
+ }
+
+ frames: FrameEntry[] = [];
+ // TODO Method shouldn't rely on extensional parameters
+ addFrameEntry(
+ sendingType: frameSendingType,
+ requestId: string,
+ timestamp: number,
+ response: WebSocketFrame
+ ): void {
+ const newFrame = getFrame(sendingType, requestId, timestamp, response);
+ this.frames.push(newFrame);
+ }
+
+ deleteAllFrameEntries(): void {
+ this.frames = [];
+ }
+ // FrameViewArray represents all frames that had been filtered and grepped
+ getFrameViewArray(): FrameEntry[] {
+ // TODO make connection with control panel
+ const MAX_STRING_LENGTH = 275;
+ const regName = '',
+ filter = '',
+ isFilterInverse = false;
+ const frameViewArray = [];
+ this.frames.map((frameEntry: FrameEntry) => {
+ // TODO refactor checkViable() newGetName to comply with new types
+ if (!checkViable(frameEntry as FrameEntryType, { regName, filter, isFilterInverse })) {
+ const greppedText = newGetName(frameEntry, { regName, filter, isFilterInverse });
+ const processedFrameEntry = Object.assign({}, frameEntry); //copy = JSON.parse(JSON.stringify(original));
+ processedFrameEntry.text = greppedText.slice(0, MAX_STRING_LENGTH);
+ processedFrameEntry.content = undefined;
+ frameViewArray.push(processedFrameEntry);
+ }
+ });
+ return frameViewArray;
+ }
+}
+
+
+/*
+FrameDataObject = {
+ frames: {id as string: FrameEntry object};
+ ids: array of id as string
+}
+
+ */
diff --git a/src/background.js b/src/background.ts
similarity index 63%
rename from src/background.js
rename to src/background.ts
index 8b98b40..373b0cc 100644
--- a/src/background.js
+++ b/src/background.ts
@@ -1,7 +1,14 @@
import './img/icon-128.png';
+import Window from 'chrome';
-const inspectors = [];
-
+type inspectorMask = {
+ id: number;
+ popup: Window; // https://developer.chrome.com/extensions/windows#type-Window
+ active: boolean;
+};
+// a list of created inspector windows
+const inspectors: inspectorMask[] = [];
+// Deletes removed inspectors mask from array
chrome.windows.onRemoved.addListener((id) => {
const pos = inspectors.findIndex(({ popup }) => popup.id === id);
if (pos >= 0) {
@@ -11,6 +18,7 @@ chrome.windows.onRemoved.addListener((id) => {
inspectors.splice(pos, 1);
}
});
+// Listens to possible Detachment of existing inspector windows
chrome.debugger.onDetach.addListener(({ tabId }) => {
const inspector = inspectors.find(({ id }) => id === tabId);
if (inspector) {
@@ -18,18 +26,26 @@ chrome.debugger.onDetach.addListener(({ tabId }) => {
}
});
+// Listens to clicks on extension icon
chrome.browserAction.onClicked.addListener((tab) => {
+ // Checks if there is an existing inspector window
const inspector = inspectors.find(({ id }) => id === tab.id);
+ // if true it gets focus
if (inspector && inspector.active) {
chrome.windows.update(inspector.popup.id, { focused: true });
} else {
+ // else attaches debugger to the given target
chrome.debugger.attach({ tabId: tab.id }, '1.0', () => {
+ // All module of callback executes after attachment attempt
+ // signalize if attachment attempt failed
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
+ // inspector Local and inspector should be identical TODO delete inspectorLocal?
const inspectorLocal = inspectors.find(({ id }) => id === tab.id);
+ // if inspector window exists it get reattached and focused
if (inspectorLocal) {
inspectorLocal.active = true;
chrome.runtime.sendMessage({
@@ -37,6 +53,7 @@ chrome.browserAction.onClicked.addListener((tab) => {
tabId: tab.id,
});
chrome.windows.update(inspectorLocal.popup.id, { focused: true });
+ // else inspector windows created and new object pushed to inspectors array
} else {
chrome.windows.create(
{
diff --git a/src/inspector.tsx b/src/inspector.tsx
index f47c9f8..179269b 100644
--- a/src/inspector.tsx
+++ b/src/inspector.tsx
@@ -3,12 +3,17 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './reset.css';
import App from './viewer/App';
+import { NetworkWebSocketParams } from './viewer/types';
+import FrameDataArray from './FrameData';
+// gets tabId of inspected window from URL
const tabId = parseInt(window.location.search.substr(1), 10);
// TODO create
const handlers: any = {};
+const frameDataArray = new FrameDataArray();
function startDebugging() {
+ // Command Debugger to use Network inspector module
chrome.debugger.sendCommand({ tabId }, 'Network.enable', undefined, () => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
@@ -16,34 +21,56 @@ function startDebugging() {
console.log('Network enabled');
}
});
-
+ // Creates title for inspector page
chrome.tabs.get(tabId, (tab) => {
if (tab.title) {
- document.title = `WebSocket Inspector - ${tab.title}`;
+ document.title = `(tab.id = ${tabId}) WebSocket Inspector - ${tab.title} `;
} else {
document.title = 'WebSocket Inspector';
}
});
}
-
+// Restarts Network debugging on command
chrome.runtime.onMessage.addListener((message) => {
if (message.message === 'reattach' && message.tabId === tabId) {
startDebugging();
}
});
-
+// Starts Network debugging on load
+window.addEventListener('load', () => {
+ startDebugging();
+});
+// Old function to listen Network events TODO refactor to core
chrome.debugger.onEvent.addListener((debuggee, message, params) => {
if (debuggee.tabId !== tabId) {
return;
}
+ // What does this do?
if (handlers[message]) {
handlers[message](params);
}
});
-
-window.addEventListener('load', () => {
- startDebugging();
+// New function to listen Network events
+chrome.debugger.onEvent.addListener((source, method, params) => {
+ const METHOD_FRAME_IN = 'Network.webSocketFrameReceived',
+ METHOD_FRAME_OUT = 'Network.webSocketFrameSent';
+ if (source.tabId !== tabId) {
+ return;
+ }
+ if (method === METHOD_FRAME_IN || method === METHOD_FRAME_OUT) {
+ // Get Frame
+ const sendingType = method === METHOD_FRAME_IN ? 'incoming' : 'outgoing';
+ const { requestId, timestamp, response } = params as NetworkWebSocketParams;
+ frameDataArray.addFrameEntry(sendingType, requestId, timestamp, response);
+ console.log({ frameDataArray });
+ let abs = frameDataArray.getFrameViewArray();
+ console.log({ abs });
+ }
});
-ReactDOM.render(, document.getElementById('root'));
+const frameViewArray = frameDataArray.getFrameViewArray();
+ReactDOM.render(
+ ,
+ document.getElementById('root')
+);
diff --git a/src/viewer/App.tsx b/src/viewer/App.tsx
index 37be7cd..782f10e 100644
--- a/src/viewer/App.tsx
+++ b/src/viewer/App.tsx
@@ -1,26 +1,28 @@
-import React, { ChangeEvent } from 'react';
+import React from 'react';
import Panel from 'react-flex-panel';
import ControlPanel from './ControlPanel/ControlPanel';
import FrameList from './FrameTable/FrameTable';
import PanelView from './PanelView/PanelView';
import { stringToBuffer } from './Helpers/Helper';
import './App.scss';
-import { IFrame, IFrameType, Response } from './types';
+import { FrameEntryType, frameSendingType, WebSocketFrame } from './types';
+import { FrameEntry } from '../FrameData';
interface AppProps {
handlers: any;
+ frameViewArray: FrameEntry[];
}
interface AppState {
[key: string]: any;
- frames: IFrame[];
- activeId: number | null;
+ frameViewArray: FrameEntry[];
+ activeId: string | null;
isCapturing: boolean;
regName: string;
filter: string;
isFilterInverse: boolean;
}
export default class App extends React.Component {
- frameUniqueId = 0;
+ // frameUniqueId = 0;
frameIssueTime: number;
@@ -30,11 +32,11 @@ export default class App extends React.Component {
constructor(props: AppProps) {
super(props);
- this.props.handlers['Network.webSocketFrameReceived'] = this.webSocketFrameReceived.bind(this);
- this.props.handlers['Network.webSocketFrameSent'] = this.webSocketFrameSent.bind(this);
+ // this.props.handlers['Network.webSocketFrameReceived'] = this.webSocketFrameReceived.bind(this);
+ // this.props.handlers['Network.webSocketFrameSent'] = this.webSocketFrameSent.bind(this);
this.state = {
- frames: [],
- activeId: null,
+ frameViewArray: props.frameViewArray,
+ activeId: '',
isCapturing: true,
regName: '',
filter: '',
@@ -57,7 +59,6 @@ export default class App extends React.Component {
return acc;
}, {});
this.setState(cacheState);
- // TODO Boolean values turns to strings.
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
@@ -77,8 +78,8 @@ export default class App extends React.Component {
}
render() {
- const { frames, activeId, regName, filter, isFilterInverse, isCapturing } = this.state;
- const active = frames.find((f) => f.id === activeId);
+ const { frameViewArray, activeId, regName, filter, isFilterInverse, isCapturing } = this.state;
+ const active = frameViewArray.find((frameEntry) => frameEntry.id === activeId);
return (
@@ -87,19 +88,16 @@ export default class App extends React.Component {
onCapturingToggle={this.onCapturingToggle}
isCapturing={isCapturing}
regName={regName}
- onRegName={this.setRegName}
+ handleRegName={this.setRegName}
filter={filter}
- onFilter={this.setFilter}
- isFilterInverse={this.state.isFilterInverse}
+ handleFilter={this.setFilter}
+ isFilterInverse={isFilterInverse}
onFilterModeToggle={this.onFilterModeToggle}
/>
@@ -113,7 +111,7 @@ export default class App extends React.Component {
);
}
- selectFrame = (id: number) => {
+ selectFrame = (id: string) => {
this.setState({ activeId: id });
};
@@ -125,23 +123,23 @@ export default class App extends React.Component {
this.setState({ isCapturing: !this.state.isCapturing });
};
- setRegName = (e: ChangeEvent) => {
- this.setState({ regName: e.target.value });
+ setRegName = (regName: string) => {
+ this.setState({ regName });
};
- setFilter = (e: ChangeEvent) => {
- this.setState({ filter: e.target.value });
+ setFilter = (filter: string) => {
+ this.setState({ filter });
};
onFilterModeToggle = () => {
this.setState({ isFilterInverse: !this.state.isFilterInverse });
};
- addFrame(type: IFrameType, timestamp: number, response: Response) {
- if (response.opcode === 1 || response.opcode === 2) {
- const frame: IFrame = {
- type,
- name: type,
+ /* addFrame(sendingType: frameSendingType, timestamp: number, response: WebSocketFrame) {
+ if ((response.opcode === 1 || response.opcode === 2) && this.state.isCapturing) {
+ const frame: FrameEntryType = {
+ sendingType: sendingType,
+ name: sendingType,
id: this.frameUniqueId,
time: this.getTime(timestamp),
length: response.payloadData.length,
@@ -156,15 +154,15 @@ export default class App extends React.Component {
}
}
- webSocketFrameReceived({ timestamp, response }: { timestamp: number; response: Response }) {
+ webSocketFrameReceived({ timestamp, response }: { timestamp: number; response: WebSocketFrame }) {
if (this.state.isCapturing) {
this.addFrame('incoming', timestamp, response);
}
}
- webSocketFrameSent({ timestamp, response }: { timestamp: number; response: Response }) {
+ webSocketFrameSent({ timestamp, response }: { timestamp: number; response: WebSocketFrame }) {
if (this.state.isCapturing) {
this.addFrame('outgoing', timestamp, response);
}
- }
+ }*/
}
diff --git a/src/viewer/ControlPanel/ControlPanel.tsx b/src/viewer/ControlPanel/ControlPanel.tsx
index 17d5699..f9b6364 100644
--- a/src/viewer/ControlPanel/ControlPanel.tsx
+++ b/src/viewer/ControlPanel/ControlPanel.tsx
@@ -3,14 +3,14 @@ import FontAwesome from 'react-fontawesome';
import cx from 'classnames';
import './ControlPanel.scss';
import { EFilter } from '../types';
-// TODO not to return events
+
type ControlPanelMode = {
isCapturing: boolean;
onClear: (event: MouseEvent) => void;
onFilterModeToggle: (event: MouseEvent) => void;
onCapturingToggle: (event: MouseEvent) => void;
- onRegName: (event: ChangeEvent) => void;
- onFilter: (event: ChangeEvent) => void;
+ handleRegName: (arg0: string) => void;
+ handleFilter: (arg0: string) => void;
};
interface ControlPanelProps extends ControlPanelMode, EFilter {}
interface ControlPanelState {
@@ -46,13 +46,22 @@ export default class ControlPanel extends React.Component) => {
+ handleRegName(e.target.value);
+ };
+
+ const onFilter = (e: ChangeEvent) => {
+ handleFilter(e.target.value);
+ };
+
return (
void;
-};
+interface FrameListProps {
+ frameViewArray: FrameEntry[];
+ activeId: string | null;
+ onSelect: (id: string | null) => void;
+}
-export default class FrameList extends React.Component {
+export default class FrameList extends React.Component {
handlerClearSelect = () => {
this.props.onSelect(null);
};
render() {
- const { frames, activeId, onSelect, ...filterData } = this.props;
+ const { frameViewArray, activeId, onSelect } = this.props;
return (
- {frames.map((frame) => (
- (
+
))}
@@ -35,32 +34,32 @@ export default class FrameList extends React.Component
}
}
-type FrameEntryProps = {
- key: number;
- frame: IFrame;
+interface FrameEntryProps {
+ key: string;
+ frameEntry: FrameEntry;
selected: boolean;
- onSelect: (id: number | null) => void;
- filterData: EFilter;
-};
+ onSelect: (id: string | null) => void;
+}
-class FrameEntry extends React.PureComponent {
+class FrameEntryComponent extends React.PureComponent {
handlerSelect = (e: MouseEvent) => {
e.stopPropagation();
- this.props.onSelect(this.props.frame.id);
+ this.props.onSelect(this.props.frameEntry.id);
};
render() {
- const { frame, selected, filterData } = this.props;
- if (checkViable(frame, filterData as EFilter)) return null;
+ const { frameEntry, selected } = this.props;
return (
-
- {TimeStamp(frame.time)}
- {getName(frame, filterData)}
- {frame.length}
+
+ /* {TimeStamp(frameEntry.time)} */
+ {frameEntry.text}
+ {frameEntry.length}
);
}
diff --git a/src/viewer/Helpers/Helper.ts b/src/viewer/Helpers/Helper.ts
index 35f0e05..8abb7ed 100644
--- a/src/viewer/Helpers/Helper.ts
+++ b/src/viewer/Helpers/Helper.ts
@@ -1,4 +1,5 @@
-import { EFilter, IFrame } from '../types';
+import { EFilter, FrameEntryType } from '../types';
+import { FrameEntry } from '../../FrameData';
export function grep(text: string, regexp: string) {
if (!(text && regexp)) {
@@ -24,14 +25,20 @@ export const TimeStamp = (time: Date): string => {
const ms = time.getMilliseconds();
return `${padded(h, 2)}:${padded(m, 2)}:${padded(s, 2)}.${padded(ms, 3)}`;
};
-export const getName = (frame: IFrame, filterData: EFilter): string => {
+export const getName = (frame: FrameEntryType, filterData: EFilter): string => {
if (frame.text != null) {
return grep(frame.text, filterData.regName) || frame.text;
}
return 'Binary Frame';
};
-export const checkViable = (frame: IFrame, filterData: EFilter): boolean => {
+export const newGetName = (frame: FrameEntry, filterData: EFilter): string => {
+ if (frame.contentType !== 'binary') {
+ return grep(frame.text, filterData.regName) || frame.text;
+ }
+ return 'Binary Frame';
+};
+export const checkViable = (frame: FrameEntryType, filterData: EFilter): boolean => {
if (filterData.filter && frame.text) {
if (filterData.isFilterInverse) {
return !!grep(frame.text, filterData.filter);
diff --git a/src/viewer/PanelView/PanelView.tsx b/src/viewer/PanelView/PanelView.tsx
index 7f52f13..7a9ee23 100644
--- a/src/viewer/PanelView/PanelView.tsx
+++ b/src/viewer/PanelView/PanelView.tsx
@@ -3,7 +3,7 @@ import React from 'react';
import cx from 'classnames';
import HexViewer from './HexViewer';
import './PanelView.scss';
-import { IFrame } from '../types';
+import { FrameEntryType } from '../types';
const TextViewer = ({ data }: { data: string | undefined }) => (
{data}
@@ -19,7 +19,7 @@ interface PanelViewState {
panel?: PanelName | PanelName[] | null;
}
interface PanelViewProps {
- frame: IFrame;
+ frame: FrameEntryType;
}
export default class PanelView extends React.Component {
diff --git a/src/viewer/types.ts b/src/viewer/types.ts
index 9b36ddb..d5bc5e2 100644
--- a/src/viewer/types.ts
+++ b/src/viewer/types.ts
@@ -1,6 +1,6 @@
-export type IFrameType = 'incoming' | 'outgoing';
-export type IFrame = {
- type: IFrameType;
+export type frameSendingType = 'incoming' | 'outgoing';
+export interface FrameEntryType {
+ sendingType: frameSendingType;
name: string;
id: number;
time: Date;
@@ -15,7 +15,15 @@ export interface EFilter {
filter: string;
isFilterInverse: boolean;
}
-export interface Response {
+
+export interface WebSocketFrame {
opcode: number;
+ mask: boolean;
payloadData: string;
}
+
+export interface NetworkWebSocketParams {
+ requestId: string;
+ timestamp: number;
+ response: WebSocketFrame;
+}
diff --git a/src/viewer/typings/react-flex-panel.d.ts b/src/viewer/typings/react-flex-panel.d.ts
new file mode 100644
index 0000000..338d388
--- /dev/null
+++ b/src/viewer/typings/react-flex-panel.d.ts
@@ -0,0 +1,17 @@
+declare module 'react-flex-panel' {
+ export class Panel {
+ rows: boolean;
+ cols: boolean;
+ size: number;
+ minSize: number;
+ maxSize: number;
+ flex: number;
+ resizable: boolean;
+ panelRef: void;
+ constructor(props: any, context: any);
+ onResize: () => number;
+ renderChildren: () => void;
+ onRef: () => void;
+ render: () => any;
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 6a5efee..1d78447 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -12,8 +12,8 @@
"target": "es6",
"experimentalDecorators": true,
"noUnusedLocals": true,
-
- "resolveJsonModule": true
+ "resolveJsonModule": true,
+ "typeRoots": ["./src/typings"]
},
"exclude": ["node_modules"]
}