Update dependencies

This commit is contained in:
Zaid Abdulla committed 2022-08-22 09:44:25 -07:00
1 parent 2789961596
commit 25ea0c8b64
14 files changed
+3449 -3947

No files matched your search

+9 -12
View File
@@ -20,11 +20,12 @@
import { Collection } from "mongodb";
import { onConnect } from "./db";
import * as config from "./config";
import { Cache } from "./mongodb-types";
const CLOCK_SKEW_TOLERANCE = 30000;
const MAX_CACHE_TTL = +config.get("MAX_CACHE_TTL");
let cacheCollection: Collection;
let cacheCollection: Collection<Cache>;
onConnect(async (db) => {
cacheCollection = db.collection("cache");
@@ -33,8 +34,7 @@ onConnect(async (db) => {
export async function get(key: string): Promise<string> {
const res = await cacheCollection.findOne({ _id: key });
if (res) return res["value"];
return null;
return res?.value;
}
export async function del(key: string): Promise<void> {
@@ -52,15 +52,14 @@ export async function set(
);
await cacheCollection.replaceOne(
{ _id: key },
{ _id: key, value, expire, timestamp },
{ value, expire, timestamp },
{ upsert: true }
);
}
export async function pop(key: string): Promise<any> {
export async function pop(key: string): Promise<string> {
const res = await cacheCollection.findOneAndDelete({ _id: key });
if (res?.["value"]) return res["value"]["value"];
return null;
return res.value?.value;
}
export async function acquireLock(
@@ -72,18 +71,16 @@ export async function acquireLock(
try {
const now = Date.now();
const r = await cacheCollection.findOneAndUpdate(
{ _id: lockName, token },
{ _id: lockName, value: token },
{
$set: {
value: token,
expire: new Date(now + ttl + CLOCK_SKEW_TOLERANCE),
},
$currentDate: { timestamp: true as unknown as Date },
$currentDate: { timestamp: true },
},
{ upsert: true, returnDocument: "after" }
);
const v = r.value;
if (Math.abs(v["timestamp"].getTime() - now) > CLOCK_SKEW_TOLERANCE)
if (Math.abs(r.value.timestamp.getTime() - now) > CLOCK_SKEW_TOLERANCE)
throw new Error("Database clock skew too great");
} catch (err) {
if (err.code !== 11000) throw err;
+1 -1
View File
@@ -536,7 +536,7 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
session.configContextCallback(sessionContext, e)
)
),
]);
]) as [string, ...Expression[]][];
if (blackList[p.channel] === 2) {
appendProvisionsToFaults[p.channel] = (
appendProvisionsToFaults[p.channel] || []
+85 -39
View File
@@ -30,19 +30,20 @@ import {
Expression,
} from "./types";
import Path from "./common/path";
import * as MongoTypes from "./mongodb-types";
export let tasksCollection: Collection,
export let tasksCollection: Collection<MongoTypes.Task>,
devicesCollection: Collection,
presetsCollection: Collection,
objectsCollection: Collection,
provisionsCollection: Collection,
virtualParametersCollection: Collection,
faultsCollection: Collection,
faultsCollection: Collection<MongoTypes.Fault>,
filesCollection: Collection,
operationsCollection: Collection,
operationsCollection: Collection<MongoTypes.Operation>,
permissionsCollection: Collection,
usersCollection: Collection,
configCollection: Collection;
configCollection: Collection<MongoTypes.Config>;
let clientPromise: Promise<MongoClient>;
@@ -643,12 +644,16 @@ export async function getFaults(
const faults: { [channel: string]: SessionFault } = {};
for (const r of res) {
const channel = r._id.slice(deviceId.length + 1);
delete r._id;
delete r.channel;
delete r.device;
r.timestamp = +r.timestamp;
r.provisions = JSON.parse(r.provisions);
faults[channel] = r as SessionFault;
const fault: SessionFault = {
code: r.code,
message: r.message,
...(r.detail && { detail: r.detail }),
timestamp: +r.timestamp,
provisions: JSON.parse(r.provisions),
retries: r.retries,
...(r.expiry && { expiry: +r.expiry }),
};
faults[channel] = fault;
}
return faults;
@@ -660,12 +665,18 @@ export async function saveFault(
fault: SessionFault
): Promise<void> {
const id = `${deviceId}:${channel}`;
const f = Object.assign({}, fault) as Record<string, any>;
f["_id"] = id;
f["device"] = deviceId;
f["channel"] = channel;
f["timestamp"] = new Date(fault.timestamp);
f["provisions"] = JSON.stringify(fault.provisions);
const f: MongoTypes.Fault = {
_id: id,
device: deviceId,
channel: channel,
timestamp: new Date(fault.timestamp),
code: fault.code,
message: fault.message,
...(fault.detail && { detail: fault.detail }),
retries: fault.retries,
...(fault.expiry && { expiry: new Date(fault.expiry) }),
provisions: JSON.stringify(fault.provisions),
};
await faultsCollection.replaceOne({ _id: id }, f, { upsert: true });
}
@@ -683,20 +694,47 @@ export async function getDueTasks(
const cur = tasksCollection.find({ device: deviceId }).sort({ timestamp: 1 });
const tasks = [] as Task[];
for await (const task of cur) {
if (task.timestamp) task.timestamp = +task.timestamp;
if (task.expiry) task.expiry = +task.expiry;
if (task.timestamp >= timestamp) return [tasks, +task.timestamp];
task._id = String(task._id);
for await (const t of cur) {
if (+t.timestamp >= timestamp) return [tasks, +t.timestamp];
const task: Task = {
_id: t._id.toString(),
name: t.name,
...(t.timestamp && { timestamp: +t.timestamp }),
...(t.expiry && { expiry: +t.expiry }),
...(t.name === "getParameterValues" && {
parameterNames: t.parameterNames,
}),
...(t.name === "setParameterValues" && {
parameterValues: t.parameterValues,
}),
...(t.name === "refreshObject" && {
objectName: t.objectName,
}),
...(t.name === "download" && {
fileType: t.fileType,
fileName: t.fileName,
targetFileName: t.targetFileName,
}),
...(t.name === "addObject" && {
objectName: t.objectName,
parameterValues: t.parameterValues,
}),
...(t.name === "deleteObject" && {
objectName: t.objectName,
}),
...(t.name === "provisions" && {
provisions: t.provisions,
}),
};
tasks.push(task as Task);
tasks.push(task);
// For API compatibility
if (task.name === "download" && task.file) {
if (task.name === "download" && t["file"]) {
let q;
if (ObjectId.isValid(task.file))
q = { _id: { $in: [task.file, new ObjectId(task.file)] } };
else q = { _id: task.file };
if (ObjectId.isValid(t["file"]))
q = { _id: { $in: [t["file"], new ObjectId(t["file"])] } };
else q = { _id: t["file"] };
const res = await filesCollection.find(q).toArray();
@@ -730,17 +768,22 @@ export async function getOperations(
const operations: { [commandKey: string]: Operation } = {};
for (const r of res) {
const commandKey = r._id.slice(deviceId.length + 1);
delete r._id;
// Workaround for a bug in v1.2.1 where operation object is saved without deserialization
if (typeof r.provisions !== "string") {
operations[commandKey] = r as Operation;
delete r._id;
operations[commandKey] = r as unknown as Operation;
continue;
}
r.timestamp = +r.timestamp;
if (r.args) r.args = JSON.parse(r.args);
r.provisions = JSON.parse(r.provisions);
r.retries = JSON.parse(r.retries);
operations[commandKey] = r as Operation;
const operation: Operation = {
name: r.name,
timestamp: +r.timestamp,
channels:
typeof r.channels === "string" ? JSON.parse(r.channels) : r.channels,
retries: JSON.parse(r.retries),
provisions: JSON.parse(r.provisions),
...(r.args && { args: JSON.parse(r.args) }),
};
operations[commandKey] = operation;
}
return operations;
}
@@ -751,12 +794,15 @@ export async function saveOperation(
operation: Operation
): Promise<void> {
const id = `${deviceId}:${commandKey}`;
const o = Object.assign({}, operation) as Record<string, any>;
o["_id"] = id;
o["timestamp"] = new Date(operation.timestamp);
o["provisions"] = JSON.stringify(operation.provisions);
o["retries"] = JSON.stringify(operation.retries);
o["args"] = JSON.stringify(operation.args);
const o: MongoTypes.Operation = {
_id: id,
name: operation.name,
timestamp: new Date(operation.timestamp),
channels: JSON.stringify(operation.channels),
provisions: JSON.stringify(operation.provisions),
retries: JSON.stringify(operation.retries),
args: JSON.stringify(operation.args),
};
await operationsCollection.replaceOne({ _id: id }, o, {
upsert: true,
});
+107
View File
@@ -0,0 +1,107 @@
import { ObjectId } from "mongodb";
import { Expression, FaultStruct } from "./types";
export interface Fault {
_id: string;
device: string;
channel: string;
timestamp: Date;
provisions: string;
retries: number;
code: string;
message: string;
detail?:
| FaultStruct
| {
name: string;
message: string;
stack?: string;
};
expiry?: Date;
}
interface TaskBase {
_id: ObjectId;
timestamp?: Date;
expiry?: Date;
name: string;
}
interface TaskGetParameterValues extends TaskBase {
name: "getParameterValues";
parameterNames: string[];
}
interface TaskSetParameterValues extends TaskBase {
name: "setParameterValues";
parameterValues: [string, string | number | boolean, string?][];
}
interface TaskRefreshObject extends TaskBase {
name: "refreshObject";
objectName: string;
}
interface TaskReboot extends TaskBase {
name: "reboot";
}
interface TaskFactoryReset extends TaskBase {
name: "factoryReset";
}
interface TaskDownload extends TaskBase {
name: "download";
fileType: string;
fileName: string;
targetFileName?: string;
}
interface TaskAddObject extends TaskBase {
name: "addObject";
objectName: string;
parameterValues: [string, string | number | boolean, string?][];
}
interface TaskDeleteObject extends TaskBase {
name: "deleteObject";
objectName: string;
}
interface TaskProvisions extends TaskBase {
name: "provisions";
provisions?: [string, ...Expression[]][];
}
export type Task =
| TaskGetParameterValues
| TaskSetParameterValues
| TaskRefreshObject
| TaskReboot
| TaskFactoryReset
| TaskDownload
| TaskAddObject
| TaskDeleteObject
| TaskProvisions;
export interface Operation {
_id: string;
name: string;
timestamp: Date;
channels: string;
retries: string;
provisions: string;
args: string;
}
export interface Config {
_id: string;
value: string;
}
export interface Cache {
_id: string;
value: string;
timestamp: Date;
expire: Date;
}
+1 -1
View File
@@ -845,7 +845,7 @@ export function listener(
cur.sort(sort);
}
cur.count((err, total) => {
collection.countDocuments(q, (err, total) => {
if (err) return void throwError(err);
response.writeHead(200, {
+1 -1
View File
@@ -504,7 +504,7 @@ export async function timeoutOperations(
export function addProvisions(
sessionContext: SessionContext,
channel: string,
provisions: (string | number | boolean)[][]
provisions: [string, ...Expression[]][]
): void {
// Multiply by two because every iteration is two
// phases: read and update
+1 -1
View File
@@ -180,7 +180,7 @@ export interface Task {
fileName?: string;
targetFileName?: string;
expiry?: number;
provisions?: (string | number | boolean)[][];
provisions?: [string, ...Expression[]][];
}
export interface Operation {
+15 -19
View File
@@ -115,30 +115,31 @@ export function query(
cursor.toArray((err, docs) => {
if (err) return reject(err);
if (resource === "devices")
docs = docs.map((d) => mongodbFunctions.flattenDevice(d));
return resolve(docs.map((d) => mongodbFunctions.flattenDevice(d)));
else if (resource === "faults")
docs = docs.map((d) => mongodbFunctions.flattenFault(d));
return resolve(docs.map((d) => mongodbFunctions.flattenFault(d)));
else if (resource === "tasks")
docs = docs.map((d) => mongodbFunctions.flattenTask(d));
return resolve(docs.map((d) => mongodbFunctions.flattenTask(d)));
else if (resource === "presets")
docs = docs.map((d) => mongodbFunctions.flattenPreset(d));
return resolve(docs.map((d) => mongodbFunctions.flattenPreset(d)));
else if (resource === "files")
docs = docs.map((d) => mongodbFunctions.flattenFile(d));
return resolve(docs.map((d) => mongodbFunctions.flattenFile(d)));
return resolve(docs);
});
} else {
cursor.forEach(
(doc) => {
if (resource === "devices") doc = mongodbFunctions.flattenDevice(doc);
if (resource === "devices")
callback(mongodbFunctions.flattenDevice(doc));
else if (resource === "faults")
doc = mongodbFunctions.flattenFault(doc);
callback(mongodbFunctions.flattenFault(doc));
else if (resource === "tasks")
doc = mongodbFunctions.flattenTask(doc);
callback(mongodbFunctions.flattenTask(doc));
else if (resource === "presets")
doc = mongodbFunctions.flattenPreset(doc);
callback(mongodbFunctions.flattenPreset(doc));
else if (resource === "files")
doc = mongodbFunctions.flattenFile(doc);
callback(doc);
callback(mongodbFunctions.flattenFile(doc));
else callback(doc);
},
(err) => {
if (err) reject(err);
@@ -150,7 +151,8 @@ export function query(
}
export function count(resource: string, filter: Expression): Promise<number> {
let q;
const collection = db.collection(RESOURCE_COLLECTION[resource] || resource);
let q: Parameters<typeof collection.countDocuments>[0];
filter = expression.evaluate(filter, null, Date.now());
filter = minimize(filter, true);
@@ -166,13 +168,7 @@ export function count(resource: string, filter: Expression): Promise<number> {
return Promise.resolve(0);
}
return new Promise((resolve, reject) => {
const collection = db.collection(RESOURCE_COLLECTION[resource] || resource);
collection.find(q).count((err, c) => {
if (err) reject(err);
else resolve(c);
});
});
return collection.countDocuments(q);
}
export async function updateDeviceTags(