UNPKG

@pureweb/platform-streaming-agent

Version:

The PureWeb platform streaming agent enables your game to communicate and stream through the PureWeb Platform

255 lines (254 loc) 13.6 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable @typescript-eslint/no-unused-vars */ const platform_sdk_1 = require("@pureweb/platform-sdk"); const platform_sdk_2 = require("@pureweb/platform-sdk"); const Log_1 = __importDefault(require("./Log")); const SidecarExtension_1 = require("./extensions/sidecar/SidecarExtension"); const LeasingExtension_1 = require("./extensions/leasing/LeasingExtension"); const StreamExtension_1 = require("./extensions/stream/StreamExtension"); const PresenceMonitorExtension_1 = require("./extensions/presence/PresenceMonitorExtension"); const SteamVRLogMonitorExtension_1 = require("./extensions/ovr/SteamVRLogMonitorExtension"); const Configuration_1 = require("./Configuration"); const yargs_1 = __importDefault(require("yargs")); const boxen_1 = __importDefault(require("boxen")); const ConnectionStates_1 = require("./ConnectionStates"); const ExitCodes_1 = require("./ExitCodes"); const RuntimeExtension_1 = require("./extensions/runtime/RuntimeExtension"); function showBanner(agent, platform, configuration) { const info = new platform_sdk_2.Info(); let streamerDetails; streamerDetails = `PureWeb Streaming Agent ${platform_sdk_1.PlatformNext.version}\n\n`; streamerDetails += `SDK version: ${info.sdkVersion}\n`; streamerDetails += `Configuration file: ${configuration.configFile}\n`; streamerDetails += `Agent id: ${agent.id}\n`; streamerDetails += `Project id: ${platform.credentials.projectId}\n`; streamerDetails += `Environment id: ${platform.credentials.environmentId}\n`; streamerDetails += `\n`; streamerDetails += `Streamer Port: ${configuration.streamerPort}\n`; streamerDetails += `Leasing Enabled: ${configuration.leaseUrl ? `YES [${configuration.leaseUrl}]` : 'NO'}\n`; streamerDetails += `Sidecar Port: ${configuration.sidecarPort ? `YES [${configuration.sidecarPort}]` : 'NO'}\n`; streamerDetails += `Stream service: ${configuration.streamService ? configuration.streamService : 'webRTC'}\n`; streamerDetails += `\n`; streamerDetails += `Timeouts\n`; streamerDetails += `\n`; streamerDetails += ` Rendezvous: ${configuration.rendezvousTimeoutSeconds > -1 ? `YES [${configuration.rendezvousTimeoutSeconds} seconds]` : 'NO'}\n`; streamerDetails += ` Streamer Rendezvous: ${configuration.streamerTimeoutSeconds > -1 ? `YES [${configuration.streamerTimeoutSeconds} seconds]` : 'NO'}\n`; streamerDetails += ` Streamer Claimed Timeout: ${configuration.claimedTimeoutSeconds ? `YES [${configuration.claimedTimeoutSeconds} seconds]` : 'NO'}\n`; streamerDetails += ` Maximum runtime: ${configuration.maximumRuntime > -1 ? `YES [${configuration.maximumRuntime} seconds]` : 'NO'}\n`; streamerDetails += ` Linger: ${configuration.lingerTimeoutSeconds > -1 ? `YES [${configuration.lingerTimeoutSeconds} seconds]` : 'NO'}\n`; streamerDetails += ` Standby Mode: ${configuration.standbyMode === true ? 'YES' : 'NO'}\n`; Log_1.default.info('\n' + (0, boxen_1.default)(streamerDetails, { padding: 1 })); } async function startServices(agent, platform, configuration) { try { let leasingService; let sidecarService; const steamVRMonitor = new SteamVRLogMonitorExtension_1.SteamVRLogMonitorExtension(); // Presence Monitor Extension const presenceMonitor = new PresenceMonitorExtension_1.PresenceMonitorExtension(); // Streaming Extension const streamService = new StreamExtension_1.StreamExtension(); // runtime Extension const runtimeService = new RuntimeExtension_1.RuntimeExtension(); let agentEnvReconnectTimer = null; agent.onConnection((state) => { Log_1.default.info('Agent connection state changed: ' + state); switch (state) { case platform_sdk_1.AgentConnectionStatus.INITIALIZING: break; case platform_sdk_1.AgentConnectionStatus.CONNECTED: if (agentEnvReconnectTimer) { clearTimeout(agentEnvReconnectTimer); agentEnvReconnectTimer = null; } streamService.reconnect(); break; case platform_sdk_1.AgentConnectionStatus.OFFLINE: if (!agentEnvReconnectTimer) { agentEnvReconnectTimer = setTimeout(() => { connectionStateChanged(configuration, ConnectionStates_1.ConnectionStates.AGENT_DISCONNECTED); }, configuration.reconnectTimeoutMilliseconds); } break; case platform_sdk_1.AgentConnectionStatus.ERROR: connectionStateChanged(configuration, ConnectionStates_1.ConnectionStates.AGENT_DISCONNECTED); break; default: Log_1.default.info('Unhandled agent connection state: ' + state); break; } }); // Runtime Monitor Extension Initializatin runtimeService.onStateChanged((state) => { connectionStateChanged(configuration, state); }); runtimeService.initialize(agent, configuration, platform, presenceMonitor); await runtimeService.start(); Log_1.default.info('Runtime monitor started'); // Presence Monitor Extension Initialization presenceMonitor.onStateChanged((state) => { connectionStateChanged(configuration, state); }); if (configuration.streamService === 'cloudXR') { steamVRMonitor.onStateChanged((state) => { connectionStateChanged(configuration, state); }); steamVRMonitor.initialize(agent, configuration, platform, presenceMonitor); await steamVRMonitor.start(); Log_1.default.info('steamVRMonitor started'); } else { presenceMonitor.initialize(agent, configuration, platform); await presenceMonitor.start(); Log_1.default.info('Presence monitor started'); // Streaming Extension Initialization streamService.onStateChanged((state) => { connectionStateChanged(configuration, state); }); streamService.initialize(agent, configuration, platform, presenceMonitor); await streamService.start(); Log_1.default.info('Streaming service started'); } // Lease Extension if (configuration.leaseUrl) { leasingService = new LeasingExtension_1.LeasingExtension(); leasingService.onStateChanged((state) => { connectionStateChanged(configuration, state); }); leasingService.initialize(agent, configuration); await leasingService.start(); Log_1.default.info('Leasing service started'); } else { Log_1.default.warn('Leasing service diabled. No Lease URL provided'); } // Sidecar Extension if (configuration.sidecarPort) { sidecarService = new SidecarExtension_1.SidecarExtension(); sidecarService.onStateChanged((state) => { connectionStateChanged(configuration, state); }); sidecarService.initialize(agent, configuration); await sidecarService .start() .then(() => { Log_1.default.info('Sidecar service started'); }) .catch((reason) => { Log_1.default.error('Failed to start sidecar service'); return Promise.reject(reason); }); } else { Log_1.default.warn('Sidecar service diabled. No sidecar provided'); } } catch (err) { return Promise.reject(err); } } function connectionStateChanged(configuration, state) { if (state === ConnectionStates_1.ConnectionStates.GRPC_DISCONNECTED && configuration.shutdownOnDisconnect) { Log_1.default.info('Sidecar disconnected, Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorGRPCDisconnected); } else if (state === ConnectionStates_1.ConnectionStates.GRPC_TIMEOUT) { Log_1.default.info('Sidecar connection timeout, Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorGRPCTimeout); } else if (state === ConnectionStates_1.ConnectionStates.LEASE_DENIED) { Log_1.default.info('Lease was denied, Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorLeaseDenied); } else if (state === ConnectionStates_1.ConnectionStates.STREAMER_PORT_UNAVAILABLE) { Log_1.default.info('Streamer port unavailable, Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorStreamerPortUnavailable); } else if (state === ConnectionStates_1.ConnectionStates.AGENT_RENDEZVOUS_MISSED) { Log_1.default.info('No agent peer arrived within the rendezvous window. Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorAgentRendezvousMissed); } else if (state === ConnectionStates_1.ConnectionStates.STREAMER_RENDEZVOUS_MISSED) { Log_1.default.info('No Streamer connected within the rendezvous window. Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorStreamerRendezvousMissed); } else if (state === ConnectionStates_1.ConnectionStates.AGENT_DISCONNECTED) { Log_1.default.info('Disconnected from agent environment. Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorAgentDisconnected); } else if (state === ConnectionStates_1.ConnectionStates.PEERS_EXITED) { Log_1.default.info('All agent peers have left the environment. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.None); } else if (state === ConnectionStates_1.ConnectionStates.INTERNAL_ERROR) { Log_1.default.info('Internal error detected, Streaming Agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorUnknown); } else if (state === ConnectionStates_1.ConnectionStates.STREAMER_CONNECTION_ERROR) { Log_1.default.info('Streamer encounter connection error. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorStreamerConnection); } else if (state === ConnectionStates_1.ConnectionStates.STREAMER_DISCONNECTED) { Log_1.default.info('Streamer disconnected. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorStreamerDisconnected); } else if (state === ConnectionStates_1.ConnectionStates.STREAMER_DUPLICATE_CONNECTION) { Log_1.default.info('The second streamer attempting connection. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorDuplicateStreamer); } else if (state === ConnectionStates_1.ConnectionStates.MAXIMUM_RUNTIME_REACHED) { Log_1.default.info('Maximum runtime reached. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.ErrorMaximumRuntimeReached); } else if (state === ConnectionStates_1.ConnectionStates.STANDBY_TIMEOUT) { Log_1.default.info('Standby timeout reached. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.None); } else if (state === ConnectionStates_1.ConnectionStates.TERMINATED) { Log_1.default.info('Streaming agent terminated'); process.exit(ExitCodes_1.ExitCodes.None); } else if (state === ConnectionStates_1.ConnectionStates.CLAIMED_TIMOUT) { Log_1.default.info('Launch request claimed timeout reached. Streaming agent shutting down'); process.exit(ExitCodes_1.ExitCodes.None); } else { return; } } async function main() { try { const configuration = new Configuration_1.Configuration(); configuration.init(yargs_1.default.argv, process.env); const credentials = new platform_sdk_1.PlatformCredentials(); credentials.agent = configuration.agentToken; const platform = new platform_sdk_1.PlatformNext(); platform.initialize({ endpoint: credentials.agent.issuer }); platform.credentials = credentials; // parse launch request id, if available const launchRequestId = configuration.leaseUrl ? configuration.leaseUrl.substring(configuration.leaseUrl.lastIndexOf('/') + 1) : undefined; Log_1.default.settings.minLevel = +configuration.logLevel; const agent = await platform.connect(); showBanner(agent, platform, configuration); startServices(agent, platform, configuration) .then(() => { Log_1.default.info(`Streaming agent services started successfully`); }) .catch((reason) => { Log_1.default.error(`Streaming agent services failed to start: ${reason}`); process.exit(ExitCodes_1.ExitCodes.ErrorUnknown); }); } catch (exception) { Log_1.default.error(`Streaming agent startup failed: ${exception}`); process.exit(ExitCodes_1.ExitCodes.ErrorUnknown); } } main();