theater-client
Version:
TypeScript client library for Theater actor system TCP protocol
184 lines • 5.54 kB
JavaScript
/**
* Actor wrapper class - provides ergonomic interface around an actor ID
*/
import { TheaterConnectionError } from '../types/client.js';
import { encodeJson, decodeJson } from '../utils/serialization.js';
import { createLogger } from '../utils/logger.js';
const log = createLogger('Actor');
/**
* Actor wrapper that provides a clean, object-oriented interface
* around an actor ID, automatically filling in the ID for all operations
*/
export class Actor {
id;
client;
// Separate connection just for event streaming
eventConnection;
callbacks;
constructor(id, client, eventConnection, callbacks) {
this.id = id;
this.client = client;
this.eventConnection = eventConnection || undefined;
this.callbacks = callbacks || undefined;
if (this.eventConnection && this.callbacks) {
this.setupEventHandling();
}
}
// ===== ACTOR MANAGEMENT =====
/**
* Get the current status of this actor
*/
async getStatus() {
return this.client.getActorStatus(this.id);
}
/**
* Restart this actor
*/
async restart() {
return this.client.restartActor(this.id);
}
/**
* Stop this actor
*/
async stop() {
// Stop the actor via hygienic connection
await this.client.stopActor(this.id);
// Clean up event connection
this.eventConnection?.close();
}
/**
* Get the manifest configuration of this actor
*/
async getManifest() {
return this.client.getActorManifest(this.id);
}
/**
* Get the current state of this actor
*/
async getState() {
return this.client.getActorState(this.id);
}
/**
* Get the event history for this actor
*/
async getEvents() {
return this.client.getActorEvents(this.id);
}
/**
* Get metrics for this actor
*/
async getMetrics() {
return this.client.getActorMetrics(this.id);
}
// ===== MESSAGING =====
/**
* Send raw bytes to this actor (fire-and-forget)
*/
async sendBytes(data) {
return this.client.sendActorMessage(this.id, data);
}
/**
* Send raw bytes to this actor and wait for response
*/
async requestBytes(data) {
return this.client.requestActorMessage(this.id, data);
}
/**
* Send a JSON object to this actor (fire-and-forget)
*/
async sendJson(obj) {
return this.sendBytes(encodeJson(obj));
}
/**
* Send a JSON object to this actor and wait for JSON response
*/
async requestJson(obj) {
const response = await this.requestBytes(encodeJson(obj));
return decodeJson(response);
}
/**
* Send a string to this actor (fire-and-forget)
*/
async sendString(text) {
return this.sendBytes(new TextEncoder().encode(text));
}
/**
* Send a string to this actor and wait for string response
*/
async requestString(text) {
const response = await this.requestBytes(new TextEncoder().encode(text));
return new TextDecoder().decode(response);
}
// ===== REAL-TIME COMMUNICATION =====
/**
* Open a communication channel with this actor
*/
async openChannel(initialMessage) {
return this.client.openChannel({ Actor: this.id }, initialMessage);
}
/**
* Subscribe to events from this actor
*/
async subscribe() {
return this.client.subscribeToActor(this.id);
}
// ===== SUPERVISION =====
/**
* Check if this actor has supervision (event stream connection)
*/
get isSupervised() {
return !!this.eventConnection;
}
/**
* Set up event handling for supervised actors
*/
setupEventHandling() {
if (!this.eventConnection || !this.callbacks)
return;
log.info(`Setting up event handling for supervised actor: ${this.id}`);
// Listen for events on the dedicated connection
this.eventConnection.onMessage((response) => {
if ('ActorEvent' in response && response.ActorEvent) {
this.callbacks?.onEvent?.(response.ActorEvent.event);
}
else if ('ActorError' in response && response.ActorError) {
this.callbacks?.onError?.(response.ActorError.error);
}
else if ('ActorResult' in response && response.ActorResult) {
this.callbacks?.onActorResult?.(response.ActorResult);
}
});
this.eventConnection.onError((error) => {
// Fail fast - let the application deal with it
const connectionError = new TheaterConnectionError(`Event stream connection failed for actor ${this.id}: ${error.message}`, error);
log.error(`Event stream connection failed for actor ${this.id}`, error);
throw connectionError;
});
}
// ===== UTILITY METHODS =====
/**
* String representation of this actor (returns the ID)
*/
toString() {
return this.id;
}
/**
* Check if this actor has the same ID as another actor
*/
equals(other) {
return this.id === other.id;
}
/**
* Get a JSON representation of this actor
*/
toJSON() {
return { id: this.id };
}
/**
* Check if this actor represents the same ID as a string
*/
hasId(id) {
return this.id === id;
}
}
//# sourceMappingURL=Actor.js.map