camstreamerlib
Version:
Helper library for CamStreamer ACAP applications.
256 lines (255 loc) • 9.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CamOverlayAPI = exports.BASE_URL = void 0;
const utils_1 = require("./internal/utils");
const CamOverlayAPI_1 = require("./types/CamOverlayAPI");
const errors_1 = require("./errors/errors");
const common_1 = require("./types/common");
const zod_1 = require("zod");
const widgetsSchema_1 = require("./models/CamOverlayAPI/widgetsSchema");
const fileSchema_1 = require("./models/CamOverlayAPI/fileSchema");
exports.BASE_URL = '/local/camoverlay/api';
class CamOverlayAPI {
client;
constructor(client) {
this.client = client;
}
static getProxyUrlPath = () => `${exports.BASE_URL}/proxy.cgi`;
static getFilePreviewPath = (path) => `${exports.BASE_URL}/image.cgi?path=${encodeURIComponent(path)}`;
async checkCameraTime() {
const responseSchema = zod_1.z.discriminatedUnion('state', [
zod_1.z.object({
state: zod_1.z.literal(true),
code: zod_1.z.number(),
}),
zod_1.z.object({
state: zod_1.z.literal(false),
code: zod_1.z.number(),
reason: zod_1.z.union([
zod_1.z.literal('INVALID_TIME'),
zod_1.z.literal('COULDNT_RESOLVE_HOST'),
zod_1.z.literal('CONNECTION_ERROR'),
]),
message: zod_1.z.string(),
}),
]);
const response = await this._get(`${exports.BASE_URL}/camera_time.cgi`);
const cameraTime = responseSchema.parse(response);
if (!cameraTime.state) {
console.error(`Camera time check failed: ${cameraTime.reason} - ${cameraTime.message}`);
}
return cameraTime.state;
}
async getNetworkCameraList() {
const response = await this._get(`${exports.BASE_URL}/network_camera_list.cgi`);
return common_1.networkCameraListSchema.parse(response.camera_list);
}
async wsAuthorization() {
const responseSchema = zod_1.z.object({
status: zod_1.z.number(),
message: zod_1.z.string(),
data: zod_1.z.string(),
});
const response = await this._get(`${exports.BASE_URL}/ws_authorization.cgi`);
return responseSchema.parse(response).data;
}
async getMjpegStreamImage(mjpegUrl) {
return await this._getBlob(`${exports.BASE_URL}/fetch_mjpeg_image.cgi?mjpeg_url=${encodeURIComponent(decodeURIComponent(mjpegUrl))}`);
}
async listFiles(fileType) {
const fileDataSchema = zod_1.z.object({
code: zod_1.z.number(),
list: fileSchema_1.fileListSchema,
});
const files = await this._get(`${exports.BASE_URL}/upload_${fileType}.cgi`, {
action: 'list',
});
return fileSchema_1.fileListSchema.parse(files.list);
}
async uploadFile(fileType, formData, storage) {
const path = `${exports.BASE_URL}/upload_${fileType}.cgi`;
await this._post(path, formData, {
action: 'upload',
storage: storage,
});
}
async removeFile(fileType, fileParams) {
const path = `${exports.BASE_URL}/upload_${fileType}.cgi`;
await this._postUrlEncoded(path, {
action: 'remove',
...fileParams,
});
}
async getFileStorage(fileType) {
const storageDataListSchema = zod_1.z.array(zod_1.z.object({
type: fileSchema_1.storageSchema,
state: zod_1.z.string(),
}));
const responseSchema = zod_1.z.object({
code: zod_1.z.number(),
list: storageDataListSchema,
});
const data = await this._get(`${exports.BASE_URL}/upload_${fileType}.cgi`, {
action: 'get_storage',
});
if (data.code !== 200) {
throw new Error('Error occured while fetching file storage data');
}
return storageDataListSchema.parse(data.list);
}
async getFilePreviewFromCamera(path) {
return await this._getBlob(CamOverlayAPI.getFilePreviewPath(path));
}
async updateInfoticker(serviceID, text) {
await this._get(`${exports.BASE_URL}/infoticker.cgi?service_id=${serviceID}&text=${text}`);
}
async setEnabled(serviceID, enabled) {
await this._post(`${exports.BASE_URL}/enabled.cgi?id_${serviceID}=${enabled ? 1 : 0}`, '');
}
async isEnabled(serviceID) {
const res = await this.client.get(`${exports.BASE_URL}/services.cgi?action=get`);
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 errors_1.ServiceNotFoundError();
}
else {
throw new Error(await (0, utils_1.responseStringify)(res));
}
}
async getSingleWidget(serviceId) {
const data = await this._get(`${exports.BASE_URL}/services.cgi`, {
action: 'get',
service_id: serviceId.toString(),
});
return widgetsSchema_1.widgetsSchema.parse(data);
}
async getWidgets() {
const widgetList = await this._get(`${exports.BASE_URL}/services.cgi`, {
action: 'get',
});
const widgets = widgetList.services;
widgets.forEach((widget) => {
const parsedWidget = widgetsSchema_1.widgetsSchema.safeParse(widget);
if (!parsedWidget.success) {
console.warn(`[SERVICE SCHEMA MISMATCH]: Service ${widget.name} (${widget.id}) does not match the current schema, or is a hidden service.`);
}
});
return widgets;
}
async updateSingleWidget(widget) {
const path = `${exports.BASE_URL}/services.cgi`;
await this._postJsonEncoded(path, JSON.stringify(widget), {
action: 'set',
service_id: widget.id.toString(),
});
}
async updateWidgets(widgets) {
const path = `${exports.BASE_URL}/services.cgi`;
await this._postJsonEncoded(path, JSON.stringify({ services: widgets }), {
action: 'set',
});
}
updateCGText(serviceID, fields) {
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);
}
updateCGImagePos(serviceID, coordinates = '', x = 0, y = 0) {
const params = {
coord_system: coordinates,
pos_x: x,
pos_y: y,
};
return this.promiseCGUpdate(serviceID, 'update_image', params);
}
updateCGImage(serviceID, path, coordinates = '', x = 0, y = 0) {
const params = {
coord_system: coordinates,
pos_x: x,
pos_y: y,
image: path,
};
return this.promiseCGUpdate(serviceID, 'update_image', params);
}
updateCGImageFromData(serviceID, imageType, imageData, coordinates = '', x = 0, y = 0) {
const contentType = imageType === CamOverlayAPI_1.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);
}
async promiseCGUpdate(serviceID, action, params = {}, contentType, data) {
const path = `${exports.BASE_URL}/customGraphics.cgi`;
let headers = {};
if (contentType !== undefined && data) {
headers = { 'Content-Type': contentType };
}
const res = await this.client.post(path, data ?? '', {
action: action,
service_id: serviceID.toString(),
...params,
}, headers);
if (!res.ok) {
throw new Error(await (0, utils_1.responseStringify)(res));
}
}
async _get(...args) {
const res = await this.client.get(...args);
if (res.ok) {
return (await res.json());
}
else {
throw new Error(await (0, utils_1.responseStringify)(res));
}
}
async _post(...args) {
const res = await this.client.post(...args);
if (res.ok) {
return (await res.json());
}
else {
throw new Error(await (0, utils_1.responseStringify)(res));
}
}
async _getBlob(...args) {
const res = await this.client.get(...args);
if (res.ok) {
return await this.parseBlobResponse(res);
}
else {
throw new Error(await (0, utils_1.responseStringify)(res));
}
}
async parseBlobResponse(response) {
try {
return (await response.blob());
}
catch (err) {
throw new errors_1.ParsingBlobError(err);
}
}
async _postUrlEncoded(path, params, headers) {
const data = (0, utils_1.paramToUrl)(params);
const baseHeaders = { 'Content-Type': 'application/x-www-form-urlencoded' };
return this._post(path, data, {}, { ...baseHeaders, ...headers });
}
async _postJsonEncoded(...args) {
const [path, data, params, headers] = args;
const baseHeaders = { 'Accept': 'application/json', 'Content-Type': 'application/json' };
return this._post(path, data, params, { ...baseHeaders, ...headers });
}
}
exports.CamOverlayAPI = CamOverlayAPI;