camstreamerlib
Version:
Helper library for CamStreamer ACAP applications.
216 lines (215 loc) • 8.79 kB
JavaScript
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 });
}
}