cloudworker-proxy
Version:
An api gateway for cloudflare workers
136 lines (116 loc) • 3.83 kB
JavaScript
;
/**
* Connection
*/
const WebSocket = require('ws');
class Connection {
constructor(sdk) {
this.sdk = sdk;
this.connection = null;
this.context = {};
}
isConnected() {
return !!this.connection;
}
/**
* Connects to websockets and returns the connection with event handlers .on('open', 'message', 'error')
*/
async connect(options) {
if (options.orgUid) {
this.sdk.context.orgUid = options.orgUid;
}
// Validate org
if (!this.sdk.context.orgUid) {
throw new Error('You must specify an "orgUid" to connect');
}
// Sanitize filter
options.filter = options.filter || {};
options.filter.stageName = options.filter.stageName ? options.filter.stageName.trim() : null;
options.filter.appName = options.filter.appName ? options.filter.appName.trim() : null;
options.filter.instanceName = options.filter.instanceName
? options.filter.instanceName.trim()
: null;
// Connect
let queryParams = `?accessKey=${this.sdk.accessKey}&orgUid=${this.sdk.context.orgUid}&`;
queryParams += `filter=${encodeURIComponent(JSON.stringify(options.filter))}`;
const domain = this.sdk.getDomain('events-streaming') + queryParams;
this.connection = new WebSocket(domain);
// Handle message event
if (options.onEvent) {
this.connection.on('message', (message) => {
const decodedMessage = Buffer.from(message, 'base64').toString();
const data = JSON.parse(decodedMessage);
return options.onEvent(data);
});
}
// Handle disconnect event
if (options.onDisconnect) {
this.connection.on('close', (code, reason) => {
return options.onDisconnect(code, reason);
});
}
return new Promise((resolve, reject) => {
// Error handler for errors that don't have an unexpected response
this.connection.on('error', (error) => {
const e = new Error(`Unexpected Serverless Platform Streaming Error: ${error.message}`);
e.detail = error;
return reject(e);
});
this.connection.on('open', () => {
return resolve();
});
});
}
/**
* Terminates the websockets connection
*/
disconnect() {
if (this.connection) {
this.connection.close();
this.connection = null;
}
}
/**
* Sends a message via the websockets connection. Validation should be handled in sdk.publish()
* event format:
* {
* orgUid,
* accessKey,
* data
* }
*/
send(event) {
// Validate
if (!event) {
throw new Error('An "event" is required');
}
if (typeof event !== 'object') {
throw new Error('The "event" argument must be an object');
}
if (!event.event || typeof event.event !== 'string') {
throw new Error(
'The "event" property containing the event type is required and must be a string'
);
}
// Convert to a safe Serverless Platform Event
const safeEvent = {};
safeEvent.accessKey = this.sdk.accessKey;
safeEvent.event = event.event.trim();
safeEvent.orgUid = event.orgUid || this.sdk.context.orgUid;
safeEvent.stageName = this.sdk.context.stageName;
safeEvent.appName = this.sdk.context.appName;
safeEvent.instanceName = this.sdk.context.instanceName;
safeEvent.componentName = this.sdk.context.componentName;
safeEvent.componentVersion = this.sdk.context.componentVersion;
safeEvent.data = event.data || {};
// Store createdAt date
safeEvent.data.createdAt = Date.now();
// Validate
if (!safeEvent.orgUid) {
throw new Error('event must have an "orgUid"');
}
const encodedData = Buffer.from(JSON.stringify(safeEvent)).toString('base64');
this.connection.send(encodedData);
}
}
module.exports = Connection;