core: publish beta

This commit is contained in:
Koushik Dutta
2022-12-02 07:39:51 -08:00
parent 5f0c9dc94e
commit ea3c159ffa
6 changed files with 114 additions and 50 deletions

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/core",
"version": "0.1.61",
"version": "0.1.62",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/core",
"version": "0.1.61",
"version": "0.1.62",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/core",
"version": "0.1.61",
"version": "0.1.62",
"description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.",
"author": "Scrypted",
"license": "Apache-2.0",

View File

@@ -1,4 +1,4 @@
import { BufferConverter, HttpRequest, HttpRequestHandler, HttpResponse, HttpResponseOptions, ScryptedDeviceBase, ScryptedMimeTypes } from "@scrypted/sdk";
import { BufferConverter, BufferConvertorOptions, HttpRequest, HttpRequestHandler, HttpResponse, HttpResponseOptions, MediaObject, RequestMediaObject, ScryptedDeviceBase, ScryptedMimeTypes } from "@scrypted/sdk";
import sdk from "@scrypted/sdk";
import mime from "mime/lite";
import path from 'path';
@@ -65,6 +65,87 @@ export class BufferHost extends ScryptedDeviceBase implements HttpRequestHandler
}
}
export class RequestMediaObjectHost extends ScryptedDeviceBase implements HttpRequestHandler, BufferConverter {
secureHosted = new Map<string, { request: RequestMediaObject, fromMimeType: string, toMimeType: string }>()
insecureHosted = new Map<string, { request: RequestMediaObject, fromMimeType: string, toMimeType: string }>()
constructor() {
super('rmo-host');
this.fromMimeType = ScryptedMimeTypes.RequestMediaObject;
this.toMimeType = ScryptedMimeTypes.MediaObject;
// this.toMimeType = secure ? ScryptedMimeTypes.LocalUrl : ScryptedMimeTypes.InsecureLocalUrl;
}
async onRequest(request: HttpRequest, response: HttpResponse) {
const normalizedRequest = Object.assign({}, request);
normalizedRequest.url = normalizedRequest.url.replace(normalizedRequest.rootPath, '');
const pathOnly = normalizedRequest.url.split('?')[0];
const file = this.secureHosted.get(pathOnly) || this.insecureHosted.get(pathOnly);;
if (!file) {
response.send('Not Found', {
code: 404,
});
return;
}
let options: HttpResponseOptions = {
headers: {
'Content-Type': file.fromMimeType,
}
};
const q = new URLSearchParams(request.url.split('?')[1]);
if (q.has('attachment')) {
options.headers['Content-Disposition'] = 'attachment';
}
try {
const mo = await file.request();
const data = await sdk.mediaManager.convertMediaObjectToBuffer(mo, mo.mimeType);
response.send(data);
}
catch (e) {
this.secureHosted.delete(pathOnly);
this.insecureHosted.delete(pathOnly);
throw e;
}
}
async convert(request: RequestMediaObject, fromMimeType: string, toMimeType: string): Promise<MediaObject> {
let hosted: typeof this.secureHosted;
if (toMimeType === ScryptedMimeTypes.Url || toMimeType === ScryptedMimeTypes.LocalUrl) {
hosted = this.secureHosted;
toMimeType = ScryptedMimeTypes.LocalUrl;
}
else if (toMimeType === ScryptedMimeTypes.InsecureLocalUrl) {
hosted = this.insecureHosted;
}
else {
return request();
}
const uuid = uuidv4();
const endpoint = await (toMimeType === ScryptedMimeTypes.LocalUrl ? endpointManager.getPublicLocalEndpoint(this.nativeId) : endpointManager.getInsecurePublicLocalEndpoint(this.nativeId));
const data = await request();
fromMimeType = data.mimeType;
const extension = mime.getExtension(fromMimeType);
const filename = uuid + (extension ? `.${extension}` : '');
const pathOnly = `/${filename}`;
hosted.set(pathOnly, { request, fromMimeType, toMimeType });
// free this resource after an hour.
setTimeout(() => hosted.delete(pathOnly), 1 * 60 * 60 * 1000);
const url = Buffer.from(`${endpoint}${filename}`);
return sdk.mediaManager.createMediaObject(url, toMimeType);
}
}
export class FileHost extends ScryptedDeviceBase implements HttpRequestHandler, BufferConverter {
hosted = new Map<string, { data: Buffer | string }>()

View File

@@ -1,12 +1,13 @@
import path from 'path';
import { ScryptedDeviceBase, DeviceProvider, ScryptedInterface, ScryptedDeviceType, BufferConverter, MediaObject, VideoCamera, Camera, ScryptedMimeTypes, RequestMediaStreamOptions, HttpRequestHandler, HttpRequest, HttpResponse } from '@scrypted/sdk';
import { ScryptedDeviceBase, DeviceProvider, ScryptedInterface, ScryptedDeviceType, BufferConverter, MediaObject, VideoCamera, Camera, ScryptedMimeTypes, RequestMediaStreamOptions, HttpRequestHandler, HttpRequest, HttpResponse, RequestMediaObject } from '@scrypted/sdk';
import sdk from '@scrypted/sdk';
const { systemManager, deviceManager, mediaManager, endpointManager } = sdk;
import { BufferHost, FileHost } from './converters';
import { RequestMediaObjectHost, FileHost, BufferHost } from './converters';
export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, BufferConverter, HttpRequestHandler {
httpHost: BufferHost;
httpsHost: BufferHost;
rmoHost: RequestMediaObjectHost;
fileHost: FileHost;
filesHost: FileHost;
@@ -33,6 +34,12 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
type: ScryptedDeviceType.API,
},
{
name: 'RequestMediaObject Host',
nativeId: 'rmo-host',
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
type: ScryptedDeviceType.API,
},
{
name: 'HTTP File Host',
nativeId: 'file',
@@ -50,6 +57,7 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
})
this.httpHost = new BufferHost(false);
this.httpsHost = new BufferHost(true);
this.rmoHost = new RequestMediaObjectHost();
this.fileHost = new FileHost(false);
this.filesHost = new FileHost(true);
})();
@@ -105,10 +113,12 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
if (path === ScryptedInterface.Camera) {
if (toMimeType === ScryptedMimeTypes.LocalUrl)
return this.getLocalSnapshot(id, path, url.search);
return await systemManager.getDeviceById<Camera>(id).takePicture() as any;
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<Camera>(id).takePicture();
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
}
if (path === ScryptedInterface.VideoCamera) {
return await systemManager.getDeviceById<VideoCamera>(id).getVideoStream() as any;
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<VideoCamera>(id).getVideoStream();
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
}
else {
throw new Error('Unrecognized Scrypted Media interface.')
@@ -120,6 +130,8 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
return this.httpHost;
if (nativeId === 'https')
return this.httpsHost;
if (nativeId === 'rmo-host')
return this.rmoHost;
if (nativeId === 'file')
return this.fileHost;
if (nativeId === 'files')

View File

@@ -1,5 +1,5 @@
<template>
<v-autocomplete :small-chips="multiple" v-model="lazyValue" :items="devices" item-value="id" outlined :multiple="multiple"
<v-autocomplete dense :small-chips="multiple" v-model="lazyValue" :items="devices" item-value="id" outlined :multiple="multiple"
:label="title" :hint="description" persistent-hint @change="onInput">
<template v-slot:append-outer>
<slot name="append-outer"></slot>

View File

@@ -3,37 +3,12 @@
<v-container>
<v-layout>
<v-flex xs12>
<v-text-field
dense
label="Notification Title"
outlined
v-model="lazyValue.notificationTitle"
@input="onChange"
></v-text-field>
<v-text-field
dense
label="Notification Body"
outlined
v-model="lazyValue.notificationBody"
@input="onChange"
></v-text-field>
<v-combobox
dense
@select="onSelect"
:items="mediaInterfaces"
label="Notification Media URL"
outlined
v-model="lazyValue.notificationMediaUrl"
@input="onChange"
:return-object="false"
></v-combobox>
<v-text-field
dense
label="Notification Media Mime Type"
outlined
v-model="lazyValue.notificationMediaMime"
@input="onChange"
></v-text-field>
<v-text-field dense label="Notification Title" outlined v-model="lazyValue.notificationTitle"
@input="onChange"></v-text-field>
<v-text-field dense label="Notification Body" outlined v-model="lazyValue.notificationBody"
@input="onChange"></v-text-field>
<v-combobox dense :items="mediaInterfaces" label="Notification Media URL" outlined
v-model="lazyValue.notificationMediaUrl" @input="onChange" :return-object="false"></v-combobox>
</v-flex>
</v-layout>
</v-container>
@@ -64,14 +39,17 @@ export default {
if (this.lazyValue.notificationMediaUrl.length) {
this.rpc().sendNotification(
this.lazyValue.notificationTitle,
this.lazyValue.notificationBody,
{
body: this.lazyValue.notificationBody,
},
this.lazyValue.notificationMediaUrl,
this.lazyValue.notificationMediaMime
);
} else {
this.rpc().sendNotification(
this.lazyValue.notificationTitle,
this.lazyValue.notificationBody
{
body: this.lazyValue.notificationBody,
},
);
}
},
@@ -89,10 +67,6 @@ export default {
ret.notificationMediaUrl,
"https://home.scrypted.app/_punch/web_hi_res_512.png"
);
ret.notificationMediaMime = this.ensureString(
ret.notificationMediaMime,
"image/png"
);
return ret;
},
onChange: function () {
@@ -104,9 +78,6 @@ export default {
send() {
this.update();
},
onSelect() {
this.lazyValue.notificationMediaMime = "";
},
},
computed: {
mediaInterfaces() {