UNPKG

@komponent/unifi-protect-lib

Version:

Node library for connecting to Ubiquiti Unifi Protect controllers and listen for events

87 lines 4.19 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); const url_1 = require("url"); class UnifiImageHandler { constructor(log, apiClient) { this.log = log; this.apiClient = apiClient; this.snapshotCache = {}; } async getSnapshot(request) { const params = new url_1.URLSearchParams({ force: "true" }); if (!request || !request.camera) { return null; } // If we aren't connected, we're done. if (request.camera.state !== "CONNECTED") { this.log.error("%s: Unable to retrieve a snapshot: the camera is offline or unavailable.", request.camera.name); return null; } // If we have details of the snapshot request, use it to request the right size. if (request.width && request.height) { params.append("width", request.width.toString()); params.append("height", request.height.toString()); } const snapshotUrl = `${this.apiClient.camerasUrl}/${request.camera.id}/snapshot`; // Request the image from the controller. const response = await this.apiClient.fetch(`${snapshotUrl}?${params.toString()}`, { method: "GET", responseType: "arraybuffer" }); // Occasional snapshot failures will happen. The controller isn't always able to generate them if // it's already generating one, or it's requested too quickly after the last one. if (!response || response.status != 200) { // See if we have an image cached that we can use instead. const cachedSnapshot = this.getCachedSnapshot(request.camera.mac); if (cachedSnapshot) { this.log.error("%s: Unable to retrieve a snapshot. Using the most recent cached snapshot instead.", request.camera.name); return cachedSnapshot; } this.log.error("%s: Unable to retrieve a snapshot. %s", request.camera.name, response ? `${response.status.toString()} - ${response.statusText}.` : "No response from API"); return null; } try { // Retrieve the image. const buffer = Buffer.from(response.data, "base64"); this.snapshotCache[request.camera.mac] = { image: buffer, time: Date.now(), }; return buffer; } catch (error) { if (axios_1.default.isAxiosError(error)) { let cachedSnapshot; switch (error.code) { case "ERR_STREAM_PREMATURE_CLOSE": cachedSnapshot = this.getCachedSnapshot(request.camera.mac); if (cachedSnapshot) { this.log.error("%s: Unable to retrieve a snapshot. Using a cached snapshot instead.", request.camera.name); return cachedSnapshot; } this.log.error("%s: Unable to retrieve a snapshot: the Protect controller closed the connection prematurely.", request.camera.name); return null; default: this.log.error("%s: Unknown error: %s", request.camera.name, error.message); return null; } } this.log.error("%s: An error occurred while making a snapshot request: %s.", request.camera.name, error); return null; } } getCachedSnapshot(cameraMac) { // If we have an image from the last few seconds, we can use it. Otherwise, we're done. if (!this.snapshotCache[cameraMac] || Date.now() - this.snapshotCache[cameraMac].time > 60 * 1000) { delete this.snapshotCache[cameraMac]; return null; } return this.snapshotCache[cameraMac].image; } } exports.default = UnifiImageHandler; //# sourceMappingURL=UnifiImageHandler.js.map