UNPKG

camstreamerlib

Version:

Helper library for CamStreamer ACAP applications.

216 lines (215 loc) 8.79 kB
import { paramToUrl } from './internal/utils'; import { ParsingBlobError, ErrorWithResponse, ServiceNotFoundError, StorageDataFetchError } from './errors/errors'; import { networkCameraListSchema } from './types/common'; import { z } from 'zod'; import { ProxyClient } from './internal/ProxyClient'; import { fileListSchema, ImageType, storageDataListSchema, serviceListSchema, servicesSchema, wsResponseSchema, } from './types/CamOverlayAPI'; const BASE_PATH = '/local/camoverlay/api'; export class CamOverlayAPI { client; constructor(client) { this.client = client; } static getBasePath = () => BASE_PATH; static getProxyPath = () => `${BASE_PATH}/proxy.cgi`; static getFilePreviewPath = (path) => `${BASE_PATH}/image.cgi?path=${encodeURIComponent(path)}`; getClient(proxyParams) { return proxyParams ? new ProxyClient(this.client, proxyParams) : this.client; } async checkCameraTime(options) { const res = await this._getJson(`${BASE_PATH}/camera_time.cgi`, undefined, options); return z.boolean().parse(res.state); } async getNetworkCameraList(options) { const res = await this._getJson(`${BASE_PATH}/network_camera_list.cgi`, undefined, options); return networkCameraListSchema.parse(res.camera_list); } async wsAuthorization(options) { const res = await this._getJson(`${BASE_PATH}/ws_authorization.cgi`, undefined, options); return wsResponseSchema.parse(res).message; } async getMjpegStreamImage(mjpegUrl, options) { return await this._getBlob(`${BASE_PATH}/fetch_mjpeg_image.cgi`, { mjpeg_url: decodeURIComponent(mjpegUrl) }, options); } async listFiles(fileType, options) { const res = await this._getJson(`${BASE_PATH}/upload_${fileType}.cgi`, { action: 'list' }, options); return fileListSchema.parse(res.list); } async uploadFile(fileType, formData, storage, options) { await this._post(`${BASE_PATH}/upload_${fileType}.cgi`, formData, { action: 'upload', storage: storage, }, options); } async removeFile(fileType, fileParams, options) { await this._postUrlEncoded(`${BASE_PATH}/upload_${fileType}.cgi`, { action: 'remove', ...fileParams, }, options, undefined); } async getFileStorage(fileType, options) { const res = await this._getJson(`${BASE_PATH}/upload_${fileType}.cgi`, { action: 'get_storage' }, options); if (res.code !== 200) { throw new StorageDataFetchError(res); } return storageDataListSchema.parse(res.list); } async getFilePreviewFromCamera(path, options) { return await this._getBlob(CamOverlayAPI.getFilePreviewPath(path), undefined, options); } async updateInfoticker(serviceId, text, options) { await this._getJson(`${BASE_PATH}/infoticker.cgi`, { service_id: serviceId, text: text }, options); } async setEnabled(serviceId, enabled, options) { await this._post(`${BASE_PATH}/enabled.cgi`, '', { [`id_${serviceId}`]: enabled ? 1 : 0 }, options); } async isEnabled(serviceId, options) { const agent = this.getClient(options?.proxyParams); const res = await agent.get({ path: `${BASE_PATH}/services.cgi`, parameters: { action: 'get' }, timeout: options?.timeout, }); if (res.ok) { const data = JSON.parse(await res.text()); for (const service of data.services) { if (service.id === serviceId) { return service.enabled === 1; } } throw new ServiceNotFoundError(); } else { throw new ErrorWithResponse(res); } } async getSingleService(serviceId, options) { const res = await this._getJson(`${BASE_PATH}/services.cgi`, { action: 'get', service_id: serviceId, }, options); return servicesSchema.parse(res); } async getServices(options) { const res = await this._getJson(`${BASE_PATH}/services.cgi`, { action: 'get' }, options); const services = serviceListSchema.parse(res).services; return services; } async updateSingleService(service, options) { await this._postJsonEncoded(`${BASE_PATH}/services.cgi`, JSON.stringify(service), { action: 'set', service_id: service.id, }, options, undefined); } async updateServices(services, options) { await this._postJsonEncoded(`${BASE_PATH}/services.cgi`, JSON.stringify({ services: services }), { action: 'set', }, options, undefined); } updateCGText(serviceId, fields, options) { const params = {}; for (const field of fields) { const name = field.field_name; params[name] = field.text; if (field.color !== undefined) { params[`${name}_color`] = field.color; } } return this.promiseCGUpdate(serviceId, 'update_text', params, undefined, undefined, options); } updateCGImagePos(serviceId, coordinates = '', x = 0, y = 0, options) { const params = { coord_system: coordinates, pos_x: x, pos_y: y, }; return this.promiseCGUpdate(serviceId, 'update_image', params, undefined, undefined, options); } updateCGImage(serviceId, path, coordinates = '', x = 0, y = 0, options) { const params = { coord_system: coordinates, pos_x: x, pos_y: y, image: path, }; return this.promiseCGUpdate(serviceId, 'update_image', params, undefined, undefined, options); } updateCGImageFromData(serviceId, imageType, imageData, coordinates = '', x = 0, y = 0, options) { const contentType = imageType === ImageType.PNG ? 'image/png' : 'image/jpeg'; const params = { coord_system: coordinates, pos_x: x, pos_y: y, }; return this.promiseCGUpdate(serviceId, 'update_image', params, contentType, imageData, options); } async promiseCGUpdate(serviceId, action, params = {}, contentType, data, options) { const path = `${BASE_PATH}/customGraphics.cgi`; let headers = {}; if (contentType !== undefined && data !== undefined) { headers = { 'Content-Type': contentType }; } const agent = this.getClient(options?.proxyParams); const res = await agent.post({ path, data: data ?? '', parameters: { action: action, service_id: serviceId.toString(), ...params, }, headers, timeout: options?.timeout, }); if (!res.ok) { throw new ErrorWithResponse(res); } } async _getJson(path, parameters, options) { const agent = this.getClient(options?.proxyParams); const res = await agent.get({ path, parameters, timeout: options?.timeout }); if (res.ok) { return await res.json(); } else { throw new ErrorWithResponse(res); } } async _post(path, data, parameters, options, headers) { const agent = this.getClient(options?.proxyParams); const res = await agent.post({ path, data, parameters, headers, timeout: options?.timeout }); if (res.ok) { return await res.json(); } else { throw new ErrorWithResponse(res); } } async _getBlob(path, parameters, options) { const agent = this.getClient(options?.proxyParams); const res = await agent.get({ path, parameters, timeout: options?.timeout }); if (res.ok) { return await this.parseBlobResponse(res); } else { throw new ErrorWithResponse(res); } } async parseBlobResponse(response) { try { return (await response.blob()); } catch (err) { throw new ParsingBlobError(err); } } async _postUrlEncoded(path, parameters, options, headers) { const data = paramToUrl(parameters); const baseHeaders = { 'Content-Type': 'application/x-www-form-urlencoded' }; return this._post(path, data, undefined, options, { ...baseHeaders, ...headers }); } async _postJsonEncoded(path, data, parameters, options, headers) { const baseHeaders = { 'Accept': 'application/json', 'Content-Type': 'application/json' }; return this._post(path, data, parameters, options, { ...baseHeaders, ...headers }); } }