UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

149 lines (148 loc) 5.56 kB
/** * HttpStorage.ts * * ARCHITECTURE DOCUMENTATION * ========================== * * HttpStorage is a client-side storage implementation that fetches content * via HTTP and receives real-time updates via WebSocket notifications. * * REAL-TIME SYNCHRONIZATION: * -------------------------- * 1. HttpStorage connects to /ws/notifications WebSocket endpoint * 2. Subscribes to file/folder change events for specific slots * 3. When notifications arrive, converts them to standard IStorage events * 4. Consumers (MCWorld, etc.) subscribe to these events * * DATA FLOW: * ---------- * NodeStorage (fs.watch) -> HttpServer (broadcast) -> WebSocket -> * HttpStorage (this) -> notifyFileAdded/Removed/Updated -> MCWorld -> WorldView * * WEBSOCKET PROTOCOL: * ------------------- * - Connect: ws://host:port/ws/notifications?token=<authToken> * - Subscribe: { header: {..., messageType: "subscriptionRequest", messagePurpose: "subscribe" }, * body: { eventNames: ["fileChanged", "fileAdded", ...], slot: 0 } } * - Receive: IServerNotification messages with file/folder change details * * RELATED FILES: * -------------- * - IServerNotification.ts: WebSocket message format definitions * - IStorageWatcher.ts: INotificationReceiver interface * - HttpServer.ts: Server-side WebSocket broadcaster * - NodeStorage.ts: Server-side file watcher source * * USAGE: * ------ * const storage = HttpStorage.get("http://localhost:6126/api/worldContent/0/"); * storage.authToken = "encrypted-token"; * await storage.connectToNotifications(); * storage.onFileAdded.subscribe((sender, file) => console.log("File added:", file.name)); */ import HttpFolder from "./HttpFolder"; import StorageBase from "./StorageBase"; import IStorage from "./IStorage"; import { INotificationReceiver } from "./IStorageWatcher"; export default class HttpStorage extends StorageBase implements IStorage, INotificationReceiver { rootFolder: HttpFolder; baseUrl: string; /** * Bearer token for Authorization header. * When set, requests will include "Authorization: Bearer <token>" header. * This is used for authenticated endpoints like /api/content. */ authToken?: string; /** * When true (default), the storage is read-only and write operations will throw. * Set to false to enable HTTP PUT/DELETE operations for editing content. */ readOnly: boolean; /** WebSocket connection for receiving notifications */ private _webSocket; /** Currently subscribed event names */ private _subscribedEvents; /** Server slot this storage is associated with (for filtering notifications) */ private _slot?; /** Whether we're currently connected to the notification server */ private _isConnected; /** Reconnection timer */ private _reconnectTimer?; /** Whether auto-reconnect is enabled */ private _autoReconnect; /** * Event fired when the server sends a shutdown notification. * This indicates the entire MCT server is shutting down (not just a BDS instance). * Subscribers should show appropriate UI feedback and disable auto-reconnect. * Args: (reason: string, graceful: boolean) */ private _onServerShutdown; /** * Subscribe to server shutdown notifications. * This is fired when the MCT server is about to shut down. */ get onServerShutdown(): import("ste-events").IEvent<HttpStorage, { reason: string; graceful: boolean; }>; /** * Static cache of HttpStorage instances by base URL. * Used to avoid creating duplicate storage instances for the same URL. */ private static _storageCache; /** * Get or create an HttpStorage instance for the given base URL. * Reuses cached instances to avoid creating duplicates. * @param baseUrl The base URL for the storage * @returns A cached or new HttpStorage instance */ static get(baseUrl: string): HttpStorage; /** * Clear the storage cache. Useful for testing or when storage should be refreshed. */ static clearCache(): void; constructor(newUrl: string); getAvailable(): Promise<boolean>; get isConnected(): boolean; /** * Get the underlying WebSocket connection. * Can be used to listen for raw notifications (e.g., debug stats). */ get webSocket(): WebSocket | null; /** * Set the slot number for filtering notifications. */ set slot(value: number | undefined); get slot(): number | undefined; /** * Connect to the WebSocket notification endpoint. * The WebSocket URL is derived from the baseUrl. * * @param url Optional override URL for the WebSocket endpoint * @param authToken Optional auth token (uses this.authToken if not provided) */ connect(url?: string, authToken?: string): Promise<void>; /** * Disconnect from the WebSocket notification server. */ disconnect(): void; /** * Subscribe to specific event types. * * @param eventNames Array of event names to subscribe to * @param slot Optional slot number to filter events */ subscribe(eventNames: string[], slot?: number): Promise<void>; /** * Unsubscribe from specific event types. */ unsubscribe(eventNames: string[]): Promise<void>; /** * Send a subscription request to the server. */ private _sendSubscription; /** * Handle an incoming notification message. */ private _handleNotification; }