Skip to content

Commit

Permalink
websocket implementation mockoon#83
Browse files Browse the repository at this point in the history
  • Loading branch information
isuru89 committed Feb 21, 2024
1 parent e210c80 commit 9c927d6
Show file tree
Hide file tree
Showing 99 changed files with 5,103 additions and 1,041 deletions.
6 changes: 4 additions & 2 deletions packages/cli/test/data/envs/file.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"uuid": "6cca9fb6-3585-4c0f-8cac-1150ce24452b",
"name": "Environment file",
"lastMigration": 32,
"lastMigration": 33,
"port": 3000,
"endpointPrefix": "",
"latency": 0,
Expand Down Expand Up @@ -34,7 +34,9 @@
}
],
"responseMode": null,
"type": "http"
"type": "http",
"streamingMode": null,
"streamingInterval": 0
}
],
"proxyMode": false,
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/test/data/envs/mock1.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "70d8639e-ef20-4d52-9749-c47d9ffc5c67",
"lastMigration": 32,
"lastMigration": 33,
"name": "mock1",
"endpointPrefix": "api",
"latency": 0,
Expand Down Expand Up @@ -33,7 +33,9 @@
}
],
"responseMode": null,
"type": "http"
"type": "http",
"streamingMode": null,
"streamingInterval": 0
}
],
"proxyMode": false,
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/test/data/envs/mock1noext
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "70d8639e-ef20-4d52-9749-c47d9ffc5c67",
"lastMigration": 32,
"lastMigration": 33,
"name": "mock1",
"endpointPrefix": "api",
"latency": 0,
Expand Down Expand Up @@ -33,7 +33,9 @@
}
],
"responseMode": null,
"type": "http"
"type": "http",
"streamingMode": null,
"streamingInterval": 0
}
],
"proxyMode": false,
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/test/data/envs/mock2.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "66f5a033-0d8b-4bc6-b5f9-a949d8fd0ec2",
"lastMigration": 32,
"lastMigration": 33,
"name": "mock2",
"endpointPrefix": "api",
"latency": 0,
Expand Down Expand Up @@ -33,7 +33,9 @@
}
],
"responseMode": null,
"type": "http"
"type": "http",
"streamingMode": null,
"streamingInterval": 0
}
],
"proxyMode": false,
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/test/data/envs/mock3.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "f4c8cd6e-dbf4-4865-9558-08195ef8b36b",
"lastMigration": 32,
"lastMigration": 33,
"name": "mock1",
"endpointPrefix": "api",
"latency": 0,
Expand Down Expand Up @@ -33,7 +33,9 @@
}
],
"responseMode": null,
"type": "http"
"type": "http",
"streamingMode": null,
"streamingInterval": 0
}
],
"proxyMode": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/data/envs/mock4.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "5d004e2c-6055-41bc-b0ac-4d0c064dddd1",
"lastMigration": 32,
"lastMigration": 33,
"name": "mockhttps",
"endpointPrefix": "api",
"latency": 0,
Expand Down
14 changes: 10 additions & 4 deletions packages/cli/test/data/envs/petstore-imported.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "2721eb99-7031-40ae-8725-0c37edc3976a",
"lastMigration": 32,
"lastMigration": 33,
"name": "Swagger Petstore",
"endpointPrefix": "v1",
"latency": 0,
Expand Down Expand Up @@ -57,7 +57,9 @@
"callbacks": []
}
],
"responseMode": null
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "094031a7-93fc-4659-82b4-58c8c9de10b0",
Expand Down Expand Up @@ -105,7 +107,9 @@
"callbacks": []
}
],
"responseMode": null
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "4b9356a9-d656-4ea8-acf3-c254fb9d6616",
Expand Down Expand Up @@ -153,7 +157,9 @@
"callbacks": []
}
],
"responseMode": null
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
}
],
"rootChildren": [
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/data/envs/wrong-cert.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"uuid": "06d4e2f2-b7a1-4717-a61d-94666816c30f",
"lastMigration": 32,
"lastMigration": 33,
"name": "test",
"endpointPrefix": "",
"latency": 0,
Expand Down
46 changes: 46 additions & 0 deletions packages/commons-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/commons-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"range-parser": "1.2.1",
"typed-emitter": "2.1.0",
"winston": "3.10.0",
"ws": "8.14.2",
"xml-js": "1.6.11"
},
"devDependencies": {
Expand All @@ -62,6 +63,7 @@
"@types/node": "20.7.1",
"@types/object-path": "0.11.2",
"@types/qs": "6.9.8",
"@types/ws": "8.5.10",
"@typescript-eslint/eslint-plugin": "6.7.3",
"@typescript-eslint/parser": "6.7.3",
"assert-request": "1.0.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ export const ServerMessages = {
SERVER_STOPPED: 'Server stopped',
SERVER_CREATING_PROXY: 'Creating proxy to %s',
CALLBACK_FILE_ERROR: 'Error while attaching file to callback request: %s',
CALLBACK_ERROR: 'Error while executing callback: %s'
CALLBACK_ERROR: 'Error while executing callback: %s',

WS_UNKNOWN_ROUTE: 'No matching route found for websocket! %s',
WS_UNSUPPORTED_CONTENT: 'Unsupported content recieved from websocket! %s',
WS_SERVING_ERROR: 'Web socket serving error! %s'
};
128 changes: 128 additions & 0 deletions packages/commons-server/src/libs/requests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Request } from 'express';
import { IncomingMessage } from 'http';

import { parse as parseUrl } from 'url';
import { parseRequestMessage, parseWebSocketMessage } from './utils';

/**
* A generic interface covering different types of requests.
* Such as, http, ws, graphql, etc.
*/
export interface ServerRequest {
cookies: any;
header: (name: string) => string | undefined;
get: (headerName: string) => string | undefined;
params: any;
query: any;
body: any;
stringBody: string;

hostname: string | undefined;
ip: string | undefined;
method: string | undefined;

originalRequest: any;
}

const toString = (data?: any): string | undefined => {
if (typeof data === 'string') {
return data;
} else if (typeof data === 'object') {
return JSON.stringify(data);
} else if (typeof data === 'undefined') {
return undefined;
}

return data + '';
};

/**
* Creates a common ServerRequest instance from Express request.
* To pass into helper classes, this common server request is required.
*
* @param req Express request object
* @returns Mockoon common server request
*/
export const fromExpressRequest = (req: Request): ServerRequest =>
({
body: req.body,
cookies: req.cookies,
header: (name: string) => req.header && req.header(name),
get: (headerName: string) => req.header && req.header(headerName),
hostname: req.hostname,
ip: req.ip,
method: req.method,
params: req.params,
originalRequest: req,
query: req.query,
stringBody: req.stringBody || ''
}) as ServerRequest;

/**
* Creates a common ServerRequest instance from Web socket request.
* To pass into helper classes, this common server request is required.
*
* @param req websocket connection request
* @param message message recieved from websocket now
*/
export const fromWsRequest = (
req: IncomingMessage,
message?: string
): ServerRequest => {
const location = parseUrl(req.url || '', true);

const structuredMessage = message
? parseWebSocketMessage(message || '', req)
: undefined;

return {
body: structuredMessage || req.body,
cookies: null,
header: (name: string) => req.headers && req.headers[name],
get: (headerName: string) => req.headers && req.headers[headerName],
hostname: req.headers && req.headers['host'],
ip:
(req.headers && req.headers['x-forwarded-for']) ||
req.socket?.remoteAddress,
method: req.method,
originalRequest: req,
params: {},
query: location.query,
stringBody: message || toString(req.body) || ''
} as ServerRequest;
};

/**
* Copies the given request with a new message.
*
* This method is useful to mimic the behaviour of websockets, because,
* we need to keep the access of original connection request and then subsequent messages
* in a full-duplex communication. This will update the body content with the recieved
* message, so that helper classes will use that instead of original body.
*
* @param req
* @param message received web socket message.
* @returns
*/
export const fromServerRequest = (
req: ServerRequest,
message?: string
): ServerRequest => {
const structuredMessage = message
? parseRequestMessage(message || '', req)
: undefined;

return {
body: structuredMessage || req.body,
cookies: req.cookies,
header: req.header,
get: req.get,
hostname: req.hostname,
ip: req.ip,
method: req.method,
originalRequest: req.originalRequest,
params: req.params,
query: req.query,
stringBody: message || req.stringBody || ''
} as ServerRequest;
};

0 comments on commit 9c927d6

Please sign in to comment.