fix(signalr): use custom msgpack to encode/decode
This commit is contained in:
424
packages/msgpack_lazer_api/Cargo.lock
generated
Normal file
424
packages/msgpack_lazer_api/Cargo.lock
generated
Normal file
@@ -0,0 +1,424 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "msgpack-lazer-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"pyo3",
|
||||
"rmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"indoc",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"once_cell",
|
||||
"portable-atomic",
|
||||
"pyo3-build-config",
|
||||
"pyo3-ffi",
|
||||
"pyo3-macros",
|
||||
"unindent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"pyo3-build-config",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"num-traits",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
14
packages/msgpack_lazer_api/Cargo.toml
Normal file
14
packages/msgpack_lazer_api/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "msgpack-lazer-api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
name = "msgpack_lazer_api"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.41"
|
||||
pyo3 = { version = "0.25.0", features = ["extension-module", "chrono"] }
|
||||
rmp = "0.8.14"
|
||||
11
packages/msgpack_lazer_api/msgpack_lazer_api.pyi
Normal file
11
packages/msgpack_lazer_api/msgpack_lazer_api.pyi
Normal file
@@ -0,0 +1,11 @@
|
||||
from typing import Any
|
||||
|
||||
class APIMod:
|
||||
def __init__(self, acronym: str, settings: dict[str, Any]) -> None: ...
|
||||
@property
|
||||
def acronym(self) -> str: ...
|
||||
@property
|
||||
def settings(self) -> str: ...
|
||||
|
||||
def encode(obj: Any) -> bytes: ...
|
||||
def decode(data: bytes) -> Any: ...
|
||||
16
packages/msgpack_lazer_api/pyproject.toml
Normal file
16
packages/msgpack_lazer_api/pyproject.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[build-system]
|
||||
requires = ["maturin>=1.9,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "msgpack-lazer-api"
|
||||
requires-python = ">=3.12"
|
||||
classifiers = [
|
||||
"Programming Language :: Rust",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
[tool.maturin]
|
||||
features = ["pyo3/extension-module"]
|
||||
315
packages/msgpack_lazer_api/src/decode.rs
Normal file
315
packages/msgpack_lazer_api/src/decode.rs
Normal file
@@ -0,0 +1,315 @@
|
||||
use crate::APIMod;
|
||||
use chrono::{TimeZone, Utc};
|
||||
use pyo3::types::PyDict;
|
||||
use pyo3::{prelude::*, IntoPyObjectExt};
|
||||
use std::collections::HashMap;
|
||||
use std::io::Read;
|
||||
|
||||
pub fn read_object(
|
||||
py: Python<'_>,
|
||||
cursor: &mut std::io::Cursor<&[u8]>,
|
||||
api_mod: bool,
|
||||
) -> PyResult<PyObject> {
|
||||
match rmp::decode::read_marker(cursor) {
|
||||
Ok(marker) => match marker {
|
||||
rmp::Marker::Null => Ok(py.None()),
|
||||
rmp::Marker::FixPos(val) => Ok(val.into_pyobject(py)?.into_any().unbind()),
|
||||
rmp::Marker::FixNeg(val) => Ok(val.into_pyobject(py)?.into_any().unbind()),
|
||||
rmp::Marker::U8 => {
|
||||
let mut buf = [0u8; 1];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
Ok(buf[0].into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::U16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = u16::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::U32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = u32::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::U64 => {
|
||||
let mut buf = [0u8; 8];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = u64::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::I8 => {
|
||||
let mut buf = [0u8; 1];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = i8::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::I16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = i16::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::I32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = i32::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::I64 => {
|
||||
let mut buf = [0u8; 8];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = i64::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::Bin8 => {
|
||||
let mut buf = [0u8; 1];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = buf[0] as u32;
|
||||
let mut data = vec![0u8; len as usize];
|
||||
cursor.read_exact(&mut data).map_err(to_py_err)?;
|
||||
Ok(data.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::Bin16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u16::from_be_bytes(buf) as u32;
|
||||
let mut data = vec![0u8; len as usize];
|
||||
cursor.read_exact(&mut data).map_err(to_py_err)?;
|
||||
Ok(data.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::Bin32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u32::from_be_bytes(buf);
|
||||
let mut data = vec![0u8; len as usize];
|
||||
cursor.read_exact(&mut data).map_err(to_py_err)?;
|
||||
Ok(data.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::True => Ok(true.into_py_any(py)?),
|
||||
rmp::Marker::False => Ok(false.into_py_any(py)?),
|
||||
rmp::Marker::FixStr(len) => read_string(py, cursor, len as u32),
|
||||
rmp::Marker::Str8 => {
|
||||
let mut buf = [0u8; 1];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = buf[0] as u32;
|
||||
read_string(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::Str16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u16::from_be_bytes(buf) as u32;
|
||||
read_string(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::Str32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u32::from_be_bytes(buf);
|
||||
read_string(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::FixArray(len) => read_array(py, cursor, len as u32, api_mod),
|
||||
rmp::Marker::Array16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u16::from_be_bytes(buf) as u32;
|
||||
read_array(py, cursor, len, api_mod)
|
||||
}
|
||||
rmp::Marker::Array32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u32::from_be_bytes(buf);
|
||||
read_array(py, cursor, len, api_mod)
|
||||
}
|
||||
rmp::Marker::FixMap(len) => read_map(py, cursor, len as u32),
|
||||
rmp::Marker::Map16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u16::from_be_bytes(buf) as u32;
|
||||
read_map(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::Map32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u32::from_be_bytes(buf);
|
||||
read_map(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::F32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = f32::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::F64 => {
|
||||
let mut buf = [0u8; 8];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let val = f64::from_be_bytes(buf);
|
||||
Ok(val.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
rmp::Marker::FixExt1 => read_ext(py, cursor, 1),
|
||||
rmp::Marker::FixExt2 => read_ext(py, cursor, 2),
|
||||
rmp::Marker::FixExt4 => read_ext(py, cursor, 4),
|
||||
rmp::Marker::FixExt8 => read_ext(py, cursor, 8),
|
||||
rmp::Marker::FixExt16 => read_ext(py, cursor, 16),
|
||||
rmp::Marker::Ext8 => {
|
||||
let mut buf = [0u8; 1];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = buf[0] as u32;
|
||||
read_ext(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::Ext16 => {
|
||||
let mut buf = [0u8; 2];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u16::from_be_bytes(buf) as u32;
|
||||
read_ext(py, cursor, len)
|
||||
}
|
||||
rmp::Marker::Ext32 => {
|
||||
let mut buf = [0u8; 4];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let len = u32::from_be_bytes(buf);
|
||||
read_ext(py, cursor, len)
|
||||
}
|
||||
_ => Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
|
||||
"Unsupported MessagePack marker",
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(format!(
|
||||
"Failed to read marker: {:?}",
|
||||
e
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_string(
|
||||
py: Python<'_>,
|
||||
cursor: &mut std::io::Cursor<&[u8]>,
|
||||
len: u32,
|
||||
) -> PyResult<PyObject> {
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
cursor.read_exact(&mut buf).map_err(to_py_err)?;
|
||||
let s = String::from_utf8(buf)
|
||||
.map_err(|_| PyErr::new::<pyo3::exceptions::PyUnicodeDecodeError, _>("Invalid UTF-8"))?;
|
||||
Ok(s.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
|
||||
fn read_array(
|
||||
py: Python,
|
||||
cursor: &mut std::io::Cursor<&[u8]>,
|
||||
len: u32,
|
||||
api_mod: bool,
|
||||
) -> PyResult<PyObject> {
|
||||
let mut items = Vec::new();
|
||||
let array_len = if api_mod { len * 2 } else { len };
|
||||
let dict = PyDict::new(py);
|
||||
let mut i = 0;
|
||||
if len == 2 && !api_mod {
|
||||
// 姑且这样判断:列表长度为2,第一个元素为长度为2的字符串,api_mod 模式未启用(不存在嵌套 APIMod)
|
||||
let obj1 = read_object(py, cursor, false)?;
|
||||
if obj1.extract::<String>(py).map_or(false, |k| k.len() == 2) {
|
||||
let obj2 = read_object(py, cursor, true)?;
|
||||
return Ok(APIMod {
|
||||
acronym: obj1.extract::<String>(py)?,
|
||||
settings: obj2.extract::<HashMap<String, PyObject>>(py)?,
|
||||
}
|
||||
.into_pyobject(py)?
|
||||
.into_any()
|
||||
.unbind());
|
||||
} else {
|
||||
items.push(obj1);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
while i < array_len {
|
||||
if api_mod && i % 2 == 0 {
|
||||
let key = read_object(py, cursor, false)?;
|
||||
let value = read_object(py, cursor, false)?;
|
||||
dict.set_item(key, value)?;
|
||||
i += 2;
|
||||
} else {
|
||||
let item = read_object(py, cursor, api_mod)?;
|
||||
items.push(item);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if api_mod {
|
||||
return Ok(dict.into_pyobject(py)?.into_any().unbind());
|
||||
} else {
|
||||
Ok(items.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_map(py: Python, cursor: &mut std::io::Cursor<&[u8]>, len: u32) -> PyResult<PyObject> {
|
||||
let mut pairs = Vec::new();
|
||||
for _ in 0..len {
|
||||
let key = read_object(py, cursor, false)?;
|
||||
let value = read_object(py, cursor, false)?;
|
||||
pairs.push((key, value));
|
||||
}
|
||||
|
||||
let dict = PyDict::new(py);
|
||||
for (key, value) in pairs {
|
||||
dict.set_item(key, value)?;
|
||||
}
|
||||
return Ok(dict.into_pyobject(py)?.into_any().unbind());
|
||||
}
|
||||
|
||||
fn to_py_err(err: std::io::Error) -> PyErr {
|
||||
PyErr::new::<pyo3::exceptions::PyIOError, _>(format!("IO error: {}", err))
|
||||
}
|
||||
|
||||
fn read_ext(py: Python, cursor: &mut std::io::Cursor<&[u8]>, len: u32) -> PyResult<PyObject> {
|
||||
// Read the extension type
|
||||
let mut type_buf = [0u8; 1];
|
||||
cursor.read_exact(&mut type_buf).map_err(to_py_err)?;
|
||||
let ext_type = type_buf[0] as i8;
|
||||
|
||||
// Read the extension data
|
||||
let mut data = vec![0u8; len as usize];
|
||||
cursor.read_exact(&mut data).map_err(to_py_err)?;
|
||||
|
||||
// Handle timestamp extension (type = -1)
|
||||
if ext_type == -1 {
|
||||
read_timestamp(py, &data)
|
||||
} else {
|
||||
// For other extension types, return as bytes or handle as needed
|
||||
Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(format!(
|
||||
"Unsupported extension type: {}",
|
||||
ext_type
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_timestamp(py: Python, data: &[u8]) -> PyResult<PyObject> {
|
||||
let (secs, nsec) = match data.len() {
|
||||
4 => {
|
||||
// timestamp32: 4-byte big endian seconds
|
||||
let secs = u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as u64;
|
||||
(secs, 0u32)
|
||||
}
|
||||
8 => {
|
||||
// timestamp64: 8-byte packed => upper 34 bits nsec, lower 30 bits secs
|
||||
let packed = u64::from_be_bytes([
|
||||
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
|
||||
]);
|
||||
let nsec = (packed >> 34) as u32;
|
||||
let secs = packed & 0x3FFFFFFFF; // lower 34 bits
|
||||
(secs, nsec)
|
||||
}
|
||||
12 => {
|
||||
// timestamp96: 12 bytes = 4-byte nsec + 8-byte seconds signed
|
||||
let nsec = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
|
||||
let secs = i64::from_be_bytes([
|
||||
data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11],
|
||||
]) as u64;
|
||||
(secs, nsec)
|
||||
}
|
||||
_ => {
|
||||
return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(format!(
|
||||
"Invalid timestamp data length: {}",
|
||||
data.len()
|
||||
)));
|
||||
}
|
||||
};
|
||||
let time = Utc.timestamp_opt(secs as i64, nsec).single();
|
||||
Ok(time.into_pyobject(py)?.into_any().unbind())
|
||||
}
|
||||
132
packages/msgpack_lazer_api/src/encode.rs
Normal file
132
packages/msgpack_lazer_api/src/encode.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use crate::APIMod;
|
||||
use chrono::{DateTime, Utc};
|
||||
use pyo3::prelude::{PyAnyMethods, PyDictMethods, PyListMethods, PyStringMethods};
|
||||
use pyo3::types::{PyBool, PyBytes, PyDateTime, PyDict, PyFloat, PyInt, PyList, PyNone, PyString};
|
||||
use pyo3::{Bound, PyAny, PyRef, Python};
|
||||
use std::io::Write;
|
||||
|
||||
fn write_list(buf: &mut Vec<u8>, obj: &Bound<'_, PyList>) {
|
||||
rmp::encode::write_array_len(buf, obj.len() as u32).unwrap();
|
||||
for item in obj.iter() {
|
||||
write_object(buf, &item);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_string(buf: &mut Vec<u8>, obj: &Bound<'_, PyString>) {
|
||||
let s = obj.to_string_lossy();
|
||||
rmp::encode::write_str(buf, &s).unwrap();
|
||||
}
|
||||
|
||||
fn write_integer(buf: &mut Vec<u8>, obj: &Bound<'_, PyInt>) {
|
||||
if let Ok(val) = obj.extract::<i32>() {
|
||||
rmp::encode::write_i32(buf, val).unwrap();
|
||||
} else if let Ok(val) = obj.extract::<i64>() {
|
||||
rmp::encode::write_i64(buf, val).unwrap();
|
||||
} else {
|
||||
panic!("Unsupported integer type");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_float(buf: &mut Vec<u8>, obj: &Bound<'_, PyAny>) {
|
||||
if let Ok(val) = obj.extract::<f32>() {
|
||||
rmp::encode::write_f32(buf, val).unwrap();
|
||||
} else if let Ok(val) = obj.extract::<f64>() {
|
||||
rmp::encode::write_f64(buf, val).unwrap();
|
||||
} else {
|
||||
panic!("Unsupported float type");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_bool(buf: &mut Vec<u8>, obj: &Bound<'_, PyBool>) {
|
||||
if let Ok(b) = obj.extract::<bool>() {
|
||||
rmp::encode::write_bool(buf, b).unwrap();
|
||||
} else {
|
||||
panic!("Unsupported boolean type");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_bin(buf: &mut Vec<u8>, obj: &Bound<'_, PyBytes>) {
|
||||
if let Ok(bytes) = obj.extract::<Vec<u8>>() {
|
||||
rmp::encode::write_bin(buf, &bytes).unwrap();
|
||||
} else {
|
||||
panic!("Unsupported binary type");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_hashmap(buf: &mut Vec<u8>, obj: &Bound<'_, PyDict>) {
|
||||
rmp::encode::write_map_len(buf, obj.len() as u32).unwrap();
|
||||
for (key, value) in obj.iter() {
|
||||
write_object(buf, &key);
|
||||
write_object(buf, &value);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_nil(buf: &mut Vec<u8>){
|
||||
rmp::encode::write_nil(buf).unwrap();
|
||||
}
|
||||
|
||||
// https://github.com/ppy/osu/blob/3dced3/osu.Game/Online/API/ModSettingsDictionaryFormatter.cs
|
||||
fn write_api_mod(buf: &mut Vec<u8>, api_mod: PyRef<APIMod>) {
|
||||
rmp::encode::write_array_len(buf, 2).unwrap();
|
||||
rmp::encode::write_str(buf, &api_mod.acronym).unwrap();
|
||||
rmp::encode::write_array_len(buf, api_mod.settings.len() as u32).unwrap();
|
||||
for (k, v) in api_mod.settings.iter() {
|
||||
rmp::encode::write_str(buf, k).unwrap();
|
||||
Python::with_gil(|py| write_object(buf, &v.bind(py)));
|
||||
}
|
||||
}
|
||||
|
||||
fn write_datetime(buf: &mut Vec<u8>, obj: &Bound<'_, PyDateTime>) {
|
||||
if let Ok(dt) = obj.extract::<DateTime<Utc>>() {
|
||||
let secs = dt.timestamp();
|
||||
let nsec = dt.timestamp_subsec_nanos();
|
||||
write_timestamp(buf, secs, nsec);
|
||||
} else {
|
||||
panic!("Unsupported datetime type. Check your input, timezone is needed.");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_timestamp(wr: &mut Vec<u8>, secs: i64, nsec: u32) {
|
||||
let buf: Vec<u8> = if nsec == 0 && secs >= 0 && secs <= u32::MAX as i64 {
|
||||
// timestamp32: 4-byte big endian seconds
|
||||
secs.to_be_bytes()[4..].to_vec()
|
||||
} else if secs >= -(1 << 34) && secs < (1 << 34) {
|
||||
// timestamp64: 8-byte packed => upper 34 bits nsec, lower 34 bits secs
|
||||
let packed = ((nsec as u64) << 34) | (secs as u64 & ((1 << 34) - 1));
|
||||
packed.to_be_bytes().to_vec()
|
||||
} else {
|
||||
// timestamp96: 12 bytes = 4-byte nsec + 8-byte seconds signed
|
||||
let mut v = Vec::with_capacity(12);
|
||||
v.extend_from_slice(&nsec.to_be_bytes());
|
||||
v.extend_from_slice(&secs.to_be_bytes());
|
||||
v
|
||||
};
|
||||
rmp::encode::write_ext_meta(wr, buf.len() as u32, -1).unwrap();
|
||||
wr.write_all(&buf).unwrap();
|
||||
}
|
||||
|
||||
pub fn write_object(buf: &mut Vec<u8>, obj: &Bound<'_, PyAny>) {
|
||||
if let Ok(list) = obj.downcast::<PyList>() {
|
||||
write_list(buf, list);
|
||||
} else if let Ok(string) = obj.downcast::<PyString>() {
|
||||
write_string(buf, string);
|
||||
} else if let Ok(integer) = obj.downcast::<PyInt>() {
|
||||
write_integer(buf, integer);
|
||||
} else if let Ok(float) = obj.downcast::<PyFloat>() {
|
||||
write_float(buf, float);
|
||||
} else if let Ok(boolean) = obj.downcast::<PyBool>() {
|
||||
write_bool(buf, boolean);
|
||||
} else if let Ok(bytes) = obj.downcast::<PyBytes>() {
|
||||
write_bin(buf, bytes);
|
||||
} else if let Ok(dict) = obj.downcast::<PyDict>() {
|
||||
write_hashmap(buf, dict);
|
||||
} else if let Ok(_none) = obj.downcast::<PyNone>() {
|
||||
write_nil(buf);
|
||||
} else if let Ok(datetime) = obj.downcast::<PyDateTime>() {
|
||||
write_datetime(buf, datetime);
|
||||
} else if let Ok(api_mod) = obj.extract::<PyRef<APIMod>>() {
|
||||
write_api_mod(buf, api_mod);
|
||||
} else {
|
||||
panic!("Unsupported type");
|
||||
}
|
||||
}
|
||||
51
packages/msgpack_lazer_api/src/lib.rs
Normal file
51
packages/msgpack_lazer_api/src/lib.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
mod decode;
|
||||
mod encode;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[pyclass]
|
||||
struct APIMod {
|
||||
#[pyo3(get, set)]
|
||||
acronym: String,
|
||||
#[pyo3(get, set)]
|
||||
settings: HashMap<String, PyObject>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl APIMod {
|
||||
#[new]
|
||||
fn new(acronym: String, settings: HashMap<String, PyObject>) -> Self {
|
||||
APIMod { acronym, settings }
|
||||
}
|
||||
|
||||
fn __repr__(&self) -> String {
|
||||
format!(
|
||||
"APIMod(acronym='{}', settings={:?})",
|
||||
self.acronym, self.settings
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(name = "encode")]
|
||||
fn encode_py(obj: &Bound<'_, PyAny>) -> PyResult<Vec<u8>> {
|
||||
let mut buf = Vec::new();
|
||||
encode::write_object(&mut buf, obj);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(name = "decode")]
|
||||
fn decode_py(py: Python, data: &[u8]) -> PyResult<PyObject> {
|
||||
let mut cursor = std::io::Cursor::new(data);
|
||||
decode::read_object(py, &mut cursor, false)
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn msgpack_lazer_api(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(encode_py, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(decode_py, m)?)?;
|
||||
m.add_class::<APIMod>()?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user