373 lines
12 KiB
JavaScript
373 lines
12 KiB
JavaScript
|
import moduleHelper from './module-helper';
|
||
|
import { ResType } from './resType';
|
||
|
import { ResTypeOther } from './resTypeOther';
|
||
|
Object.assign(ResType, ResTypeOther);
|
||
|
function realUid(length = 20, char = true) {
|
||
|
const soup = `${char ? '' : '!#%()*+,-./:;=?@[]^_`{|}~'}ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`;
|
||
|
const soupLength = soup.length;
|
||
|
const id = [];
|
||
|
for (let i = 0; i < length; i++) {
|
||
|
id[i] = soup.charAt(Math.random() * soupLength);
|
||
|
}
|
||
|
return id.join('');
|
||
|
}
|
||
|
const identifierCache = [];
|
||
|
const clearIdTicker = {};
|
||
|
const tempCacheObj = {};
|
||
|
const typeMap = {
|
||
|
array: [],
|
||
|
arrayBuffer: [],
|
||
|
string: '',
|
||
|
number: 0,
|
||
|
bool: false,
|
||
|
object: {},
|
||
|
};
|
||
|
const interfaceTypeMap = {
|
||
|
array: 'object',
|
||
|
arrayBuffer: 'object',
|
||
|
string: 'string',
|
||
|
number: 'number',
|
||
|
bool: 'boolean',
|
||
|
object: 'object',
|
||
|
};
|
||
|
export const uid = () => realUid(20, true);
|
||
|
export function formatIdentifier(identifier, eventType, changed) {
|
||
|
if (changed && clearIdTicker[identifier]) {
|
||
|
clearTimeout(clearIdTicker[identifier]);
|
||
|
delete clearIdTicker[identifier];
|
||
|
}
|
||
|
let id = identifierCache.indexOf(identifier);
|
||
|
if (id <= -1) {
|
||
|
for (let key = 0; key < identifierCache.length; key++) {
|
||
|
if (identifierCache[key] === null) {
|
||
|
identifierCache[key] = identifier;
|
||
|
id = key;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (id <= -1) {
|
||
|
identifierCache.push(identifier);
|
||
|
id = identifierCache.length - 1;
|
||
|
}
|
||
|
if (changed && (eventType === 'touchend' || eventType === 'touchcancel')) {
|
||
|
clearIdTicker[identifier] = setTimeout(() => {
|
||
|
identifierCache[id] = null;
|
||
|
delete clearIdTicker[identifier];
|
||
|
}, 50);
|
||
|
}
|
||
|
return id;
|
||
|
}
|
||
|
export function formatTouchEvent(v, type, changed) {
|
||
|
return {
|
||
|
clientX: v.clientX * window.devicePixelRatio,
|
||
|
clientY: (window.innerHeight - v.clientY) * window.devicePixelRatio,
|
||
|
force: v.force,
|
||
|
identifier: formatIdentifier(v.identifier, type, changed),
|
||
|
pageX: v.pageX * window.devicePixelRatio,
|
||
|
pageY: (window.innerHeight - v.pageY) * window.devicePixelRatio,
|
||
|
};
|
||
|
}
|
||
|
export function formatResponse(type, data, id) {
|
||
|
if (!data) {
|
||
|
data = {};
|
||
|
}
|
||
|
if (typeof data !== 'object') {
|
||
|
return {};
|
||
|
}
|
||
|
const conf = ResType[type];
|
||
|
if (!conf) {
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
Object.keys(conf).forEach((key) => {
|
||
|
if (data[key] === null || typeof data[key] === 'undefined') {
|
||
|
if (typeof typeMap[conf[key]] === 'undefined') {
|
||
|
if (conf[key].indexOf('[]') > -1) {
|
||
|
data[key] = [];
|
||
|
}
|
||
|
else {
|
||
|
data[key] = {};
|
||
|
if (ResType[conf[key]]) {
|
||
|
formatResponse(conf[key], data[key]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
data[key] = typeMap[conf[key]];
|
||
|
}
|
||
|
}
|
||
|
else if (conf[key] === 'long') {
|
||
|
data[key] = parseInt(data[key], 10);
|
||
|
}
|
||
|
else if (conf[key] === 'number' && typeof data[key] === 'string') {
|
||
|
data[key] = Number(data[key]);
|
||
|
}
|
||
|
else if (conf[key] === 'string' && typeof data[key] === 'number') {
|
||
|
data[key] = `${data[key]}`;
|
||
|
}
|
||
|
else if (conf[key] === 'bool' && (typeof data[key] === 'number' || typeof data[key] === 'string')) {
|
||
|
data[key] = !!data[key];
|
||
|
}
|
||
|
else if (conf[key] === 'arrayBuffer') {
|
||
|
if (id) {
|
||
|
|
||
|
cacheArrayBuffer(id, data[key]);
|
||
|
data.arrayBufferLength = data[key].byteLength;
|
||
|
data[key] = [];
|
||
|
}
|
||
|
else if (data[key] instanceof ArrayBuffer) {
|
||
|
data[key] = new Uint8Array(data[key]);
|
||
|
data[key] = Array.from(data[key]);
|
||
|
}
|
||
|
else {
|
||
|
data[key] = [];
|
||
|
}
|
||
|
}
|
||
|
else if (typeof data[key] === 'object' && conf[key] === 'object') {
|
||
|
Object.keys(data[key]).forEach((v) => {
|
||
|
if (typeof data[key][v] === 'object') {
|
||
|
data[key][v] = JSON.stringify(data[key][v]);
|
||
|
}
|
||
|
else {
|
||
|
data[key][v] += '';
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else if (typeof data[key] === 'object' && conf[key]) {
|
||
|
|
||
|
const array = conf[key].match(/(.+)\[\]/);
|
||
|
if (array) {
|
||
|
for (const itemKey of Object.keys(data[key])) {
|
||
|
if (array[1] === 'string') {
|
||
|
data[key][itemKey] = `${data[key][itemKey]}`;
|
||
|
}
|
||
|
else if (array[1] === 'number') {
|
||
|
data[key][itemKey] = Number(data[key][itemKey]);
|
||
|
}
|
||
|
else {
|
||
|
formatResponse(array[1], data[key][itemKey]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
formatResponse(conf[key], data[key]);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (conf.anyKeyWord) {
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
Object.keys(data).forEach((key) => {
|
||
|
if (typeof conf[key] === 'undefined') {
|
||
|
delete data[key];
|
||
|
}
|
||
|
else {
|
||
|
const getType = interfaceTypeMap[conf[key]];
|
||
|
if (getType && getType !== typeof data[key]) {
|
||
|
data[key] = typeMap[conf[key]];
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return data;
|
||
|
}
|
||
|
export function formatJsonStr(str, type) {
|
||
|
if (!str) {
|
||
|
return {};
|
||
|
}
|
||
|
if (type === 'string|arrayBuffer') {
|
||
|
return convertBase64ToData(str);
|
||
|
}
|
||
|
try {
|
||
|
const data = JSON.parse(str);
|
||
|
Object.keys(data).forEach((v) => {
|
||
|
if (data[v] === null) {
|
||
|
delete data[v];
|
||
|
}
|
||
|
});
|
||
|
if (type) {
|
||
|
const conf = ResType[type];
|
||
|
if (!conf) {
|
||
|
return data;
|
||
|
}
|
||
|
Object.keys(conf).forEach((key) => {
|
||
|
if (data[key]) {
|
||
|
if (conf[key] === 'arrayBuffer') {
|
||
|
data[key] = new Uint8Array(data[key]).buffer;
|
||
|
}
|
||
|
else if (conf[key] === 'string|arrayBuffer') {
|
||
|
data[key] = convertBase64ToData(data[key]);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return data;
|
||
|
}
|
||
|
catch (e) {
|
||
|
return str;
|
||
|
}
|
||
|
}
|
||
|
function isBase64(str) {
|
||
|
const base64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
||
|
return base64Pattern.test(str);
|
||
|
}
|
||
|
function base64ToArrayBuffer(base64) {
|
||
|
const binaryString = atob(base64);
|
||
|
const len = binaryString.length;
|
||
|
const bytes = new Uint8Array(len);
|
||
|
for (let i = 0; i < len; i++) {
|
||
|
bytes[i] = binaryString.charCodeAt(i);
|
||
|
}
|
||
|
return bytes.buffer;
|
||
|
}
|
||
|
function convertBase64ToData(input) {
|
||
|
if (isBase64(input)) {
|
||
|
return base64ToArrayBuffer(input);
|
||
|
}
|
||
|
return input;
|
||
|
}
|
||
|
export function cacheArrayBuffer(callbackId, data) {
|
||
|
if (!callbackId || !data) {
|
||
|
return;
|
||
|
}
|
||
|
tempCacheObj[callbackId] = data;
|
||
|
}
|
||
|
export function setArrayBuffer(buffer, offset, callbackId) {
|
||
|
buffer.set(new Uint8Array(tempCacheObj[callbackId]), offset);
|
||
|
delete tempCacheObj[callbackId];
|
||
|
}
|
||
|
export function getListObject(list, name) {
|
||
|
return (id) => {
|
||
|
if (!list) {
|
||
|
list = {};
|
||
|
}
|
||
|
const obj = list[id];
|
||
|
if (!obj) {
|
||
|
console.error(`${name} 不存在:`, id);
|
||
|
}
|
||
|
return obj;
|
||
|
};
|
||
|
}
|
||
|
export function onEventCallback(list, eventName, id, callbackId) {
|
||
|
if (!list[id]) {
|
||
|
list[id] = [];
|
||
|
}
|
||
|
const callback = (res) => {
|
||
|
const resStr = JSON.stringify({
|
||
|
callbackId: callbackId || id,
|
||
|
res: JSON.stringify(res),
|
||
|
});
|
||
|
moduleHelper.send(eventName, resStr);
|
||
|
};
|
||
|
list[id].push(callback);
|
||
|
return callback;
|
||
|
}
|
||
|
export function offEventCallback(list, callback, id) {
|
||
|
if (!list || !list[id]) {
|
||
|
return;
|
||
|
}
|
||
|
list[id].forEach(callback);
|
||
|
delete list[id];
|
||
|
}
|
||
|
function allocateAndSet(byteArray) {
|
||
|
const ptr = GameGlobal.Module._malloc(byteArray.length);
|
||
|
GameGlobal.Module.HEAPU8.set(byteArray, ptr);
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
function convertNumberToPointer(num, ArrayType = Float64Array) {
|
||
|
const byteArray = numberToUint8Array(num, ArrayType);
|
||
|
return allocateAndSet(byteArray);
|
||
|
}
|
||
|
function convertArrayBufferToPointer(arrayBuffer) {
|
||
|
const byteArray = new Uint8Array(arrayBuffer);
|
||
|
return allocateAndSet(byteArray);
|
||
|
}
|
||
|
function convertStringToPointer(str) {
|
||
|
const byteArray = GameGlobal.Module.lengthBytesUTF8(str) + 1;
|
||
|
const ptr = GameGlobal.Module._malloc(byteArray);
|
||
|
GameGlobal.Module.stringToUTF8(str, ptr, byteArray);
|
||
|
return ptr;
|
||
|
}
|
||
|
export function convertDataToPointer(data) {
|
||
|
if (typeof data === 'number') {
|
||
|
return convertNumberToPointer(data);
|
||
|
}
|
||
|
if (typeof data === 'string') {
|
||
|
return convertStringToPointer(data);
|
||
|
}
|
||
|
if (data instanceof ArrayBuffer || typeof data === 'object') {
|
||
|
return convertArrayBufferToPointer(data);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
function numberToUint8Array(num, ArrayType = Float64Array) {
|
||
|
return new Uint8Array(new ArrayType([num]).buffer);
|
||
|
}
|
||
|
function stringToUint8ArrayWithLength(str) {
|
||
|
const strPtr = convertStringToPointer(str);
|
||
|
const strBytesLength = GameGlobal.Module.lengthBytesUTF8(str);
|
||
|
const strBytes = new Uint8Array(GameGlobal.Module.HEAPU8.buffer, strPtr, strBytesLength);
|
||
|
const lengthBytes = new Uint8Array(4);
|
||
|
new DataView(lengthBytes.buffer).setUint32(0, strBytes.length, true);
|
||
|
const result = new Uint8Array(4 + strBytes.length);
|
||
|
result.set(lengthBytes);
|
||
|
result.set(strBytes, 4);
|
||
|
GameGlobal.Module._free(strPtr);
|
||
|
return result;
|
||
|
}
|
||
|
function createUint8ArrayFromByteArrays(byteArrays) {
|
||
|
const totalLength = byteArrays.reduce((sum, byteArray) => sum + byteArray.length, 0);
|
||
|
const result = new Uint8Array(totalLength);
|
||
|
let offset = 0;
|
||
|
byteArrays.forEach((byteArray) => {
|
||
|
result.set(byteArray, offset);
|
||
|
offset += byteArray.length;
|
||
|
});
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function touchToUint8Array(touch) {
|
||
|
return createUint8ArrayFromByteArrays([
|
||
|
numberToUint8Array(touch.clientX, Float32Array),
|
||
|
numberToUint8Array(touch.clientY, Float32Array),
|
||
|
numberToUint8Array(touch.force),
|
||
|
numberToUint8Array(touch.identifier, Uint32Array),
|
||
|
numberToUint8Array(touch.pageX, Float32Array),
|
||
|
numberToUint8Array(touch.pageY, Float32Array),
|
||
|
]);
|
||
|
}
|
||
|
function touchesToUint8Array(touches) {
|
||
|
return createUint8ArrayFromByteArrays(touches.map(touchToUint8Array));
|
||
|
}
|
||
|
function onTouchStartListenerResultToUint8Array(result) {
|
||
|
return createUint8ArrayFromByteArrays([
|
||
|
touchesToUint8Array(result.touches),
|
||
|
touchesToUint8Array(result.changedTouches),
|
||
|
numberToUint8Array(result.timeStamp, Uint32Array),
|
||
|
]);
|
||
|
}
|
||
|
export function convertOnTouchStartListenerResultToPointer(result) {
|
||
|
return allocateAndSet(onTouchStartListenerResultToUint8Array(result));
|
||
|
}
|
||
|
|
||
|
function infoToUint8Array(info) {
|
||
|
return createUint8ArrayFromByteArrays([
|
||
|
stringToUint8ArrayWithLength(info.address),
|
||
|
stringToUint8ArrayWithLength(info.family),
|
||
|
numberToUint8Array(info.port, Uint32Array)
|
||
|
]);
|
||
|
}
|
||
|
export function convertInfoToPointer(info) {
|
||
|
return allocateAndSet(infoToUint8Array(info));
|
||
|
}
|
||
|
export function stringifyRes(obj) {
|
||
|
if (!obj) {
|
||
|
return '{}';
|
||
|
}
|
||
|
return JSON.stringify(obj);
|
||
|
}
|