alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
94 lines (83 loc) • 2.66 kB
text/typescript
import { $hook, $inject, Alepha, AlephaError } from "alepha";
import { $logger } from "alepha/logger";
import { BunRedisProvider } from "./BunRedisProvider.ts";
import {
RedisSubscriberProvider,
type SubscribeCallback,
} from "./RedisSubscriberProvider.ts";
/**
* Bun Redis subscriber provider for pub/sub operations.
*
* This provider creates a dedicated Redis connection for subscriptions,
* as Redis requires separate connections for pub/sub operations.
*
* @example
* ```ts
* const subscriber = alepha.inject(RedisSubscriberProvider);
* await subscriber.subscribe("channel", (message, channel) => {
* console.log(`Received: ${message} on ${channel}`);
* });
* ```
*/
export class BunRedisSubscriberProvider extends RedisSubscriberProvider {
protected readonly log = $logger();
protected readonly alepha = $inject(Alepha);
protected readonly redisProvider = $inject(BunRedisProvider);
protected client?: Bun.RedisClient;
public get subscriber(): Bun.RedisClient {
if (!this.client?.connected) {
throw new AlephaError("Redis subscriber client is not ready");
}
return this.client;
}
public override get isReady(): boolean {
return this.client?.connected ?? false;
}
protected readonly start = $hook({
on: "start",
handler: () => this.connect(),
});
protected readonly stop = $hook({
on: "stop",
handler: () => this.close(),
});
/**
* Connect to the Redis server for subscriptions.
*/
public override async connect(): Promise<void> {
this.log.debug("Connecting subscriber...");
this.client = await this.redisProvider.duplicate();
this.log.info("Subscriber connection OK");
}
/**
* Close the subscriber connection.
*/
public override async close(): Promise<void> {
if (this.client) {
this.log.debug("Closing subscriber connection...");
this.client.close();
this.client = undefined;
this.log.info("Subscriber connection closed");
}
}
public override async subscribe(
channel: string,
callback: SubscribeCallback,
): Promise<void> {
await this.subscriber.subscribe(channel, (message, ch) => {
// Bun's callback provides Buffer or string, normalize to string
const msg =
typeof message === "object" && message !== null
? Buffer.from(message as Uint8Array).toString()
: String(message);
callback(msg, ch);
});
}
public override async unsubscribe(
channel: string,
_callback?: SubscribeCallback,
): Promise<void> {
// Bun's unsubscribe doesn't support callback filtering
await this.subscriber.unsubscribe(channel);
}
}