feat: remove superjson

This commit is contained in:
手瓜一十雪
2025-06-16 17:36:27 +08:00
parent ee4c9e95ad
commit 2be014a9f2
7 changed files with 712 additions and 9 deletions

View File

@@ -59,7 +59,6 @@
"vite": "^6.0.1",
"vite-plugin-cp": "^6.0.0",
"vite-tsconfig-paths": "^5.1.0",
"superjson": "^2.2.2",
"winston": "^3.17.0"
},
"dependencies": {

View File

View File

View File

@@ -11,7 +11,7 @@ import {
NodeIDependsAdapter,
NodeIDispatcherAdapter
} from "../../core/adapters";
import superjson from "superjson";
import { rpc_decode, rpc_encode } from "./serialize";
class RemoteServiceManager {
private services: Map<string, any> = new Map();
@@ -28,14 +28,14 @@ class RemoteServiceManager {
}
const serviceClient = createRemoteServiceClient(serviceName, async (serviceCommand, ...args) => {
const call_dto = superjson.stringify({ command: serviceCommand, params: args });
const call_data = superjson.parse<{ command: ServiceMethodCommand; params: any[] }>(call_dto);
const call_dto = rpc_encode({ command: serviceCommand, params: args });
const call_data = rpc_decode<{ command: ServiceMethodCommand; params: any[] }>(call_dto);
return handleServiceServerOnce(
call_data.command,
async (listenerCommand: string, ...args: any[]) => {
const listener_dto = superjson.stringify({ command: listenerCommand, params: args });
const listener_data = superjson.parse<{ command: string; params: any[] }>(listener_dto);
const listener_dto = rpc_encode({ command: listenerCommand, params: args });
const listener_data = rpc_decode<{ command: string; params: any[] }>(listener_dto);
serviceClient.receiverListener(listener_data.command, ...listener_data.params);
},
this.eventWrapper,

View File

@@ -0,0 +1,576 @@
#include <node_api.h>
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
// Base64 编码表
static const char *BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Base64 编码
std::string base64_encode(const unsigned char *data, size_t len)
{
if (!data || len == 0)
return "";
std::string result;
result.reserve((len + 2) / 3 * 4); // 预分配内存
for (size_t i = 0; i < len; i += 3)
{
uint32_t value = static_cast<uint32_t>(data[i]) << 16;
if (i + 1 < len)
value |= static_cast<uint32_t>(data[i + 1]) << 8;
if (i + 2 < len)
value |= static_cast<uint32_t>(data[i + 2]);
result += BASE64_CHARS[(value >> 18) & 0x3F];
result += BASE64_CHARS[(value >> 12) & 0x3F];
result += (i + 1 < len) ? BASE64_CHARS[(value >> 6) & 0x3F] : '=';
result += (i + 2 < len) ? BASE64_CHARS[value & 0x3F] : '=';
}
return result;
}
// Base64 解码
std::vector<uint8_t> base64_decode(const std::string &encoded)
{
if (encoded.empty())
return {};
auto get_base64_index = [](char c) -> int
{
if (c >= 'A' && c <= 'Z')
return c - 'A';
if (c >= 'a' && c <= 'z')
return c - 'a' + 26;
if (c >= '0' && c <= '9')
return c - '0' + 52;
if (c == '+')
return 62;
if (c == '/')
return 63;
return -1;
};
std::vector<uint8_t> result;
result.reserve(encoded.size() * 3 / 4);
for (size_t i = 0; i < encoded.size(); i += 4)
{
uint32_t value = 0;
int valid_chars = 0;
for (int j = 0; j < 4 && i + j < encoded.size(); j++)
{
char c = encoded[i + j];
if (c == '=')
break;
int index = get_base64_index(c);
if (index == -1)
continue;
value = (value << 6) | index;
valid_chars++;
}
if (valid_chars >= 2)
{
value <<= (4 - valid_chars) * 6;
result.push_back((value >> 16) & 0xFF);
if (valid_chars >= 3)
result.push_back((value >> 8) & 0xFF);
if (valid_chars >= 4)
result.push_back(value & 0xFF);
}
}
return result;
}
// 创建字符串值
napi_value create_string(napi_env env, const std::string &str)
{
napi_value result;
napi_status status = napi_create_string_utf8(env, str.c_str(), str.size(), &result);
if (status != napi_ok)
return nullptr;
return result;
}
// 创建带类型标识的对象
napi_value create_typed_object(napi_env env, const char *type_name)
{
napi_value obj, type_value;
if (napi_create_object(env, &obj) != napi_ok)
return nullptr;
if (napi_create_string_utf8(env, type_name, NAPI_AUTO_LENGTH, &type_value) != napi_ok)
return nullptr;
if (napi_set_named_property(env, obj, "$type", type_value) != napi_ok)
return nullptr;
return obj;
}
// 获取字符串值
std::string get_string_value(napi_env env, napi_value str_val)
{
size_t str_len;
if (napi_get_value_string_utf8(env, str_val, nullptr, 0, &str_len) != napi_ok)
return "";
std::string result(str_len, '\0');
if (napi_get_value_string_utf8(env, str_val, &result[0], str_len + 1, &str_len) != napi_ok)
return "";
return result;
}
// 类型检测函数
bool is_buffer(napi_env env, napi_value val)
{
bool result = false;
napi_is_buffer(env, val, &result);
return result;
}
bool is_array(napi_env env, napi_value val)
{
bool result = false;
napi_is_array(env, val, &result);
return result;
}
bool is_map(napi_env env, napi_value val)
{
napi_value global, map_constructor;
if (napi_get_global(env, &global) != napi_ok)
return false;
if (napi_get_named_property(env, global, "Map", &map_constructor) != napi_ok)
return false;
bool result = false;
napi_instanceof(env, val, map_constructor, &result);
return result;
}
// 前向声明
napi_value encode_value(napi_env env, napi_value value);
napi_value decode_value(napi_env env, napi_value obj);
// 编码 Map 类型
napi_value encode_map(napi_env env, napi_value map)
{
napi_value result = create_typed_object(env, "Map");
if (!result)
return nullptr;
// 获取 Map 的 entries
napi_value entries_method, iterator;
if (napi_get_named_property(env, map, "entries", &entries_method) != napi_ok)
return nullptr;
if (napi_call_function(env, map, entries_method, 0, nullptr, &iterator) != napi_ok)
return nullptr;
napi_value entries_array;
if (napi_create_array(env, &entries_array) != napi_ok)
return nullptr;
uint32_t index = 0;
napi_value next_method;
if (napi_get_named_property(env, iterator, "next", &next_method) != napi_ok)
return nullptr;
while (true)
{
napi_value next_result;
if (napi_call_function(env, iterator, next_method, 0, nullptr, &next_result) != napi_ok)
break;
napi_value done_val;
bool done = false;
if (napi_get_named_property(env, next_result, "done", &done_val) != napi_ok)
break;
if (napi_get_value_bool(env, done_val, &done) != napi_ok)
break;
if (done)
break;
napi_value entry_pair;
if (napi_get_named_property(env, next_result, "value", &entry_pair) != napi_ok)
break;
napi_value key, value;
if (napi_get_element(env, entry_pair, 0, &key) != napi_ok)
break;
if (napi_get_element(env, entry_pair, 1, &value) != napi_ok)
break;
napi_value encoded_key = encode_value(env, key);
napi_value encoded_value = encode_value(env, value);
if (!encoded_key || !encoded_value)
break;
napi_value encoded_pair;
if (napi_create_array_with_length(env, 2, &encoded_pair) != napi_ok)
break;
if (napi_set_element(env, encoded_pair, 0, encoded_key) != napi_ok)
break;
if (napi_set_element(env, encoded_pair, 1, encoded_value) != napi_ok)
break;
if (napi_set_element(env, entries_array, index++, encoded_pair) != napi_ok)
break;
}
napi_set_named_property(env, result, "$value", entries_array);
return result;
}
// 编码数组类型
napi_value encode_array(napi_env env, napi_value arr)
{
napi_value result = create_typed_object(env, "Array");
if (!result)
return nullptr;
uint32_t length;
if (napi_get_array_length(env, arr, &length) != napi_ok)
return nullptr;
napi_value encoded_array;
if (napi_create_array_with_length(env, length, &encoded_array) != napi_ok)
return nullptr;
for (uint32_t i = 0; i < length; i++)
{
napi_value element;
if (napi_get_element(env, arr, i, &element) != napi_ok)
continue;
napi_value encoded_element = encode_value(env, element);
if (encoded_element)
{
napi_set_element(env, encoded_array, i, encoded_element);
}
}
napi_set_named_property(env, result, "$value", encoded_array);
return result;
}
// 编码对象类型
napi_value encode_object(napi_env env, napi_value obj)
{
napi_value result = create_typed_object(env, "Object");
if (!result)
return nullptr;
napi_value prop_names;
if (napi_get_property_names(env, obj, &prop_names) != napi_ok)
return nullptr;
uint32_t prop_count;
if (napi_get_array_length(env, prop_names, &prop_count) != napi_ok)
return nullptr;
napi_value encoded_obj;
if (napi_create_object(env, &encoded_obj) != napi_ok)
return nullptr;
for (uint32_t i = 0; i < prop_count; i++)
{
napi_value prop_name;
if (napi_get_element(env, prop_names, i, &prop_name) != napi_ok)
continue;
std::string key = get_string_value(env, prop_name);
if (key.empty())
continue;
napi_value prop_value;
if (napi_get_named_property(env, obj, key.c_str(), &prop_value) != napi_ok)
continue;
napi_value encoded_value = encode_value(env, prop_value);
if (encoded_value)
{
napi_set_named_property(env, encoded_obj, key.c_str(), encoded_value);
}
}
napi_set_named_property(env, result, "$value", encoded_obj);
return result;
}
// 主编码函数
napi_value encode_value(napi_env env, napi_value value)
{
napi_valuetype type;
if (napi_typeof(env, value, &type) != napi_ok)
return nullptr;
// 检查 null
bool is_null_val = false;
if (napi_is_null(env, value, &is_null_val) == napi_ok && is_null_val)
{
return create_typed_object(env, "null");
}
// 检查 undefined
bool is_undefined_val = false;
if (napi_is_undefined(env, value, &is_undefined_val) == napi_ok && is_undefined_val)
{
return create_typed_object(env, "undefined");
}
switch (type)
{
case napi_number:
{
napi_value result = create_typed_object(env, "number");
if (result)
napi_set_named_property(env, result, "$value", value);
return result;
}
case napi_string:
{
napi_value result = create_typed_object(env, "string");
if (result)
napi_set_named_property(env, result, "$value", value);
return result;
}
case napi_boolean:
{
napi_value result = create_typed_object(env, "boolean");
if (result)
napi_set_named_property(env, result, "$value", value);
return result;
}
case napi_object:
{
if (is_buffer(env, value))
{
// 处理 Buffer
void *data;
size_t length;
if (napi_get_buffer_info(env, value, &data, &length) != napi_ok)
return nullptr;
std::string base64_str = base64_encode(static_cast<const unsigned char *>(data), length);
napi_value result = create_typed_object(env, "Buffer");
napi_value base64_val = create_string(env, base64_str);
if (result && base64_val)
{
napi_set_named_property(env, result, "$value", base64_val);
}
return result;
}
if (is_map(env, value))
{
return encode_map(env, value);
}
if (is_array(env, value))
{
return encode_array(env, value);
}
return encode_object(env, value);
}
default:
return nullptr;
}
}
// 主解码函数
napi_value decode_value(napi_env env, napi_value obj)
{
napi_valuetype type;
if (napi_typeof(env, obj, &type) != napi_ok || type != napi_object)
{
return nullptr;
}
// 获取类型标识
napi_value type_val;
bool has_type = false;
if (napi_has_named_property(env, obj, "$type", &has_type) != napi_ok || !has_type)
{
return nullptr;
}
if (napi_get_named_property(env, obj, "$type", &type_val) != napi_ok)
{
return nullptr;
}
std::string type_str = get_string_value(env, type_val);
if (type_str.empty())
return nullptr;
if (type_str == "null")
{
napi_value result;
napi_get_null(env, &result);
return result;
}
if (type_str == "undefined")
{
napi_value result;
napi_get_undefined(env, &result);
return result;
}
// 获取值
napi_value value_obj;
if (napi_get_named_property(env, obj, "$value", &value_obj) != napi_ok)
{
return nullptr;
}
if (type_str == "number" || type_str == "string" || type_str == "boolean")
{
return value_obj;
}
if (type_str == "Buffer")
{
std::string base64_str = get_string_value(env, value_obj);
std::vector<uint8_t> data = base64_decode(base64_str);
napi_value buffer;
if (napi_create_buffer_copy(env, data.size(), data.data(), nullptr, &buffer) == napi_ok)
{
return buffer;
}
return nullptr;
}
if (type_str == "Array")
{
uint32_t length;
if (napi_get_array_length(env, value_obj, &length) != napi_ok)
return nullptr;
napi_value result;
if (napi_create_array_with_length(env, length, &result) != napi_ok)
return nullptr;
for (uint32_t i = 0; i < length; i++)
{
napi_value element;
if (napi_get_element(env, value_obj, i, &element) == napi_ok)
{
napi_value decoded_element = decode_value(env, element);
if (decoded_element)
{
napi_set_element(env, result, i, decoded_element);
}
}
}
return result;
}
if (type_str == "Object")
{
napi_value prop_names;
if (napi_get_property_names(env, value_obj, &prop_names) != napi_ok)
return nullptr;
uint32_t prop_count;
if (napi_get_array_length(env, prop_names, &prop_count) != napi_ok)
return nullptr;
napi_value result;
if (napi_create_object(env, &result) != napi_ok)
return nullptr;
for (uint32_t i = 0; i < prop_count; i++)
{
napi_value prop_name;
if (napi_get_element(env, prop_names, i, &prop_name) != napi_ok)
continue;
std::string key = get_string_value(env, prop_name);
if (key.empty())
continue;
napi_value prop_value;
if (napi_get_named_property(env, value_obj, key.c_str(), &prop_value) != napi_ok)
continue;
napi_value decoded_value = decode_value(env, prop_value);
if (decoded_value)
{
napi_set_named_property(env, result, key.c_str(), decoded_value);
}
}
return result;
}
if (type_str == "Map")
{
napi_value global, map_constructor;
if (napi_get_global(env, &global) != napi_ok)
return nullptr;
if (napi_get_named_property(env, global, "Map", &map_constructor) != napi_ok)
return nullptr;
napi_value map_instance;
if (napi_new_instance(env, map_constructor, 0, nullptr, &map_instance) != napi_ok)
return nullptr;
uint32_t length;
if (napi_get_array_length(env, value_obj, &length) != napi_ok)
return map_instance;
napi_value set_method;
if (napi_get_named_property(env, map_instance, "set", &set_method) != napi_ok)
return map_instance;
for (uint32_t i = 0; i < length; i++)
{
napi_value pair;
if (napi_get_element(env, value_obj, i, &pair) != napi_ok)
continue;
napi_value key, value;
if (napi_get_element(env, pair, 0, &key) != napi_ok)
continue;
if (napi_get_element(env, pair, 1, &value) != napi_ok)
continue;
napi_value decoded_key = decode_value(env, key);
napi_value decoded_value = decode_value(env, value);
if (decoded_key && decoded_value)
{
napi_value args[2] = {decoded_key, decoded_value};
napi_call_function(env, map_instance, set_method, 2, args, nullptr);
}
}
return map_instance;
}
return nullptr;
}
// 导出函数
napi_value Encode(napi_env env, napi_value value)
{
return encode_value(env, value);
}
napi_value Decode(napi_env env, napi_value obj)
{
return decode_value(env, obj);
}

View File

@@ -0,0 +1,131 @@
interface EncodedValue {
$type: string;
$value?: unknown;
}
interface EncodedNull {
$type: "null";
}
interface EncodedUndefined {
$type: "undefined";
}
interface EncodedPrimitive {
$type: "number" | "string" | "boolean";
$value: number | string | boolean;
}
interface EncodedBuffer {
$type: "Buffer";
$value: string;
}
interface EncodedMap {
$type: "Map";
$value: [EncodedValue, EncodedValue][];
}
interface EncodedArray {
$type: "Array";
$value: EncodedValue[];
}
interface EncodedObject {
$type: "Object";
$value: { [key: string]: EncodedValue };
}
type SerializedValue = EncodedNull | EncodedUndefined | EncodedPrimitive | EncodedBuffer | EncodedMap | EncodedArray | EncodedObject;
function rpc_encode<T>(value: T): SerializedValue {
if (value === null) return { $type: "null" };
if (value === undefined) return { $type: "undefined" };
if (typeof value === "number") return { $type: "number", $value: value };
if (typeof value === "string") return { $type: "string", $value: value };
if (typeof value === "boolean") return { $type: "boolean", $value: value };
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
// Buffer和Uint8Array都转成base64字符串
let base64: string = Buffer.from(value).toString("base64");
return { $type: "Buffer", $value: base64 };
}
if (value instanceof Map) {
let arr: [SerializedValue, SerializedValue][] = [];
for (let [k, v] of value.entries()) {
arr.push([rpc_encode(k), rpc_encode(v)]);
}
return { $type: "Map", $value: arr };
}
if (Array.isArray(value) || (typeof value === "object" && value !== null && typeof (value as unknown as ArrayLike<unknown>).length === "number")) {
// ArrayLike也认为是Array
let arr: SerializedValue[] = [];
const arrayLike = value as unknown as ArrayLike<unknown>;
for (let i = 0; i < arrayLike.length; i++) {
arr.push(rpc_encode(arrayLike[i]));
}
return { $type: "Array", $value: arr };
}
if (typeof value === "object" && value !== null) {
let obj: { [key: string]: SerializedValue } = {};
for (let k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
obj[k] = rpc_encode((value as Record<string, unknown>)[k]);
}
}
return { $type: "Object", $value: obj };
}
throw new Error("Unsupported type");
}
function rpc_decode<T = unknown>(obj: EncodedValue): T {
if (obj == null || typeof obj !== "object" || !("$type" in obj)) {
throw new Error("Invalid encoded object");
}
switch (obj.$type) {
case "null": return null as T;
case "undefined": return undefined as T;
case "number": return (obj as EncodedPrimitive).$value as T;
case "string": return (obj as EncodedPrimitive).$value as T;
case "boolean": return (obj as EncodedPrimitive).$value as T;
case "Buffer":
return Buffer.from((obj as EncodedBuffer).$value, "base64") as T;
case "Map":
{
let map = new Map();
for (let [k, v] of (obj as EncodedMap).$value) {
map.set(rpc_decode(k), rpc_decode(v));
}
return map as T;
}
case "Array":
{
let arr: unknown[] = [];
for (let item of (obj as EncodedArray).$value) {
arr.push(rpc_decode(item));
}
return arr as T;
}
case "Object":
{
let out: Record<string, unknown> = {};
for (let k in (obj as EncodedObject).$value) {
const value = (obj as EncodedObject).$value[k];
if (value !== undefined) {
out[k] = rpc_decode(value);
}
}
return out as T;
}
default:
throw new Error("Unknown $type: " + obj.$type);
}
}
export { rpc_encode, rpc_decode };
export type { SerializedValue };

View File

@@ -92,9 +92,6 @@ export function createRemoteServiceClient<T extends keyof ServiceNamingMapping>(
});
const receiverListener = function (command: string, ...args: any[]) {
if (command.indexOf('onRecvMsg') !== - 1 || command.indexOf('onRecvSysMsg') !== -1) {
console.log(`Received command: ${command}, with args: ${JSON.stringify(args)}`);
}
return clientCallback.get(command)?.(...args);
};
return { receiverListener: receiverListener, object: object as ServiceNamingMapping[T] };