2017-11-30 04:11:59 +00:00
|
|
|
import * as Long from 'long';
|
2020-11-19 16:51:14 +00:00
|
|
|
import { Subject, Subscription } from 'rxjs';
|
2021-09-23 16:37:54 +01:00
|
|
|
import * as xml2js from 'xml2js';
|
|
|
|
|
|
|
|
|
|
import * as zlib from 'zlib';
|
2020-01-09 17:53:22 +00:00
|
|
|
import { AssetType } from '../enums/AssetType';
|
2020-11-19 16:51:14 +00:00
|
|
|
import { FilterResponse } from '../enums/FilterResponse';
|
2021-09-23 16:37:54 +01:00
|
|
|
import { HTTPAssets } from '../enums/HTTPAssets';
|
|
|
|
|
import { InventoryType } from '../enums/InventoryType';
|
2020-11-19 16:51:14 +00:00
|
|
|
import { Logger } from './Logger';
|
2021-09-23 16:37:54 +01:00
|
|
|
import { GlobalPosition } from './public/interfaces/GlobalPosition';
|
|
|
|
|
import { Quaternion } from './Quaternion';
|
|
|
|
|
import { Vector3 } from './Vector3';
|
2022-04-19 16:12:21 +01:00
|
|
|
import * as crypto from 'crypto';
|
2023-11-09 19:06:55 +00:00
|
|
|
import Timeout = NodeJS.Timeout;
|
2020-12-03 13:55:02 +00:00
|
|
|
|
2017-11-26 19:47:41 +00:00
|
|
|
export class Utils
|
|
|
|
|
{
|
2018-11-15 03:10:14 +00:00
|
|
|
static TWO_PI = 6.283185307179586476925286766559;
|
|
|
|
|
static CUT_QUANTA = 0.00002;
|
|
|
|
|
static SCALE_QUANTA = 0.01;
|
|
|
|
|
static SHEAR_QUANTA = 0.01;
|
|
|
|
|
static TAPER_QUANTA = 0.01;
|
|
|
|
|
static REV_QUANTA = 0.015;
|
|
|
|
|
static HOLLOW_QUANTA = 0.00002;
|
|
|
|
|
|
2017-11-26 19:47:41 +00:00
|
|
|
static StringToBuffer(str: string): Buffer
|
|
|
|
|
{
|
|
|
|
|
return Buffer.from(str + '\0', 'utf8');
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2022-04-19 16:12:21 +01:00
|
|
|
static SHA1String(str: string): string
|
|
|
|
|
{
|
|
|
|
|
return crypto.createHash('sha1').update(str).digest('hex');
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static BufferToStringSimple(buf: Buffer): string
|
2017-11-30 04:11:59 +00:00
|
|
|
{
|
|
|
|
|
if (buf.length === 0)
|
|
|
|
|
{
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
if (buf[buf.length - 1] === 0)
|
|
|
|
|
{
|
|
|
|
|
return buf.slice(0, buf.length - 1).toString('utf8');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return buf.toString('utf8');
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static Clamp(value: number, min: number, max: number): number
|
2018-11-05 11:45:04 +00:00
|
|
|
{
|
|
|
|
|
value = (value > max) ? max : value;
|
|
|
|
|
value = (value < min) ? min : value;
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static fillArray<T>(value: T, count: number): T[]
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
const arr: T[] = new Array<T>(count);
|
|
|
|
|
while (count--)
|
|
|
|
|
{
|
|
|
|
|
arr[count] = value;
|
|
|
|
|
}
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static JSONStringify(obj: object, space: number): string
|
- Add "GET" method to Caps
- New events: ObjectPhysicsDataEvent, ParcelPropertiesEvent, NewObjectEvent, ObjectUpdateEvent, ObjectKilledEvent
- Added getXML function to Color4, Vector2, Vector3, Vector4, GameObject, Region, Quaternion, UUID for opensim-compatible XML export
- Added TextureAnim and ParticleSystem decoding to the "full" ObjectStore
- Object store will automatically request missing "parent" prims
- "setPersist" - When persist is TRUE, the ObjectStore will not forget about "killed" prims - useful for region scanning
- Support for Flexible params, Light params, LightImage params, Mesh data, Sculpt maps
- Fixed object scale being incorrectly calculated
- Add terrain decoding (this was a ballache)
- Add parcel map decoding
- Add support for region windlight settings (region.environment)
- Add support for materials (normal / specular maps)
- Add getBuffer, getLong and bitwiseOr to UUID
- Added a circular-reference-safe JSONStringify to Utils
- Add XferFile capability to Circuit
PUBLIC API:
AssetCommands:
- Rework "downloadAsset" to detect failures
- NEW: downloadInventoryAsset() - uses TransferRequest for prim inventory items
- NEW: getMaterials() - resolves material UUIDs
RegionCommands:
- NEW: getTerrainTextures()
- NEW: exportSettings() - OpenSim XML export of region settings
- NEW: async getTerrain() - Get binary terrain heightmap, 256x256 float32
- resolveObjects() - now fetches task inventory contents too.
- resolveObjects() - fix calculation of land impact
- NEW: getObjectByLocalID(localID: number, timeout: number)
- NEW: getObjectByUUID(uuid: UUID, timeout: number)
- NEW: getParcels();
- NEW: pruneObjects - removes missing GameObjects from a list
- NEW: setPersist - prevent objectstore from forgetting about killed gameobjects
2018-10-31 11:28:24 +00:00
|
|
|
{
|
|
|
|
|
const cache: any[] = [];
|
2021-09-23 17:21:36 +01:00
|
|
|
return JSON.stringify(obj, function(_: string, value): unknown
|
- Add "GET" method to Caps
- New events: ObjectPhysicsDataEvent, ParcelPropertiesEvent, NewObjectEvent, ObjectUpdateEvent, ObjectKilledEvent
- Added getXML function to Color4, Vector2, Vector3, Vector4, GameObject, Region, Quaternion, UUID for opensim-compatible XML export
- Added TextureAnim and ParticleSystem decoding to the "full" ObjectStore
- Object store will automatically request missing "parent" prims
- "setPersist" - When persist is TRUE, the ObjectStore will not forget about "killed" prims - useful for region scanning
- Support for Flexible params, Light params, LightImage params, Mesh data, Sculpt maps
- Fixed object scale being incorrectly calculated
- Add terrain decoding (this was a ballache)
- Add parcel map decoding
- Add support for region windlight settings (region.environment)
- Add support for materials (normal / specular maps)
- Add getBuffer, getLong and bitwiseOr to UUID
- Added a circular-reference-safe JSONStringify to Utils
- Add XferFile capability to Circuit
PUBLIC API:
AssetCommands:
- Rework "downloadAsset" to detect failures
- NEW: downloadInventoryAsset() - uses TransferRequest for prim inventory items
- NEW: getMaterials() - resolves material UUIDs
RegionCommands:
- NEW: getTerrainTextures()
- NEW: exportSettings() - OpenSim XML export of region settings
- NEW: async getTerrain() - Get binary terrain heightmap, 256x256 float32
- resolveObjects() - now fetches task inventory contents too.
- resolveObjects() - fix calculation of land impact
- NEW: getObjectByLocalID(localID: number, timeout: number)
- NEW: getObjectByUUID(uuid: UUID, timeout: number)
- NEW: getParcels();
- NEW: pruneObjects - removes missing GameObjects from a list
- NEW: setPersist - prevent objectstore from forgetting about killed gameobjects
2018-10-31 11:28:24 +00:00
|
|
|
{
|
|
|
|
|
if (typeof value === 'object' && value !== null)
|
|
|
|
|
{
|
|
|
|
|
if (cache.indexOf(value) !== -1)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return JSON.parse(JSON.stringify(value));
|
|
|
|
|
}
|
|
|
|
|
catch (error)
|
|
|
|
|
{
|
|
|
|
|
return 'Circular Reference';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cache.push(value);
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}, space);
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2017-11-30 04:11:59 +00:00
|
|
|
static BufferToString(buf: Buffer, startPos?: number):
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
readLength: number,
|
|
|
|
|
result: string
|
|
|
|
|
}
|
2017-11-30 04:11:59 +00:00
|
|
|
{
|
|
|
|
|
if (buf.length === 0)
|
|
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
readLength: 0,
|
|
|
|
|
result: ''
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if (startPos === undefined)
|
|
|
|
|
{
|
|
|
|
|
startPos = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let foundNull = -1;
|
|
|
|
|
for (let x = startPos; x <= buf.length; x++)
|
|
|
|
|
{
|
|
|
|
|
if (buf[x] === 0)
|
|
|
|
|
{
|
|
|
|
|
foundNull = x;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (foundNull === -1)
|
|
|
|
|
{
|
|
|
|
|
console.error('BufferToString: Null terminator not found after ' + (buf.length - startPos) + ' bytes. Buffer length: ' + buf.length + ', startPos: ' + startPos);
|
|
|
|
|
foundNull = buf.length - 1;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
readLength: (foundNull - startPos) + 1,
|
|
|
|
|
result: buf.slice(startPos, foundNull).toString('utf8')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 14:34:43 +01:00
|
|
|
static RegionCoordinatesToHandle(regionX: number, regionY: number): GlobalPosition
|
2017-11-30 04:11:59 +00:00
|
|
|
{
|
2018-10-12 14:34:43 +01:00
|
|
|
const realRegionX = Math.floor(regionX / 256) * 256;
|
|
|
|
|
const realRegionY = Math.floor(regionY / 256) * 256;
|
|
|
|
|
const localX = regionX - realRegionX;
|
|
|
|
|
const localY = regionY - realRegionY;
|
|
|
|
|
const handle = new Long(realRegionY, realRegionX);
|
|
|
|
|
return {
|
|
|
|
|
'regionHandle': handle,
|
|
|
|
|
'regionX': realRegionX / 256,
|
|
|
|
|
'regionY': realRegionY / 256,
|
|
|
|
|
'localX': localX,
|
|
|
|
|
'localY': localY
|
|
|
|
|
};
|
2017-11-30 04:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 16:51:14 +00:00
|
|
|
static InventoryTypeToLLInventoryType(type: InventoryType): string
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case InventoryType.Texture:
|
|
|
|
|
return 'texture';
|
|
|
|
|
case InventoryType.Sound:
|
|
|
|
|
return 'sound';
|
|
|
|
|
case InventoryType.CallingCard:
|
|
|
|
|
return 'callcard';
|
|
|
|
|
case InventoryType.Landmark:
|
|
|
|
|
return 'landmark';
|
|
|
|
|
case InventoryType.Object:
|
|
|
|
|
return 'object';
|
|
|
|
|
case InventoryType.Notecard:
|
|
|
|
|
return 'notecard';
|
|
|
|
|
case InventoryType.Category:
|
|
|
|
|
return 'category';
|
|
|
|
|
case InventoryType.RootCategory:
|
|
|
|
|
return 'root';
|
|
|
|
|
case InventoryType.Script:
|
|
|
|
|
return 'script';
|
|
|
|
|
case InventoryType.Snapshot:
|
|
|
|
|
return 'snapshot';
|
|
|
|
|
case InventoryType.Attachment:
|
|
|
|
|
return 'attach';
|
2021-09-22 14:58:49 +01:00
|
|
|
case InventoryType.Bodypart:
|
|
|
|
|
return 'bodypart';
|
2020-11-19 16:51:14 +00:00
|
|
|
case InventoryType.Wearable:
|
|
|
|
|
return 'wearable';
|
|
|
|
|
case InventoryType.Animation:
|
|
|
|
|
return 'animation';
|
|
|
|
|
case InventoryType.Gesture:
|
|
|
|
|
return 'gesture';
|
|
|
|
|
case InventoryType.Mesh:
|
|
|
|
|
return 'mesh';
|
2021-09-22 14:53:34 +01:00
|
|
|
case InventoryType.LSL:
|
2021-09-23 16:37:54 +01:00
|
|
|
return 'script';
|
|
|
|
|
case InventoryType.Widget:
|
|
|
|
|
return 'widget';
|
|
|
|
|
case InventoryType.Person:
|
|
|
|
|
return 'person';
|
|
|
|
|
case InventoryType.Settings:
|
|
|
|
|
return 'settings';
|
2023-11-09 19:06:55 +00:00
|
|
|
case InventoryType.Material:
|
|
|
|
|
return 'material';
|
2020-11-19 16:51:14 +00:00
|
|
|
default:
|
|
|
|
|
console.error('Unknown inventory type: ' + InventoryType[type]);
|
|
|
|
|
return 'texture';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 17:53:22 +00:00
|
|
|
static HTTPAssetTypeToAssetType(HTTPAssetType: string): AssetType
|
|
|
|
|
{
|
|
|
|
|
switch (HTTPAssetType)
|
|
|
|
|
{
|
|
|
|
|
case HTTPAssets.ASSET_TEXTURE:
|
|
|
|
|
return AssetType.Texture;
|
|
|
|
|
case HTTPAssets.ASSET_SOUND:
|
|
|
|
|
return AssetType.Sound;
|
|
|
|
|
case HTTPAssets.ASSET_ANIMATION:
|
|
|
|
|
return AssetType.Animation;
|
|
|
|
|
case HTTPAssets.ASSET_GESTURE:
|
|
|
|
|
return AssetType.Gesture;
|
|
|
|
|
case HTTPAssets.ASSET_LANDMARK:
|
|
|
|
|
return AssetType.Landmark;
|
|
|
|
|
case HTTPAssets.ASSET_CALLINGCARD:
|
|
|
|
|
return AssetType.CallingCard;
|
|
|
|
|
case HTTPAssets.ASSET_SCRIPT:
|
|
|
|
|
return AssetType.Script;
|
|
|
|
|
case HTTPAssets.ASSET_CLOTHING:
|
|
|
|
|
return AssetType.Clothing;
|
|
|
|
|
case HTTPAssets.ASSET_OBJECT:
|
|
|
|
|
return AssetType.Object;
|
|
|
|
|
case HTTPAssets.ASSET_NOTECARD:
|
|
|
|
|
return AssetType.Notecard;
|
|
|
|
|
case HTTPAssets.ASSET_LSL_TEXT:
|
|
|
|
|
return AssetType.LSLText;
|
|
|
|
|
case HTTPAssets.ASSET_LSL_BYTECODE:
|
|
|
|
|
return AssetType.LSLBytecode;
|
|
|
|
|
case HTTPAssets.ASSET_BODYPART:
|
|
|
|
|
return AssetType.Bodypart;
|
|
|
|
|
case HTTPAssets.ASSET_MESH:
|
|
|
|
|
return AssetType.Mesh;
|
2021-09-23 16:37:54 +01:00
|
|
|
case HTTPAssets.ASSET_SETTINGS:
|
|
|
|
|
return AssetType.Settings;
|
|
|
|
|
case HTTPAssets.ASSET_WIDGET:
|
|
|
|
|
return AssetType.Widget;
|
|
|
|
|
case HTTPAssets.ASSET_PERSON:
|
|
|
|
|
return AssetType.Person;
|
2023-11-09 19:06:55 +00:00
|
|
|
case HTTPAssets.ASSET_MATERIAL:
|
|
|
|
|
return AssetType.Material;
|
2020-01-09 17:53:22 +00:00
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 16:51:14 +00:00
|
|
|
static AssetTypeToHTTPAssetType(assetType: AssetType): HTTPAssets
|
|
|
|
|
{
|
|
|
|
|
switch (assetType)
|
|
|
|
|
{
|
|
|
|
|
case AssetType.Texture:
|
|
|
|
|
return HTTPAssets.ASSET_TEXTURE;
|
|
|
|
|
case AssetType.Sound:
|
|
|
|
|
return HTTPAssets.ASSET_SOUND;
|
|
|
|
|
case AssetType.Animation:
|
|
|
|
|
return HTTPAssets.ASSET_ANIMATION;
|
|
|
|
|
case AssetType.Gesture:
|
|
|
|
|
return HTTPAssets.ASSET_GESTURE;
|
|
|
|
|
case AssetType.Landmark:
|
|
|
|
|
return HTTPAssets.ASSET_LANDMARK;
|
|
|
|
|
case AssetType.CallingCard:
|
|
|
|
|
return HTTPAssets.ASSET_CALLINGCARD;
|
|
|
|
|
case AssetType.Script:
|
|
|
|
|
return HTTPAssets.ASSET_SCRIPT;
|
|
|
|
|
case AssetType.Clothing:
|
|
|
|
|
return HTTPAssets.ASSET_CLOTHING;
|
|
|
|
|
case AssetType.Object:
|
|
|
|
|
return HTTPAssets.ASSET_OBJECT;
|
|
|
|
|
case AssetType.Notecard:
|
|
|
|
|
return HTTPAssets.ASSET_NOTECARD;
|
|
|
|
|
case AssetType.LSLText:
|
|
|
|
|
return HTTPAssets.ASSET_LSL_TEXT;
|
|
|
|
|
case AssetType.LSLBytecode:
|
|
|
|
|
return HTTPAssets.ASSET_LSL_BYTECODE;
|
|
|
|
|
case AssetType.Bodypart:
|
|
|
|
|
return HTTPAssets.ASSET_BODYPART;
|
|
|
|
|
case AssetType.Mesh:
|
|
|
|
|
return HTTPAssets.ASSET_MESH;
|
2021-09-23 16:37:54 +01:00
|
|
|
case AssetType.Settings:
|
|
|
|
|
return HTTPAssets.ASSET_SETTINGS;
|
|
|
|
|
case AssetType.Person:
|
|
|
|
|
return HTTPAssets.ASSET_PERSON;
|
|
|
|
|
case AssetType.Widget:
|
|
|
|
|
return HTTPAssets.ASSET_WIDGET;
|
2023-11-09 19:06:55 +00:00
|
|
|
case AssetType.Material:
|
|
|
|
|
return HTTPAssets.ASSET_MATERIAL;
|
2020-11-19 16:51:14 +00:00
|
|
|
default:
|
|
|
|
|
return HTTPAssets.ASSET_TEXTURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HTTPAssetTypeToInventoryType(HTTPAssetType: string): InventoryType
|
2020-01-09 17:53:22 +00:00
|
|
|
{
|
|
|
|
|
switch (HTTPAssetType)
|
|
|
|
|
{
|
|
|
|
|
case HTTPAssets.ASSET_TEXTURE:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Texture;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_SOUND:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Sound;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_ANIMATION:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Animation;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_GESTURE:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Gesture;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_LANDMARK:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Landmark;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_CALLINGCARD:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.CallingCard;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_SCRIPT:
|
2021-09-23 16:37:54 +01:00
|
|
|
return InventoryType.LSL;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_CLOTHING:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Wearable;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_OBJECT:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Object;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_NOTECARD:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Notecard;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_LSL_TEXT:
|
2021-09-23 16:37:54 +01:00
|
|
|
return InventoryType.LSL;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_LSL_BYTECODE:
|
2021-09-23 16:37:54 +01:00
|
|
|
return InventoryType.LSL;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_BODYPART:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Wearable;
|
2020-01-09 17:53:22 +00:00
|
|
|
case HTTPAssets.ASSET_MESH:
|
2020-11-19 16:51:14 +00:00
|
|
|
return InventoryType.Mesh;
|
2023-11-09 19:06:55 +00:00
|
|
|
case HTTPAssets.ASSET_MATERIAL:
|
|
|
|
|
return InventoryType.Material;
|
2020-01-09 17:53:22 +00:00
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static HTTPAssetTypeToCapInventoryType(HTTPAssetType: string): String
|
2017-11-30 04:11:59 +00:00
|
|
|
{
|
|
|
|
|
switch (HTTPAssetType)
|
|
|
|
|
{
|
|
|
|
|
case HTTPAssets.ASSET_TEXTURE:
|
|
|
|
|
return 'texture';
|
|
|
|
|
case HTTPAssets.ASSET_SOUND:
|
|
|
|
|
return 'sound';
|
|
|
|
|
case HTTPAssets.ASSET_ANIMATION:
|
|
|
|
|
return 'animation';
|
|
|
|
|
case HTTPAssets.ASSET_GESTURE:
|
|
|
|
|
return 'gesture';
|
|
|
|
|
case HTTPAssets.ASSET_LANDMARK:
|
|
|
|
|
return 'landmark';
|
|
|
|
|
case HTTPAssets.ASSET_CALLINGCARD:
|
|
|
|
|
return 'callcard';
|
|
|
|
|
case HTTPAssets.ASSET_SCRIPT:
|
|
|
|
|
return 'script';
|
|
|
|
|
case HTTPAssets.ASSET_CLOTHING:
|
|
|
|
|
return 'wearable';
|
|
|
|
|
case HTTPAssets.ASSET_OBJECT:
|
|
|
|
|
return 'object';
|
|
|
|
|
case HTTPAssets.ASSET_NOTECARD:
|
|
|
|
|
return 'notecard';
|
|
|
|
|
case HTTPAssets.ASSET_CATEGORY:
|
|
|
|
|
return 'category';
|
|
|
|
|
case HTTPAssets.ASSET_LSL_TEXT:
|
|
|
|
|
return 'script';
|
|
|
|
|
case HTTPAssets.ASSET_LSL_BYTECODE:
|
|
|
|
|
return 'script';
|
|
|
|
|
case HTTPAssets.ASSET_BODYPART:
|
|
|
|
|
return 'wearable';
|
|
|
|
|
case HTTPAssets.ASSET_MESH:
|
|
|
|
|
return 'mesh';
|
|
|
|
|
default:
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static FloatToByte(val: number, lower: number, upper: number): number
|
2018-11-05 11:45:04 +00:00
|
|
|
{
|
|
|
|
|
val = Utils.Clamp(val, lower, upper);
|
|
|
|
|
val -= lower;
|
|
|
|
|
val /= (upper - lower);
|
|
|
|
|
return Math.round(val * 255);
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static ByteToFloat(byte: number, lower: number, upper: number): number
|
2018-10-16 16:46:58 +01:00
|
|
|
{
|
|
|
|
|
const ONE_OVER_BYTEMAX: number = 1.0 / 255;
|
|
|
|
|
|
|
|
|
|
let fval: number = byte * ONE_OVER_BYTEMAX;
|
|
|
|
|
const delta: number = (upper - lower);
|
|
|
|
|
fval *= delta;
|
|
|
|
|
fval += lower;
|
|
|
|
|
|
|
|
|
|
const error: number = delta * ONE_OVER_BYTEMAX;
|
|
|
|
|
if (Math.abs(fval) < error)
|
|
|
|
|
{
|
|
|
|
|
fval = 0.0;
|
|
|
|
|
}
|
|
|
|
|
return fval;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static UInt16ToFloat(val: number, lower: number, upper: number): number
|
2017-11-30 04:11:59 +00:00
|
|
|
{
|
|
|
|
|
const ONE_OVER_U16_MAX = 1.0 / 65535;
|
|
|
|
|
let fval = val * ONE_OVER_U16_MAX;
|
|
|
|
|
const delta = upper - lower;
|
|
|
|
|
fval *= delta;
|
|
|
|
|
fval += lower;
|
|
|
|
|
|
|
|
|
|
const maxError = delta * ONE_OVER_U16_MAX;
|
|
|
|
|
if (Math.abs(fval) < maxError)
|
|
|
|
|
{
|
|
|
|
|
fval = 0.0;
|
|
|
|
|
}
|
|
|
|
|
return fval;
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2017-11-30 04:11:59 +00:00
|
|
|
static Base64EncodeString(str: string): string
|
|
|
|
|
{
|
2020-11-19 16:51:14 +00:00
|
|
|
const buff = Buffer.from(str, 'utf8');
|
2017-11-30 04:11:59 +00:00
|
|
|
return buff.toString('base64');
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2017-11-30 04:11:59 +00:00
|
|
|
static Base64DecodeString(str: string): string
|
|
|
|
|
{
|
2020-11-19 16:51:14 +00:00
|
|
|
const buff = Buffer.from(str, 'base64');
|
2017-11-30 04:11:59 +00:00
|
|
|
return buff.toString('utf8');
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static HexToLong(hex: string): Long
|
2017-12-15 21:28:45 +00:00
|
|
|
{
|
|
|
|
|
while (hex.length < 16)
|
|
|
|
|
{
|
|
|
|
|
hex = '0' + hex;
|
|
|
|
|
}
|
|
|
|
|
return new Long(parseInt(hex.substr(8), 16), parseInt(hex.substr(0, 8), 16));
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2018-10-16 16:46:58 +01:00
|
|
|
static ReadRotationFloat(buf: Buffer, pos: number): number
|
|
|
|
|
{
|
2018-11-15 03:10:14 +00:00
|
|
|
return ((buf[pos] | (buf[pos + 1] << 8)) / 32768.0) * Utils.TWO_PI;
|
2018-10-16 16:46:58 +01:00
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2018-10-16 16:46:58 +01:00
|
|
|
static ReadGlowFloat(buf: Buffer, pos: number): number
|
|
|
|
|
{
|
|
|
|
|
return buf[pos] / 255;
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2018-10-16 16:46:58 +01:00
|
|
|
static ReadOffsetFloat(buf: Buffer, pos: number): number
|
|
|
|
|
{
|
|
|
|
|
const offset = buf.readInt16LE(pos);
|
|
|
|
|
return offset / 32767.0;
|
|
|
|
|
}
|
2018-11-15 03:10:14 +00:00
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static TEOffsetShort(num: number): number
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
num = Utils.Clamp(num, -1.0, 1.0);
|
|
|
|
|
num *= 32767.0;
|
|
|
|
|
return Math.round(num);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static IEEERemainder(x: number, y: number): number
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
if (isNaN(x))
|
|
|
|
|
{
|
|
|
|
|
return x; // IEEE 754-2008: NaN payload must be preserved
|
|
|
|
|
}
|
|
|
|
|
if (isNaN(y))
|
|
|
|
|
{
|
|
|
|
|
return y; // IEEE 754-2008: NaN payload must be preserved
|
|
|
|
|
}
|
|
|
|
|
const regularMod = x % y;
|
|
|
|
|
if (isNaN(regularMod))
|
|
|
|
|
{
|
|
|
|
|
return NaN;
|
|
|
|
|
}
|
|
|
|
|
if (regularMod === 0)
|
|
|
|
|
{
|
|
|
|
|
if (Math.sign(x) < 0)
|
|
|
|
|
{
|
|
|
|
|
return -0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const alternativeResult = regularMod - (Math.abs(y) * Math.sign(x));
|
|
|
|
|
if (Math.abs(alternativeResult) === Math.abs(regularMod))
|
|
|
|
|
{
|
|
|
|
|
const divisionResult = x / y;
|
|
|
|
|
const roundedResult = Math.round(divisionResult);
|
|
|
|
|
if (Math.abs(roundedResult) > Math.abs(divisionResult))
|
|
|
|
|
{
|
|
|
|
|
return alternativeResult;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return regularMod;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Math.abs(alternativeResult) < Math.abs(regularMod))
|
|
|
|
|
{
|
|
|
|
|
return alternativeResult;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return regularMod;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static TERotationShort(rotation: number): number
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
return Math.floor(((Utils.IEEERemainder(rotation, Utils.TWO_PI) / Utils.TWO_PI) * 32768.0) + 0.5);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static OctetsToUInt32BE(octets: number[]): number
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
const buf = Buffer.allocUnsafe(4);
|
|
|
|
|
let pos = 0;
|
|
|
|
|
for (let x = octets.length - 4; x < octets.length; x++)
|
|
|
|
|
{
|
|
|
|
|
if (x >= 0)
|
|
|
|
|
{
|
|
|
|
|
buf.writeUInt8(octets[x], pos++);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return buf.readUInt32BE(0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static OctetsToUInt32LE(octets: number[]): number
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
const buf = Buffer.allocUnsafe(4);
|
|
|
|
|
let pos = 0;
|
|
|
|
|
for (let x = octets.length - 4; x < octets.length; x++)
|
|
|
|
|
{
|
|
|
|
|
if (x >= 0)
|
|
|
|
|
{
|
|
|
|
|
buf.writeUInt8(octets[x], pos++);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return buf.readUInt32LE(0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static numberToFixedHex(num: number): string
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
let str = num.toString(16);
|
|
|
|
|
while (str.length < 8)
|
|
|
|
|
{
|
|
|
|
|
str = '0' + str;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static TEGlowByte(glow: number): number
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
return (glow * 255.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NumberToByteBuffer(num: number): Buffer
|
|
|
|
|
{
|
|
|
|
|
const buf = Buffer.allocUnsafe(1);
|
|
|
|
|
buf.writeUInt8(num, 0);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NumberToShortBuffer(num: number): Buffer
|
|
|
|
|
{
|
|
|
|
|
const buf = Buffer.allocUnsafe(2);
|
|
|
|
|
buf.writeInt16LE(num, 0);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NumberToFloatBuffer(num: number): Buffer
|
|
|
|
|
{
|
|
|
|
|
const buf = Buffer.allocUnsafe(4);
|
|
|
|
|
buf.writeFloatLE(num, 0);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static numberOrZero(num: number | undefined): number
|
|
|
|
|
{
|
|
|
|
|
if (num === undefined)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static vector3OrZero(vec: Vector3 | undefined): Vector3
|
|
|
|
|
{
|
|
|
|
|
if (vec === undefined)
|
|
|
|
|
{
|
|
|
|
|
return Vector3.getZero();
|
|
|
|
|
}
|
|
|
|
|
return vec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static quaternionOrZero(quat: Quaternion | undefined): Quaternion
|
|
|
|
|
{
|
|
|
|
|
if (quat === undefined)
|
|
|
|
|
{
|
|
|
|
|
return Quaternion.getIdentity();
|
|
|
|
|
}
|
|
|
|
|
return quat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packBeginCut(beginCut: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round(beginCut / Utils.CUT_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packEndCut(endCut: number): number
|
|
|
|
|
{
|
|
|
|
|
return (50000 - Math.round(endCut / Utils.CUT_QUANTA));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packPathScale(pathScale: number): number
|
|
|
|
|
{
|
|
|
|
|
return (200 - Math.round(pathScale / Utils.SCALE_QUANTA));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packPathShear(pathShear: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round(pathShear / Utils.SHEAR_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packPathTwist(pathTwist: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round(pathTwist / Utils.SCALE_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packPathTaper(pathTaper: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round(pathTaper / Utils.TAPER_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packPathRevolutions(pathRevolutions: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round((pathRevolutions - 1) / Utils.REV_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static packProfileHollow(profileHollow: number): number
|
|
|
|
|
{
|
|
|
|
|
return Math.round(profileHollow / Utils.HOLLOW_QUANTA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackBeginCut(beginCut: number): number
|
|
|
|
|
{
|
|
|
|
|
return beginCut * Utils.CUT_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackEndCut(endCut: number): number
|
|
|
|
|
{
|
|
|
|
|
return (50000 - endCut) * Utils.CUT_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackPathScale(pathScale: number): number
|
|
|
|
|
{
|
|
|
|
|
return (200 - pathScale) * Utils.SCALE_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackPathShear(pathShear: number): number
|
|
|
|
|
{
|
|
|
|
|
return pathShear * Utils.SHEAR_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackPathTwist(pathTwist: number): number
|
|
|
|
|
{
|
|
|
|
|
return pathTwist * Utils.SCALE_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackPathTaper(pathTaper: number): number
|
|
|
|
|
{
|
|
|
|
|
return pathTaper * Utils.TAPER_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackPathRevolutions(pathRevolutions: number): number
|
|
|
|
|
{
|
|
|
|
|
return pathRevolutions * Utils.REV_QUANTA + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unpackProfileHollow(profileHollow: number): number
|
|
|
|
|
{
|
|
|
|
|
return profileHollow * Utils.HOLLOW_QUANTA;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static nullTerminatedString(str: string): string
|
2018-11-15 03:10:14 +00:00
|
|
|
{
|
|
|
|
|
const index = str.indexOf('\0');
|
|
|
|
|
if (index === -1)
|
|
|
|
|
{
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return str.substr(0, index - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-07 21:01:20 +00:00
|
|
|
|
2021-09-23 17:21:36 +01:00
|
|
|
static promiseConcurrent<T>(promises: (() => Promise<T>)[], concurrency: number, timeout: number): Promise<{ results: T[], errors: Error[] }>
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
2021-09-23 17:21:36 +01:00
|
|
|
return new Promise<{ results: T[], errors: Error[] }>(async(resolve) =>
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
|
|
|
|
const originalConcurrency = concurrency;
|
|
|
|
|
const promiseQueue: (() => Promise<T>)[] = [];
|
2020-11-19 16:51:14 +00:00
|
|
|
Logger.Info('PromiseConcurrent: ' + promiseQueue.length + ' in queue. Concurrency: ' + concurrency);
|
2020-01-07 21:01:20 +00:00
|
|
|
for (const promise of promises)
|
|
|
|
|
{
|
|
|
|
|
promiseQueue.push(promise);
|
|
|
|
|
}
|
|
|
|
|
const slotAvailable: Subject<void> = new Subject<void>();
|
|
|
|
|
const errors: Error[] = [];
|
|
|
|
|
const results: T[] = [];
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
function waitForAvailable(): Promise<void>
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
2020-12-03 13:55:02 +00:00
|
|
|
return new Promise<void>((resolve1) =>
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
|
|
|
|
const subs = slotAvailable.subscribe(() =>
|
|
|
|
|
{
|
|
|
|
|
subs.unsubscribe();
|
|
|
|
|
resolve1();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
function runPromise(promise: () => Promise<T>): void
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
|
|
|
|
concurrency--;
|
|
|
|
|
let timedOut = false;
|
|
|
|
|
let timeo: Timeout | undefined = undefined;
|
|
|
|
|
promise().then((result: T) =>
|
|
|
|
|
{
|
|
|
|
|
if (timedOut)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (timeo !== undefined)
|
|
|
|
|
{
|
|
|
|
|
clearTimeout(timeo);
|
|
|
|
|
}
|
|
|
|
|
results.push(result);
|
|
|
|
|
concurrency++;
|
|
|
|
|
slotAvailable.next();
|
|
|
|
|
}).catch((err) =>
|
|
|
|
|
{
|
|
|
|
|
if (timedOut)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (timeo !== undefined)
|
|
|
|
|
{
|
|
|
|
|
clearTimeout(timeo);
|
|
|
|
|
}
|
|
|
|
|
errors.push(err);
|
|
|
|
|
concurrency++;
|
|
|
|
|
slotAvailable.next();
|
|
|
|
|
});
|
2020-11-19 16:51:14 +00:00
|
|
|
if (timeout > 0)
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
2020-11-19 16:51:14 +00:00
|
|
|
timeo = setTimeout(() =>
|
|
|
|
|
{
|
|
|
|
|
timedOut = true;
|
|
|
|
|
errors.push(new Error('Promise timed out'));
|
|
|
|
|
concurrency++;
|
|
|
|
|
slotAvailable.next();
|
|
|
|
|
}, timeout);
|
|
|
|
|
}
|
2020-01-07 21:01:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (promiseQueue.length > 0)
|
|
|
|
|
{
|
|
|
|
|
if (concurrency < 1)
|
|
|
|
|
{
|
|
|
|
|
await waitForAvailable();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const thunk = promiseQueue.shift();
|
|
|
|
|
if (thunk !== undefined)
|
|
|
|
|
{
|
|
|
|
|
runPromise(thunk);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (concurrency < originalConcurrency)
|
|
|
|
|
{
|
|
|
|
|
await waitForAvailable();
|
|
|
|
|
}
|
2021-09-23 17:21:36 +01:00
|
|
|
resolve({ results: results, errors: errors });
|
2020-01-07 21:01:20 +00:00
|
|
|
});
|
|
|
|
|
}
|
2020-11-19 16:51:14 +00:00
|
|
|
|
|
|
|
|
static waitFor(timeout: number): Promise<void>
|
|
|
|
|
{
|
2020-12-03 13:55:02 +00:00
|
|
|
return new Promise<void>((resolve) =>
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
setTimeout(() =>
|
|
|
|
|
{
|
|
|
|
|
resolve();
|
|
|
|
|
}, timeout);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static getFromXMLJS(obj: any, param: string): any
|
|
|
|
|
{
|
|
|
|
|
if (obj[param] === undefined)
|
|
|
|
|
{
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
let retParam;
|
|
|
|
|
if (Array.isArray(obj[param]))
|
|
|
|
|
{
|
|
|
|
|
retParam = obj[param][0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
retParam = obj[param];
|
|
|
|
|
}
|
|
|
|
|
if (typeof retParam === 'string')
|
|
|
|
|
{
|
|
|
|
|
if (retParam.toLowerCase() === 'false')
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (retParam.toLowerCase() === 'true')
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
const numVar = parseInt(retParam, 10);
|
|
|
|
|
if (numVar >= Number.MIN_SAFE_INTEGER && numVar <= Number.MAX_SAFE_INTEGER && String(numVar) === retParam)
|
|
|
|
|
{
|
|
|
|
|
return numVar
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return retParam;
|
|
|
|
|
}
|
|
|
|
|
static inflate(buf: Buffer): Promise<Buffer>
|
|
|
|
|
{
|
|
|
|
|
return new Promise<Buffer>((resolve, reject) =>
|
|
|
|
|
{
|
|
|
|
|
zlib.inflate(buf, (error: (Error| null), result: Buffer) =>
|
|
|
|
|
{
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
reject(error)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
resolve(result);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
static deflate(buf: Buffer): Promise<Buffer>
|
|
|
|
|
{
|
|
|
|
|
return new Promise<Buffer>((resolve, reject) =>
|
|
|
|
|
{
|
2021-09-23 17:21:36 +01:00
|
|
|
zlib.deflate(buf, { level: 9 }, (error: (Error| null), result: Buffer) =>
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
reject(error)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
resolve(result);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
static waitOrTimeOut<T>(subject: Subject<T>, timeout?: number, callback?: (msg: T) => FilterResponse): Promise<T>
|
|
|
|
|
{
|
|
|
|
|
return new Promise<T>((resolve, reject) =>
|
|
|
|
|
{
|
|
|
|
|
let timer: Timeout | undefined = undefined;
|
|
|
|
|
let subs: Subscription | undefined = undefined;
|
|
|
|
|
subs = subject.subscribe((result: T) =>
|
|
|
|
|
{
|
|
|
|
|
if (callback !== undefined)
|
|
|
|
|
{
|
|
|
|
|
const accepted = callback(result);
|
|
|
|
|
if (accepted !== FilterResponse.Finish)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (timer !== undefined)
|
|
|
|
|
{
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
timer = undefined;
|
|
|
|
|
}
|
|
|
|
|
if (subs !== undefined)
|
|
|
|
|
{
|
|
|
|
|
subs.unsubscribe();
|
|
|
|
|
subs = undefined;
|
|
|
|
|
}
|
|
|
|
|
resolve(result);
|
|
|
|
|
});
|
|
|
|
|
if (timeout !== undefined)
|
|
|
|
|
{
|
|
|
|
|
timer = setTimeout(() =>
|
|
|
|
|
{
|
|
|
|
|
if (timer !== undefined)
|
|
|
|
|
{
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
timer = undefined;
|
|
|
|
|
}
|
|
|
|
|
if (subs !== undefined)
|
|
|
|
|
{
|
|
|
|
|
subs.unsubscribe();
|
|
|
|
|
subs = undefined;
|
|
|
|
|
}
|
|
|
|
|
reject(new Error('Timeout'));
|
|
|
|
|
}, timeout);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static parseLine(line: string): {
|
|
|
|
|
'key': string | null,
|
|
|
|
|
'value': string
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
line = line.trim().replace(/[\t]/gu, ' ').trim();
|
|
|
|
|
while (line.indexOf('\u0020\u0020') > 0)
|
|
|
|
|
{
|
|
|
|
|
line = line.replace(/\u0020\u0020/gu, '\u0020');
|
|
|
|
|
}
|
|
|
|
|
let key: string | null = null;
|
|
|
|
|
let value = '';
|
|
|
|
|
if (line.length > 2)
|
|
|
|
|
{
|
|
|
|
|
const sep = line.indexOf(' ');
|
|
|
|
|
if (sep > 0)
|
|
|
|
|
{
|
|
|
|
|
key = line.substr(0, sep);
|
|
|
|
|
value = line.substr(sep + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (line.length === 1)
|
|
|
|
|
{
|
|
|
|
|
key = line;
|
|
|
|
|
}
|
|
|
|
|
else if (line.length > 0)
|
|
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
'key': line,
|
|
|
|
|
'value': ''
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (key !== null)
|
|
|
|
|
{
|
|
|
|
|
key = key.trim();
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
'key': key,
|
|
|
|
|
'value': value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 13:55:02 +00:00
|
|
|
static sanitizePath(input: string): string
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
return input.replace(/[^a-z0-9]/gi, '').replace(/ /gi, '_');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static parseXML(input: string): Promise<any>
|
|
|
|
|
{
|
|
|
|
|
return new Promise<any>((resolve, reject) =>
|
|
|
|
|
{
|
2023-11-04 17:53:36 +00:00
|
|
|
xml2js.parseString(input, (err: Error | null, result: any) =>
|
2020-11-19 16:51:14 +00:00
|
|
|
{
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
reject(err);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
resolve(result);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-11-20 20:44:21 +00:00
|
|
|
|
|
|
|
|
public static getNotecardLine(lineObj: {
|
|
|
|
|
lines: string[],
|
|
|
|
|
lineNum: number,
|
|
|
|
|
pos: number
|
|
|
|
|
}): string
|
|
|
|
|
{
|
|
|
|
|
const line = lineObj.lines[lineObj.lineNum++];
|
|
|
|
|
lineObj.pos += Buffer.byteLength(line) + 1;
|
|
|
|
|
return line.replace(/\r/, '').trim().replace(/[\t ]+/g, ' ');
|
|
|
|
|
}
|
2023-11-21 13:57:06 +00:00
|
|
|
|
|
|
|
|
public static sleep(ms: number): Promise<void>
|
|
|
|
|
{
|
|
|
|
|
return new Promise((resolve) =>
|
|
|
|
|
{
|
|
|
|
|
setTimeout(() =>
|
|
|
|
|
{
|
|
|
|
|
resolve();
|
|
|
|
|
}, ms)
|
|
|
|
|
});
|
|
|
|
|
}
|
2018-10-16 16:46:58 +01:00
|
|
|
}
|