2024-10-22 09:17:28 +08:00

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);
}