From 17381406e0c0e2d61220bfaa293792c34cd99f1c Mon Sep 17 00:00:00 2001 From: Marcel Lorbeer Date: Mon, 3 Jul 2023 21:36:24 +0200 Subject: [PATCH] Added Subscriptions --- src/SubscriptionManager.ts | 81 ++++++++++++++++++++++++++++++++++++++ src/marcsync.ts | 16 +++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/SubscriptionManager.ts diff --git a/src/SubscriptionManager.ts b/src/SubscriptionManager.ts new file mode 100644 index 0000000..cf5ee82 --- /dev/null +++ b/src/SubscriptionManager.ts @@ -0,0 +1,81 @@ +import { BaseEntry, Entry, EntryData } from "./Entry"; +import { ClientEvents } from "./marcsync"; +import * as signalR from "@microsoft/signalr"; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +export class SubscriptionManager { + + private _subscriptions: Record void)[]>; + private _hubConnection: signalR.HubConnection; + private _accessToken: string; + + + constructor(accessToken: string) { + this._accessToken = accessToken; + this._subscriptions = {} as Record void)[]>; + this._hubConnection = new signalR.HubConnectionBuilder() + .withUrl("https://ws.marcsync.dev/websocket?access_token=Bearer " + accessToken, { + skipNegotiation: true, + transport: signalR.HttpTransportType.WebSockets + }) + .configureLogging(signalR.LogLevel.None) + .build(); + this._hubConnection.start() + .catch(err => { + console.error(err.toString()); + process.exit(1); + }); + this.handleSubscriptions(); + } + + subscribe(subscription: keyof ClientEvents, callback: () => void) { + if (!this._subscriptions[subscription]) this._subscriptions[subscription] = []; + this._subscriptions[subscription].push(callback); + } + + private async handleSubscriptions() { + this._hubConnection.on("entryCreated", (e: string) => { + let d = JSON.parse(e) as EntryCreatedEvent; + this._subscriptions.entryCreated.forEach(callback => { try { callback(new Entry(this._accessToken, d.data.collectionName, d.data.values), d.databaseId, d.timestamp) } catch(e) {console.error(e)} }); + }); + this._hubConnection.on("entryDeleted", (e: string) => { + let d = JSON.parse(e) as EntryDeletedEvent; + this._subscriptions.entryDeleted.forEach(callback => { try { callback(new BaseEntry(d.data.values, d.data.collectionName), d.databaseId, d.timestamp) } catch(e) {console.error(e)} }); + }) + this._hubConnection.on("entryUpdated", (e: string) => { + let d = JSON.parse(e) as EntryUpdatedEvent; + this._subscriptions.entryUpdated.forEach(callback => { try { callback(new BaseEntry(d.data.oldValues, d.data.collectionName), new Entry(this._accessToken, d.data.collectionName, d.data.newValues), d.databaseId, d.timestamp) } catch(e) {console.error(e)} }); + }) + } + +} + +export interface BaseEvent { + databaseId: string; + timestamp: number; + type: number; +} + +export interface EntryCreatedEvent extends BaseEvent { + data: { + collectionName: string; + values: EntryData; + }; +} + +export interface EntryDeletedEvent extends BaseEvent { + data: { + collectionName: string; + values: EntryData; + }; +} + +export interface EntryUpdatedEvent extends BaseEvent { + data: { + collectionName: string; + oldValues: EntryData; + newValues: EntryData; + }; +} \ No newline at end of file diff --git a/src/marcsync.ts b/src/marcsync.ts index 44d53b6..8793627 100644 --- a/src/marcsync.ts +++ b/src/marcsync.ts @@ -1,9 +1,11 @@ import { Collection, CollectionAlreadyExists, CollectionNotFound } from "./Collection"; -import { Entry, EntryData } from "./Entry"; +import { BaseEntry, Entry } from "./Entry"; +import { SubscriptionManager } from "./SubscriptionManager"; export class Client { private _accessToken: string; + private _subscriptions: SubscriptionManager; /** * @@ -12,6 +14,7 @@ export class Client { * */ constructor(accessToken: string) { + this._subscriptions = new SubscriptionManager(accessToken); this._accessToken = accessToken; } @@ -97,10 +100,21 @@ export class Client { } return new Collection(this._accessToken, collectionName); } + + public on(event: K, listener: (...args: ClientEvents[K]) => void): this { + this._subscriptions.subscribe(event, listener); + return this; + }; } export class Unauthorized extends Error { constructor(message: string = "Invalid access token") { super(message); } +} + +export interface ClientEvents { + entryCreated: [entry: Entry, databaseId: string, timestamp: number]; + entryUpdated: [oldEntry: BaseEntry, newEntry: Entry, databaseId: string, timestamp: number]; + entryDeleted: [entry: BaseEntry, databaseId: string, timestamp: number]; } \ No newline at end of file