@nodecg/types
Version:
Dynamic broadcast graphics rendered in a browser
225 lines • 9.94 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerReplicant = void 0;
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const internal_util_1 = require("@nodecg/internal-util");
const json_schema_lib_1 = __importDefault(require("@nodecg/json-schema-lib"));
const hasha_1 = __importDefault(require("hasha"));
const json_1 = require("klona/json");
const replicants_shared_1 = require("../../shared/replicants.shared");
const compileJsonSchema_1 = require("../../shared/utils/compileJsonSchema");
const logger_1 = require("../logger");
const schema_hacks_1 = require("./schema-hacks");
/**
* Never instantiate this directly.
* Always use Replicator.declare instead.
* The Replicator needs to have complete control over the ServerReplicant class.
*/
class ServerReplicant extends replicants_shared_1.AbstractReplicant {
constructor(name, namespace, opts = {}, startingValue = undefined) {
super(name, namespace, opts);
/**
* Server Replicants are immediately considered declared.
* Client Replicants aren't considered declared until they have
* fetched the current value from the server, which is an
* async operation that takes time.
*/
this.status = "declared";
this.log = (0, logger_1.createLogger)(`Replicant/${namespace}.${name}`);
function getBundlePath() {
if (internal_util_1.isLegacyProject) {
return path.join((0, internal_util_1.getNodecgRoot)(), "bundles", namespace);
}
const rootPackageJson = fs.readFileSync(path.join(internal_util_1.rootPath, "package.json"), "utf-8");
if (JSON.parse(rootPackageJson).name === namespace) {
return internal_util_1.rootPath;
}
else {
const bundlesDir = path.join(internal_util_1.rootPath, "bundles");
const bundlesDirStat = fs.existsSync(bundlesDir)
? fs.statSync(bundlesDir)
: null;
if (bundlesDirStat?.isDirectory()) {
const bundles = fs.readdirSync(path.join(internal_util_1.rootPath, "bundles"), {
withFileTypes: true,
});
for (const bundleDir of bundles) {
if (!bundleDir.isDirectory()) {
continue;
}
const bundlePath = path.join(internal_util_1.rootPath, "bundles", bundleDir.name);
const bundlePackageJsonPath = path.join(bundlePath, "package.json");
if (!fs.existsSync(bundlePackageJsonPath)) {
continue;
}
const bundlePackageJson = fs.readFileSync(bundlePackageJsonPath, "utf-8");
if (JSON.parse(bundlePackageJson).name === namespace) {
return bundlePath;
}
}
}
return false;
}
}
let absoluteSchemaPath;
const schemaPath = opts.schemaPath;
if (schemaPath) {
if (path.isAbsolute(schemaPath)) {
absoluteSchemaPath = schemaPath;
}
else {
absoluteSchemaPath = path.join(internal_util_1.isLegacyProject ? (0, internal_util_1.getNodecgRoot)() : internal_util_1.rootPath, schemaPath);
}
}
else {
const bundlePath = getBundlePath();
if (bundlePath) {
absoluteSchemaPath = path.join(bundlePath, "schemas", `${encodeURIComponent(name)}.json`);
}
}
if (absoluteSchemaPath && fs.existsSync(absoluteSchemaPath)) {
try {
const rawSchema = json_schema_lib_1.default.readSync(absoluteSchemaPath);
const parsedSchema = (0, schema_hacks_1.formatSchema)(rawSchema.root, rawSchema.rootFile, rawSchema.files);
if (!parsedSchema) {
throw new Error("parsed schema was unexpectedly undefined");
}
this.schema = parsedSchema;
this.schemaSum = (0, hasha_1.default)(JSON.stringify(parsedSchema), {
algorithm: "sha1",
});
this.validate = this._generateValidator();
}
catch (e) {
if (!process.env.NODECG_TEST) {
this.log.error("Schema could not be loaded, are you sure that it is valid JSON?\n", e.stack);
}
}
}
let defaultValue = "defaultValue" in opts ? opts.defaultValue : undefined;
// Set the default value, if a schema is present and no default value was provided.
if (this.schema && defaultValue === undefined) {
defaultValue = (0, compileJsonSchema_1.getSchemaDefault)(this.schema, `${this.namespace}:${this.name}`);
}
// If `opts.persistent` is true and this replicant has a persisted value, try to load that persisted value.
// Else, apply `defaultValue`.
if (opts.persistent &&
typeof startingValue !== "undefined" &&
startingValue !== null) {
if (this.validate(startingValue, { throwOnInvalid: false })) {
this._value = (0, replicants_shared_1.proxyRecursive)(this, startingValue, "/");
this.log.replicants("Loaded a persisted value:", startingValue);
}
else if (this.schema) {
this._value = (0, replicants_shared_1.proxyRecursive)(this, (0, compileJsonSchema_1.getSchemaDefault)(this.schema, `${this.namespace}:${this.name}`), "/");
this.log.replicants("Discarded persisted value, as it failed schema validation. Replaced with defaults from schema.");
}
}
else {
if (this.schema && defaultValue !== undefined) {
this.validate(defaultValue);
}
if (defaultValue === undefined) {
this.log.replicants('Declared "%s" in namespace "%s"\n', name, namespace);
}
else {
this._value = (0, replicants_shared_1.proxyRecursive)(this, (0, json_1.klona)(defaultValue), "/");
this.log.replicants('Declared "%s" in namespace "%s" with defaultValue:\n', name, namespace, defaultValue);
}
}
}
get value() {
return this._value;
}
set value(newValue) {
if (newValue === this._value) {
this.log.replicants("value unchanged, no action will be taken");
return;
}
this.validate(newValue);
this.log.replicants("running setter with", newValue);
const clonedNewVal = (0, json_1.klona)(newValue);
this._addOperation({
path: "/",
method: "overwrite",
args: {
newValue: clonedNewVal,
},
});
(0, replicants_shared_1.ignoreProxy)(this);
this._value = (0, replicants_shared_1.proxyRecursive)(this, newValue, "/");
(0, replicants_shared_1.resumeProxy)(this);
}
/**
* Refer to the abstract base class' implementation for details.
* @private
*/
_addOperation(operation) {
this._operationQueue.push(operation);
if (!this._pendingOperationFlush) {
this._oldValue = (0, json_1.klona)(this.value);
this._pendingOperationFlush = true;
process.nextTick(() => {
this._flushOperations();
});
}
}
/**
* Refer to the abstract base class' implementation for details.
* @private
*/
_flushOperations() {
this._pendingOperationFlush = false;
if (this._operationQueue.length <= 0)
return;
this.revision++;
this.emit("operations", {
name: this.name,
namespace: this.namespace,
operations: this._operationQueue,
revision: this.revision,
});
const opQ = this._operationQueue;
this._operationQueue = [];
this.emit("change", this.value, this._oldValue, opQ);
}
}
exports.ServerReplicant = ServerReplicant;
//# sourceMappingURL=server-replicant.js.map