2
0
mirror of https://github.com/esiur/esiur-js.git synced 2025-05-06 12:32:58 +00:00

Added Records

This commit is contained in:
Ahmed Zamil 2021-06-18 17:58:37 +03:00
parent 2bf5605ef1
commit 6d2e4156cf
15 changed files with 1884 additions and 2262 deletions

View File

@ -3,8 +3,8 @@
[ [
"@babel/preset-env" "@babel/preset-env"
] ]
],
"plugins": [
["@babel/plugin-proposal-class-properties", { "loose": true }]
] ]
//"plugins": [
//["@babel/plugin-proposal-class-properties", { "loose": true }]
//]
} }

File diff suppressed because it is too large Load Diff

2637
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,16 +19,14 @@
"url": "https://github.com/esiur/esiur-js/issues" "url": "https://github.com/esiur/esiur-js/issues"
}, },
"homepage": "https://github.com/esiur/esiur-js#readme", "homepage": "https://github.com/esiur/esiur-js#readme",
"dependencies": {
"mongodb": "^3.6.9",
"ws": "^7.5.0"
},
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.13.16", "@babel/core": "^7.14.6",
"@babel/core": "^7.13.16", "@babel/preset-env": "^7.14.5",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/preset-env": "^7.13.15",
"babelify": "^10.0.0", "babelify": "^10.0.0",
"browserify": "^17.0.0" "browserify": "^17.0.0"
},
"dependencies": {
"mongodb": "^3.6.6",
"ws": "^7.4.5"
} }
} }

View File

@ -27,7 +27,7 @@
"use strict"; "use strict";
import DataType from './DataType.js'; import DataType from './DataType.js';
import ResourceComparisonResult from './ResourceComparisionResult.js'; import ResourceComparisonResult from './ResourceComparisonResult.js';
import StructureComparisonResult from './StructureComparisonResult.js'; import StructureComparisonResult from './StructureComparisonResult.js';
import AsyncBag from '../Core/AsyncBag.js'; import AsyncBag from '../Core/AsyncBag.js';
@ -39,6 +39,9 @@ import BinaryList from './BinaryList.js';
import DistributedPropertyContext from '../Net/IIP/DistributedPropertyContext.js'; import DistributedPropertyContext from '../Net/IIP/DistributedPropertyContext.js';
import DistributedResource from '../Net/IIP/DistributedResource.js' import DistributedResource from '../Net/IIP/DistributedResource.js'
import IResource from '../Resource/IResource.js'; import IResource from '../Resource/IResource.js';
import RecordComparisonResult from './RecordComparisonResult.js';
import IRecord from './IRecord.js';
import Record from './Record.js';
export default class Codec { export default class Codec {
@ -132,6 +135,9 @@ export default class Codec {
case DataType.Structure: case DataType.Structure:
return Codec.parseStructureArray(data, offset, contentLength, connection); return Codec.parseStructureArray(data, offset, contentLength, connection);
case DataType.Record:
return Codec.parseRecordArray(data, offset, contentLength, connection);
} }
} }
else { else {
@ -192,6 +198,10 @@ export default class Codec {
case DataType.Structure: case DataType.Structure:
return Codec.parseStructure(data, offset, contentLength, connection); return Codec.parseStructure(data, offset, contentLength, connection);
case DataType.Record:
return Codec.parseRecord(data, offset, contentLength, connection);
} }
} }
@ -582,6 +592,10 @@ export default class Codec {
rt.addUint8Array(Codec.composeVarArray(value, connection, true)); rt.addUint8Array(Codec.composeVarArray(value, connection, true));
break; break;
case DataType.Record:
rt.addUint8Array(Codec.composeRecord(value, connection, true, true));
break;
case DataType.ResourceArray: case DataType.ResourceArray:
rt.addUint8Array(Codec.composeResourceArray(value, connection, true)); rt.addUint8Array(Codec.composeResourceArray(value, connection, true));
break; break;
@ -590,6 +604,10 @@ export default class Codec {
rt.addUint8Array(Codec.composeStructureArray(value, connection, true)); rt.addUint8Array(Codec.composeStructureArray(value, connection, true));
break; break;
case DataType.RecordArray:
rt.addUint8Array(Codec.composeRecordArray(value, connection, true));
break;
default: default:
rt.add({type: type, value: value}); rt.add({type: type, value: value});
if (DataType.isArray(type)) if (DataType.isArray(type))
@ -665,6 +683,206 @@ export default class Codec {
return rt.toArray(); return rt.toArray();
} }
/// <summary>
/// Compare two records
/// </summary>
/// <param name="initial">Initial record to compare with</param>
/// <param name="next">Next record to compare with the initial</param>
/// <param name="connection">DistributedConnection is required in case a structure holds items at the other end</param>
static compareRecords(initial, next)
{
if (next == null)
return RecordComparisonResult.Null;
if (initial == null)
return RecordComparisonResult.Record;
if (next == initial)
return RecordComparisonResult.Same;
if (next.constructor === initial.constructor)
return RecordComparisonResult.RecordSameType;
return RecordComparisonResult.Record;
}
static parseRecordArray(data, offset, length, connection)
{
var reply = new AsyncBag();
if (length == 0)
{
reply.seal();
return reply;
}
var end = offset + length;
var result = data.getUint8(offset++);
var previous = null;
var classId = null;
if (result == RecordComparisonResult.Null)
previous = new AsyncReply(null);
else if (result == RecordComparisonResult.Record)
{
var cs = data.getUint32(offset);
var recordLength = cs - 16;
offset += 4;
classId = data.getGuid(offset);
offset += 16;
previous = Codec.parseRecord(data, offset, recordLength, connection, classId);
offset += recordLength;
}
reply.Add(previous);
while (offset < end)
{
result = data.getUint8(offset++);
if (result == RecordComparisonResult.Null)
previous = new AsyncReply(null);
else if (result == RecordComparisonResult.Record)
{
var cs = data.getUint32(offset);
var recordLength = cs - 16;
offset += 4;
classId = data.getGuid(offset);
offset += 16;
previous = Codec.parseRecord(data, offset, recordLength, connection, classId);
offset += recordLength;
}
else if (result == RecordComparisonResult.RecordSameType)
{
var cs = data.getUint32(offset);
offset += 4;
previous = Codec.parseRecord(data, offset, cs, connection, classId);
offset += cs;
}
else if (result == RecordComparisonResult.Same)
{
// do nothing
}
reply.add(previous);
}
reply.seal();
return reply;
}
static parseRecord(data, offset, length, connection, classId = null)
{
var reply = new AsyncReply();
if (classId == null)
{
classId = data.getGuid(offset);
offset += 16;
length -= 16;
}
var template = Warehouse.getTemplateByClassId(classId);
if (template != null)
{
Codec.parseVarArray(data, offset, length, connection).then(ar =>
{
if (template.resourceType != null)
{
var record = new template.resourceType();
for (var i = 0; i < template.properties.length; i++)
record[template.properties[i].name] = ar[i];
reply.trigger(record);
}
else
{
var record = new Record();
for (var i = 0; i < template.properties.Length; i++)
record[template.properties[i].name] = ar[i];
reply.trigger(record);
}
});
}
else
{
connection.getTemplate(classId).then(tmp => {
Codec.parseVarArray(data, offset, length, connection).then(ar =>
{
var record = new Record();
for (var i = 0; i < tmp.properties.length; i++)
record[tmp.properties[i].name] = ar[i];
reply.trigger(record);
});
}).error(x=>reply.triggerError(x));
}
return reply;
}
static composeRecord(record, connection, includeClassId = true, prependLength = false)
{
var rt = new BinaryList();
var template = Warehouse.getTemplateByType(record.constructor);
if (includeClassId)
rt.addGuid(template.classId);
for(var i = 0; i < template.properties.length; i++)
{
var value = record[template.properties[i].name];
rt.addUint8Array(Codec.compose(value, connection));
}
if (prependLength)
rt.insertInt32(0, rt.length);
return rt.toArray();
}
static composeRecordArray(records, connection, prependLength = false)
{
if (records == null || records?.length == 0)
return prependLength ? new DC(4) : new DC(0);
var rt = new BinaryList();
var comparsion = Codec.compareRecords(null, records[0]);
rt.addUint8(comparsion);
if (comparsion == RecordComparisonResult.Record)
rt.addUint8Array(Codec.composeRecord(records[0], connection, true, true));
for (var i = 1; i < records.length; i++)
{
comparsion = Codec.compareRecords(records[i - 1], records[i]);
rt.addUint8(comparsion);
if (comparsion == RecordComparisonResult.Record)
rt.addUint8Array(Codec.composeRecord(records[i], connection, true, true));
else if (comparsion == RecordComparisonResult.RecordSameType)
rt.addUint8Array(Codec.composeRecord(records[i], connection, false, true));
}
if (prependLength)
rt.insertInt32(0, rt.length);
return rt.toArray();
}
static compareStructure(previous, next, connection) { static compareStructure(previous, next, connection) {
if (next == null) if (next == null)
return StructureComparisonResult.Null; return StructureComparisonResult.Null;
@ -854,6 +1072,9 @@ static getDataType(value, connection) {
else if (value instanceof Structure) { else if (value instanceof Structure) {
return DataType.Structure; return DataType.Structure;
} }
else if (value instanceof IRecord){
return DataType.Record;
}
else { else {
return DataType.Void return DataType.Void
} }
@ -900,7 +1121,7 @@ static getDataType(value, connection) {
{ {
var cs = data.getUint32(offset); var cs = data.getUint32(offset);
offset += 4; offset += 4;
previous = this.parseStructure(data, offset, cs, connection, metadata); previous = Codec.parseStructure(data, offset, cs, connection, metadata);
offset += cs; offset += cs;
} }
@ -917,21 +1138,21 @@ static getDataType(value, connection) {
{ {
var cs = data.getUint32(offset); var cs = data.getUint32(offset);
offset += 4; offset += 4;
previous = this.parseStructure(data, offset, cs, connection, metadata); previous = Codec.parseStructure(data, offset, cs, connection, metadata);
offset += cs; offset += cs;
} }
else if (result == StructureComparisonResult.StructureSameKeys) else if (result == StructureComparisonResult.StructureSameKeys)
{ {
var cs = data.getUint32(offset); var cs = data.getUint32(offset);
offset += 4; offset += 4;
previous = this.parseStructure(data, offset, cs, connection, metadata, metadata.keys); previous = Codec.parseStructure(data, offset, cs, connection, metadata, metadata.keys);
offset += cs; offset += cs;
} }
else if (result == StructureComparisonResult.StructureSameTypes) else if (result == StructureComparisonResult.StructureSameTypes)
{ {
var cs = data.getUint32(offset); var cs = data.getUint32(offset);
offset += 4; offset += 4;
previous = this.parseStructure(data, offset, cs, connection, metadata, metadata.keys, metadata.types); previous = Codec.parseStructure(data, offset, cs, connection, metadata, metadata.keys, metadata.types);
offset += cs; offset += cs;
} }

View File

@ -49,6 +49,7 @@ export default
ResourceLink: 17, ResourceLink: 17,
String: 18, String: 18,
Structure: 19, Structure: 19,
Record: 20,
//Stream, //Stream,
//Array = 0x80, //Array = 0x80,
VarArray: 0x80, VarArray: 0x80,
@ -71,6 +72,7 @@ export default
ResourceLinkArray: 0x91, ResourceLinkArray: 0x91,
StringArray: 0x92, StringArray: 0x92,
StructureArray: 0x93, StructureArray: 0x93,
RecordArray: 0x94,
NotModified: 0x7f, NotModified: 0x7f,
Unspecified: 0xff, Unspecified: 0xff,

3
src/Data/IRecord.js Normal file
View File

@ -0,0 +1,3 @@
export default class IRecord {
}

32
src/Data/Record.js Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2017-2021 Ahmed Kh. Zamil
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Created by Ahmed Zamil on 06/13/2021.
*/
import IRecord from './IRecord.js';
export default class Record extends IRecord
{
}

View File

@ -0,0 +1,7 @@
export default // const ResourceComparisonResult =
{
Null: 0,
Record: 1,
RecordSameType: 2,
Same: 3
};

View File

@ -969,8 +969,6 @@ export default class DistributedConnection extends IStore {
trigger(trigger) { trigger(trigger) {
console.log(this, trigger);
if (trigger == ResourceTrigger.Open) { if (trigger == ResourceTrigger.Open) {
if (this.server != null) if (this.server != null)
return new AsyncReply(true); return new AsyncReply(true);
@ -996,7 +994,7 @@ export default class DistributedConnection extends IStore {
var host = this.instance.name.split(':'); var host = this.instance.name.split(':');
var address = host[0]; var address = host[0];
var port = parseInt(host[1]); var port = host.length > 1 ? parseInt(host[1]) : 10518;
if (username != null if (username != null
&& password != null) && password != null)

View File

@ -29,6 +29,9 @@ import SHA256 from '../../Security/Integrity/SHA256.js';
import {DC, BL} from '../../Data/DataConverter.js'; import {DC, BL} from '../../Data/DataConverter.js';
import ArgumentTemplate from './ArgumentTemplate.js'; import ArgumentTemplate from './ArgumentTemplate.js';
import TemplateDataType from "./TemplateDataType.js"; import TemplateDataType from "./TemplateDataType.js";
import IResource from '../IResource.js';
import IRecord from '../../Data/IRecord.js';
import TemplateType from './TemplateType.js'
export default class ResourceTemplate { export default class ResourceTemplate {
@ -203,7 +206,6 @@ export default class ResourceTemplate {
constructor(type) { constructor(type) {
//@TODO: check if the type is IResource
this.properties = []; this.properties = [];
this.events = []; this.events = [];
@ -213,6 +215,13 @@ export default class ResourceTemplate {
if (type === undefined) if (type === undefined)
return; return;
if (type.prototype instanceof IRecord)
this.templateType = TemplateType.Record;
else if (type.prototype instanceof IResource)
this.templateType = TemplateType.Resource;
else
throw new Error("Type is neither a resource nor a record.");
this.resourceType = type; this.resourceType = type;
var template = type.template; var template = type.template;
@ -239,7 +248,11 @@ export default class ResourceTemplate {
this.properties.push(pt); this.properties.push(pt);
} }
if (this.templateType == TemplateType.Resource)
{
if (template.events != null) if (template.events != null)
{
for (var i = 0; i < template.events.length; i++) { for (var i = 0; i < template.events.length; i++) {
// [name, type, {listenable: true/false, help: ""}] // [name, type, {listenable: true/false, help: ""}]
@ -253,8 +266,10 @@ export default class ResourceTemplate {
et.eventInfo = ei; et.eventInfo = ei;
this.events.push(et); this.events.push(et);
} }
}
if (template.functions != null) if (template.functions != null)
{
for (var i = 0; i < template.functions.length; i++) { for (var i = 0; i < template.functions.length; i++) {
var fi = template.functions[i]; var fi = template.functions[i];
@ -274,6 +289,8 @@ export default class ResourceTemplate {
this.functions.push(ft); this.functions.push(ft);
} }
}
}
// append signals // append signals
@ -289,7 +306,8 @@ export default class ResourceTemplate {
// bake it binarily // bake it binarily
var b = BL(); var b = BL();
var cls = DC.stringToBytes(this.className); var cls = DC.stringToBytes(this.className);
b.addUint8Array(this.classId.value) b.addUint8(this.templateType)
.addUint8Array(this.classId.value)
.addUint8(cls.length) .addUint8(cls.length)
.addUint8Array(cls) .addUint8Array(cls)
.addUint32(template.version) .addUint32(template.version)
@ -341,6 +359,8 @@ export default class ResourceTemplate {
var od = new ResourceTemplate(); var od = new ResourceTemplate();
od.content = data.clip(offset, contentLength); od.content = data.clip(offset, contentLength);
od.templateType = data.getUint8(offset++);
od.classId = data.getGuid(offset); od.classId = data.getGuid(offset);
offset += 16; offset += 16;
od.className = data.getString(offset + 1, data.getUint8(offset)); od.className = data.getString(offset + 1, data.getUint8(offset));

View File

@ -27,6 +27,7 @@ import DataType from "../../Data/DataType.js";
import Structure from '../../Data/Structure.js'; import Structure from '../../Data/Structure.js';
import IResource from '../IResource.js'; import IResource from '../IResource.js';
import ResourceTemplate from './ResourceTemplate.js'; import ResourceTemplate from './ResourceTemplate.js';
import IRecord from '../../Data/IRecord.js';
export default class TemplateDataType export default class TemplateDataType
{ {
@ -83,6 +84,11 @@ export default class TemplateDataType
dataType = DataType.Resource; dataType = DataType.Resource;
typeGuid = ResourceTemplate.getTypeGuid(type); typeGuid = ResourceTemplate.getTypeGuid(type);
} }
else if (type?.prototype instanceof IRecord)
{
dataType = DataType.Record;
typeGuid = ResourceTemplate.getTypeGuid(type);
}
if (isArray) if (isArray)
dataType |= DataType.VarArray; dataType |= DataType.VarArray;
@ -96,7 +102,9 @@ export default class TemplateDataType
compose() compose()
{ {
if (this.type == DataType.Resource || if (this.type == DataType.Resource ||
this.type == DataType.ResourceArray) this.type == DataType.ResourceArray ||
this.type == DataType.Record ||
this.type == DataType.RecordArray)
{ {
return BL() return BL()
.addUint8(this.type) .addUint8(this.type)
@ -116,7 +124,9 @@ export default class TemplateDataType
{ {
var type = data.getUint8(offset++); var type = data.getUint8(offset++);
if (type == DataType.Resource || if (type == DataType.Resource ||
type == DataType.ResourceArray) type == DataType.ResourceArray ||
type == DataType.Record ||
type == DataType.RecordArray)
{ {
var guid = data.getGuid(offset); var guid = data.getGuid(offset);
return {size: 17, value: new TemplateDataType(type, guid)}; return {size: 17, value: new TemplateDataType(type, guid)};

View File

@ -0,0 +1,5 @@
export default
{
Resource: 0,
Record: 1
}

View File

@ -39,6 +39,7 @@ import IResource, { ResourceTrigger } from './IResource.js';
import IndexedDBStore from '../Stores/IndexedDBStore.js'; import IndexedDBStore from '../Stores/IndexedDBStore.js';
import ResourceProxy from '../Proxy/ResourceProxy.js'; import ResourceProxy from '../Proxy/ResourceProxy.js';
import AsyncBag from '../Core/AsyncBag.js'; import AsyncBag from '../Core/AsyncBag.js';
import IRecord from '../Data/IRecord.js';
export class WH extends IEventHandler export class WH extends IEventHandler
@ -51,6 +52,7 @@ export class WH extends IEventHandler
this.resources = new KeyList(); this.resources = new KeyList();
this.resourceCounter = 0; this.resourceCounter = 0;
this.templates = new KeyList(); this.templates = new KeyList();
this.wrapperTemplates = new KeyList();
this.protocols = new KeyList(); this.protocols = new KeyList();
this._register("connected"); this._register("connected");
this._register("disconnected"); this._register("disconnected");
@ -289,18 +291,25 @@ export class WH extends IEventHandler
value.instance.parents.add(value); value.instance.parents.add(value);
} }
putTemplate(template) putTemplate(template, wrapper = false)
{ {
if (wrapper) {
this.wrapperTemplates.add(template.classId.valueOf(), template);
}
else {
this.templates.add(template.classId.valueOf(), template); this.templates.add(template.classId.valueOf(), template);
} }
}
getTemplateByType(type) getTemplateByType(type)
{ {
if (type == IResource) if (type == IResource
|| type == IRecord)
return null; return null;
if (!(type.prototype instanceof IResource)) if (!(type.prototype instanceof IResource
|| type.prototype instanceof IRecord))
return false; return false;
let className = type.prototype.constructor.name; let className = type.prototype.constructor.name;
@ -321,10 +330,14 @@ export class WH extends IEventHandler
return template; return template;
} }
getTemplateByClassId(classId) getTemplateByClassId(classId, wrapper = false)
{ {
var template = this.templates.item(classId); if (wrapper) {
return template; return this.wrapperTemplates.item(classId);
}
else {
return this.templates.item(classId);
}
} }
getTemplateByClassName(className) getTemplateByClassName(className)