wirekvs-js/src/index.js
2025-05-10 14:51:07 +02:00

245 lines
5.7 KiB
JavaScript

const axios = require("axios");
const WebSocket = require("ws");
const EventEmitter = require("events");
const API_BASE_URL = "https://kvs.wireway.ch/v2";
class WireKVSDatabase extends EventEmitter {
constructor(id, accessKey) {
super();
this.id = id;
this.accessKey = accessKey;
this.ws = null;
this.isConnected = false;
this.keepAliveInterval = null;
this._eventHandlers = new Map();
this._setupWebSocket();
}
_setupWebSocket() {
const wsUrl = `wss://kvs.wireway.ch/events/${
this.id
}?accessKey=${encodeURIComponent(this.accessKey)}`;
this.ws = new WebSocket(wsUrl);
this.ws.on("open", () => {
this.isConnected = true;
this.emit("connected");
});
this.ws.on("close", () => {
this.isConnected = false;
this.emit("disconnected");
if (this.keepAliveInterval) {
clearInterval(this.keepAliveInterval);
this.keepAliveInterval = null;
}
if (!this._disconnecting) {
setTimeout(() => this._setupWebSocket(), 5000);
}
});
this.ws.on("message", (data) => {
try {
const message = JSON.parse(data);
if (message.type === "ping") {
return;
}
if (message.type === "error") {
console.error("WebSocket error from server:", message.message);
this.emit("error", new Error(message.message));
if (
message.message === "KVSDB not found" ||
message.message === "Forbidden"
) {
this.disconnect();
return;
}
}
this.emit(message.type, message);
} catch (error) {
console.error("Error parsing WebSocket message:", error);
}
});
this.ws.on("error", (error) => {
console.error("WebSocket error:", error);
this.emit("error", error);
});
}
on(event, handler) {
super.on(event, handler);
if (!this._eventHandlers.has(event)) {
this._eventHandlers.set(event, new Set());
}
this._eventHandlers.get(event).add(handler);
return this;
}
off(event, handler) {
if (handler) {
super.removeListener(event, handler);
const handlers = this._eventHandlers.get(event);
if (handlers) {
handlers.delete(handler);
}
} else {
const handlers = this._eventHandlers.get(event);
if (handlers) {
handlers.forEach((h) => super.removeListener(event, h));
handlers.clear();
}
}
return this;
}
disconnect() {
this._disconnecting = true;
this._eventHandlers.forEach((handlers, event) => {
handlers.forEach((handler) => super.removeListener(event, handler));
});
this._eventHandlers.clear();
if (this.ws) {
if (this.keepAliveInterval) {
clearInterval(this.keepAliveInterval);
this.keepAliveInterval = null;
}
this.ws.close();
this.ws = null;
}
this.isConnected = false;
}
async getAllEntries() {
const response = await axios.get(`${API_BASE_URL}/database/${this.id}`, {
headers: { Authorization: this.accessKey },
});
return response.data;
}
async get(key) {
const response = await axios.get(
`${API_BASE_URL}/database/${this.id}/${key}`,
{
headers: { Authorization: this.accessKey },
}
);
return response.data;
}
async set(key, value) {
await axios.post(`${API_BASE_URL}/database/${this.id}/${key}`, value, {
headers: { Authorization: this.accessKey },
});
}
async update(key, value) {
await axios.patch(`${API_BASE_URL}/database/${this.id}/${key}`, value, {
headers: { Authorization: this.accessKey },
});
}
async delete(key) {
await axios.delete(`${API_BASE_URL}/database/${this.id}/${key}`, {
headers: { Authorization: this.accessKey },
});
}
async search(query) {
const response = await axios.post(
`${API_BASE_URL}/databaseSearch/${this.id}`,
query,
{
headers: { Authorization: this.accessKey },
}
);
return response.data;
}
}
class WireKVS {
constructor(token) {
this.token = token;
}
static connect(id, accessKey) {
return new WireKVSDatabase(id, accessKey);
}
async listDatabases() {
const response = await axios.get(`${API_BASE_URL}/databases`, {
headers: { Authorization: this.token },
});
return response.data;
}
async createDatabase({
name,
allowPublicWrites = false,
allowPublicReads = false,
allowPublicModifications = false,
allowSpecificPublicReads = false,
}) {
const response = await axios.post(
`${API_BASE_URL}/database`,
{
name,
allowPublicWrites,
allowPublicReads,
allowPublicModifications,
allowSpecificPublicReads,
},
{
headers: { Authorization: this.token },
}
);
return response.data;
}
async updateDatabase(
id,
{
name,
allowPublicWrites,
allowPublicReads,
allowPublicModifications,
allowSpecificPublicReads,
}
) {
const response = await axios.patch(
`${API_BASE_URL}/database/${id}`,
{
name,
allowPublicWrites,
allowPublicReads,
allowPublicModifications,
allowSpecificPublicReads,
},
{
headers: { Authorization: this.token },
}
);
return response.data;
}
async deleteDatabase(id) {
await axios.delete(`${API_BASE_URL}/database/${id}`, {
headers: { Authorization: this.token },
});
}
async truncateDatabase(id) {
await axios.delete(`${API_BASE_URL}/databaseTruncate/${id}`, {
headers: { Authorization: this.token },
});
}
database(id, accessKey) {
return new WireKVSDatabase(id, accessKey);
}
}
module.exports = WireKVS;