Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@cap-js-community/websocket

Package Overview
Dependencies
Maintainers
7
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cap-js-community/websocket - npm Package Compare versions

Comparing version 0.8.1 to 0.9.0

8

CHANGELOG.md

@@ -8,2 +8,10 @@ # Changelog

## Version 0.9.0 - 2024-04-02
### Fixed
- Add option to activate Redis adapter in other (non-local) environments (e.g. Kyma)
- Fix Redis re-connect behavior to prevent Redis overload
- Pass adapter configurations to Redis client creation
## Version 0.8.1 - 2024-03-04

@@ -10,0 +18,0 @@

34

package.json
{
"name": "@cap-js-community/websocket",
"version": "0.8.1",
"version": "0.9.0",
"description": "WebSocket adapter for CDS",

@@ -44,7 +44,7 @@ "homepage": "https://cap.cloud.sap/",

"dependencies": {
"@sap/xsenv": "^4.2.0",
"@sap/xsenv": "^5.1.0",
"cookie": "^0.6.0",
"express": "^4.18.3",
"express": "^4.19.2",
"redis": "^4.6.13",
"socket.io": "^4.7.4",
"socket.io": "^4.7.5",
"ws": "^8.15.1"

@@ -54,8 +54,8 @@ },

"@cap-js-community/websocket": "./",
"@cap-js/sqlite": "^1.5.1",
"@sap/cds": "^7.7.0",
"@sap/cds-dk": "^7.7.0",
"@cap-js/sqlite": "^1.6.0",
"@sap/cds": "^7.8.0",
"@sap/cds-dk": "^7.8.0",
"@sap/xssec": "3.6.1",
"@socket.io/redis-adapter": "^8.2.1",
"@socket.io/redis-streams-adapter": "^0.2.0",
"@socket.io/redis-adapter": "^8.3.0",
"@socket.io/redis-streams-adapter": "^0.2.1",
"@types/express": "^4.17.21",

@@ -68,3 +68,3 @@ "eslint": "^8.57.0",

"prettier": "^3.2.4",
"socket.io-client": "^4.7.4"
"socket.io-client": "^4.7.5"
},

@@ -117,8 +117,18 @@ "license": "Apache-2.0",

"type": "object",
"description": "Websocket adapter implementation configuration options",
"description": "Websocket adapter implementation options",
"additionalProperties": true
},
"config": {
"type": "object",
"description": "Websocket adapter implementation configurations (i.e. Redis client options)",
"additionalProperties": true
},
"active": {
"type": "boolean",
"description": "Enable websocket adapter",
"default": true
},
"local": {
"type": "boolean",
"description": "Enabled websocket adapter in local environment",
"description": "Enable websocket adapter in local environment",
"default": false

@@ -125,0 +135,0 @@ }

@@ -649,8 +649,12 @@ # @cap-js-community/websocket

- Application needs to be bound to a Redis instance
- Cloud Foundry: Redis automatically active
- Local (or other):
- Option `cds.websocket.adapter.local: true` needs to be set
- Cloud Foundry: Redis is automatically active
- Use option `cds.websocket.adapter.active: false` to disable Redis adapter
- Other Environment (e.g. Kyma): Redis is NOT automatically active
- Use option `cds.websocket.adapter.active: true` to enable Redis adapter
- Local: Redis is NOT automatically active
- Use option `cds.websocket.adapter.local: true` to enable Redis adapter
- File `default-env.json` need to exist with Redis configuration
- Redis Adapter options can be specified via `cds.websocket.adapter.options`
- Redis channel key can be specified via `cds.websocket.adapter.options.key`. Default value is `websocket`.
- Redis client connection configuration can be passed via `cds.websocket.adapter.config`

@@ -657,0 +661,0 @@ ###### Custom Adapter

@@ -9,10 +9,11 @@ "use strict";

class RedisAdapter {
constructor(server, prefix, options) {
constructor(server, prefix, options, config) {
this.server = server;
this.prefix = prefix;
this.options = options;
this.config = config;
}
async setup() {
this.client = await redis.createPrimaryClientAndConnect();
this.client = await redis.createPrimaryClientAndConnect(this.config);
}

@@ -19,0 +20,0 @@

@@ -13,37 +13,43 @@ "use strict";

const IS_ON_CF = process.env.USER === "vcap";
const TIMEOUT = 5 * 1000;
const LOG_AFTER_SEC = 5;
let primaryClientPromise;
let secondaryClientPromise;
let lastErrorLog = Date.now();
const createPrimaryClientAndConnect = () => {
const createPrimaryClientAndConnect = (options) => {
if (primaryClientPromise) {
return primaryClientPromise;
}
const errorHandlerCreateClient = (err) => {
LOG?.error("Error from redis client for pub/sub failed", err);
primaryClientPromise = null;
setTimeout(createPrimaryClientAndConnect, TIMEOUT).unref();
setTimeout(createPrimaryClientAndConnect, LOG_AFTER_SEC * 1000).unref();
};
primaryClientPromise = _createClientAndConnect(errorHandlerCreateClient);
primaryClientPromise = createClientAndConnect(errorHandlerCreateClient, options);
return primaryClientPromise;
};
const createSecondaryClientAndConnect = () => {
const createSecondaryClientAndConnect = (options) => {
if (secondaryClientPromise) {
return secondaryClientPromise;
}
const errorHandlerCreateClient = (err) => {
LOG?.error("Error from redis client for pub/sub failed", err);
secondaryClientPromise = null;
setTimeout(createSecondaryClientAndConnect, TIMEOUT).unref();
setTimeout(createSecondaryClientAndConnect, LOG_AFTER_SEC * 1000).unref();
};
secondaryClientPromise = _createClientAndConnect(errorHandlerCreateClient);
secondaryClientPromise = createClientAndConnect(errorHandlerCreateClient, options);
return secondaryClientPromise;
};
const _createClientBase = () => {
const createClientBase = (options = {}) => {
const adapterActive = cds.env.websocket?.adapter?.active !== false;
if (!adapterActive) {
LOG?.info("Redis adapter is disabled");
return;
}
const adapterActiveExplicit = !!cds.env.websocket?.adapter?.active;
const adapterLocal = !!cds.env.websocket?.adapter?.local;
if (!(IS_ON_CF || adapterLocal)) {
if (!(IS_ON_CF || adapterActiveExplicit || adapterLocal)) {
LOG?.info("Redis not available in local environment");

@@ -74,31 +80,38 @@ return;

socket: { tls: credentials.tls },
...options,
},
});
}
return redis.createClient({ url });
return redis.createClient({ url, ...options });
} catch (err) {
throw new Error("error during create client with redis-cache service:" + err);
throw new Error("Error during create client with redis-cache service:" + err);
}
};
const _createClientAndConnect = async (errorHandlerCreateClient) => {
let client;
const createClientAndConnect = async (errorHandlerCreateClient, options) => {
try {
client = _createClientBase();
} catch (err) {
errorHandlerCreateClient(new Error("Error during create client with redis-cache service:" + err));
return;
}
if (!client) {
return;
}
client.on("error", errorHandlerCreateClient);
try {
const client = createClientBase(options);
if (!client) {
return;
}
await client.connect();
LOG?.info("Service redis-cache connected");
client.on("error", (err) => {
const dateNow = Date.now();
if (dateNow - lastErrorLog > LOG_AFTER_SEC * 1000) {
LOG?.error("Error from redis client for pub/sub failed", err);
lastErrorLog = dateNow;
}
});
client.on("reconnecting", () => {
const dateNow = Date.now();
if (dateNow - lastErrorLog > LOG_AFTER_SEC * 1000) {
LOG?.info("Redis client trying reconnect...");
lastErrorLog = dateNow;
}
});
return client;
} catch (err) {
errorHandlerCreateClient(err);
return;
}
return client;
};

@@ -105,0 +118,0 @@

@@ -128,2 +128,6 @@ "use strict";

}
let config = {};
if (cds.env.websocket?.adapter?.config) {
config = { ...config, ...cds.env.websocket?.adapter?.config };
}
let client;

@@ -134,5 +138,5 @@ let subClient;

case "@socket.io/redis-adapter":
client = await redis.createPrimaryClientAndConnect();
client = await redis.createPrimaryClientAndConnect(config);
if (client) {
subClient = await redis.createSecondaryClientAndConnect();
subClient = await redis.createSecondaryClientAndConnect(config);
if (subClient) {

@@ -139,0 +143,0 @@ this.adapter = adapterFactory.createAdapter(client, subClient, options);

@@ -191,5 +191,9 @@ "use strict";

}
let config = {};
if (cds.env.websocket?.adapter?.config) {
config = { ...config, ...cds.env.websocket?.adapter?.config };
}
const prefix = options?.key ?? "websocket";
const adapterFactory = SocketServer.require(adapterImpl, "adapter");
this.adapter = new adapterFactory(this, prefix, options);
this.adapter = new adapterFactory(this, prefix, options, config);
await this.adapter?.setup();

@@ -196,0 +200,0 @@ this.adapterActive = !!this.adapter?.client;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc