snapshot: relax some cpu and memory usage

This commit is contained in:
Koushik Dutta
2022-03-21 09:58:20 -07:00
parent 2dc15e13be
commit afa0cf44ac
3 changed files with 57 additions and 29 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/snapshot",
"version": "0.0.16",
"version": "0.0.17",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/snapshot",
"version": "0.0.16",
"version": "0.0.17",
"dependencies": {
"@koush/axios-digest-auth": "^0.8.5",
"@types/node": "^16.6.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/snapshot",
"version": "0.0.16",
"version": "0.0.17",
"description": "Snapshot Plugin for Scrypted",
"scripts": {
"prepublishOnly": "NODE_ENV=production scrypted-webpack",

View File

@@ -4,13 +4,15 @@ import { StorageSettings } from "@scrypted/common/src/settings"
import AxiosDigestAuth from '@koush/axios-digest-auth';
import https from 'https';
import axios, { Axios } from "axios";
import { TimeoutError, timeoutPromise } from "@scrypted/common/src/promise-utils";
import { RefreshPromise, singletonPromise, TimeoutError, timeoutPromise } from "@scrypted/common/src/promise-utils";
import { AutoenableMixinProvider } from "@scrypted/common/src/autoenable-mixin-provider";
import jimp from 'jimp';
const { systemManager } = sdk;
const { mediaManager, systemManager } = sdk;
// lol
const FOREVER = 24 * 60 * 60 * 1000;
const { mediaManager } = sdk;
const httpsAgent = new https.Agent({
rejectUnauthorized: false
});
@@ -27,8 +29,11 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
title: 'Default Snapshot Channel',
description: 'The default channel to use for snapshots.',
defaultValue: 'Camera Default',
hide: true,
hide: !this.mixinDeviceInterfaces.includes(ScryptedInterface.Camera),
onGet: async () => {
if (!this.mixinDeviceInterfaces.includes(ScryptedInterface.Camera))
return {};
let psos: PictureOptions[];
try {
psos = await this.mixinDevice.getPictureOptions();
@@ -92,10 +97,11 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
});
axiosClient: Axios | AxiosDigestAuth;
pendingPicture: Promise<Buffer>;
// this will contain the last picture retrieved,
// or an outdated picture blurred with an error overlay.
lastPicture: Buffer;
rawLastPicture: Buffer;
errorPicture: RefreshPromise<Buffer>;
timeoutPicture: RefreshPromise<Buffer>;
progressPicture: RefreshPromise<Buffer>;
currentPicture: Buffer;
lastAvailablePicture: Buffer;
constructor(options: SettingsMixinDeviceOptions<Camera>) {
super(options);
@@ -190,17 +196,18 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
try {
picture = await takePicture();
picture = await this.cropAndScale(picture);
this.rawLastPicture = picture;
this.clearCachedPictures();
this.currentPicture = picture;
this.lastAvailablePicture = picture;
setTimeout(() => {
if (this.currentPicture === picture) {
this.clearCachedPictures();
}
}, 30000);
}
catch (e) {
picture = await this.createErrorImage(e);
}
this.lastPicture = picture;
setTimeout(() => {
if (this.lastPicture === picture) {
this.lastPicture = undefined;
}
}, 30000);
return picture;
})();
@@ -222,13 +229,13 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
else {
try {
if (this.storageSettings.values.snapshotMode === 'Never Wait') {
if (!this.lastPicture) {
if (!this.currentPicture) {
// this triggers an event to refresh the web ui.
this.pendingPicture.then(() => this.onDeviceEvent(ScryptedInterface.Camera, undefined));
data = await this.createErrorImage(new NeverWaitError());
}
else {
data = this.lastPicture;
data = this.currentPicture;
}
}
else {
@@ -266,16 +273,37 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
return cropped;
}
clearCachedPictures() {
this.currentPicture = undefined;
this.errorPicture = undefined;
this.pendingPicture = undefined;
this.timeoutPicture = undefined;
}
async createErrorImage(e: any) {
this.console.log('creating error snapshot', e);
let text: string;
if (e instanceof TimeoutError)
text = 'Snapshot Timed Out';
else if (e instanceof NeverWaitError)
text = 'Snapshot in Progress';
else
text = 'Snapshot Failed';
if (!this.rawLastPicture) {
if (e instanceof TimeoutError) {
this.timeoutPicture = singletonPromise(this.timeoutPicture,
() => this.createTextErrorImage('Snapshot Timed Out'),
FOREVER);
return this.timeoutPicture.promise;
}
else if (e instanceof NeverWaitError) {
this.progressPicture = singletonPromise(this.timeoutPicture,
() => this.createTextErrorImage('Snapshot In Progress'),
FOREVER);
return this.progressPicture.promise;
}
else {
this.errorPicture = singletonPromise(this.timeoutPicture,
() => this.createTextErrorImage('Snapshot Failed'),
FOREVER);
return this.errorPicture.promise;
}
}
async createTextErrorImage(text: string) {
if (!this.currentPicture) {
const img = await jimp.create(1920 / 2, 1080 / 2);
const font = await fontPromise;
img.print(font, 0, 0, {
@@ -286,7 +314,7 @@ class SnapshotMixin extends SettingsMixinDeviceBase<Camera> implements Camera {
return img.getBufferAsync('image/jpeg');
}
else {
const img = await jimp.read(this.rawLastPicture);
const img = await jimp.read(this.currentPicture);
img.resize(1920 / 2, jimp.AUTO);
img.blur(15);
img.brightness(-.2);