titanpl-sdk 2.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/app/t.native.d.ts +1983 -0
- package/templates/app/t.native.js +39 -0
- package/templates/server/Cargo.toml +20 -2
- package/templates/server/src/action_management.rs +8 -10
- package/templates/server/src/errors.rs +3 -1
- package/templates/server/src/extensions/builtin.rs +928 -877
- package/templates/server/src/extensions/external.rs +14 -80
- package/templates/server/src/extensions/mod.rs +580 -448
- package/templates/server/src/extensions/titan_core.js +213 -186
- package/templates/server/src/fast_path.rs +719 -0
- package/templates/server/src/main.rs +370 -169
- package/templates/server/src/runtime.rs +284 -245
- package/templates/server/src/utils.rs +2 -2
- package/templates/app/titan.d.ts +0 -87
- package/templates/index.d.ts +0 -249
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
//! External native extension loading and FFI.
|
|
2
|
+
//!
|
|
3
|
+
//! Supports loading `.dll` / `.so` extensions defined in `titan.json` files.
|
|
4
|
+
|
|
1
5
|
use v8;
|
|
2
6
|
use std::path::PathBuf;
|
|
3
7
|
use std::collections::HashMap;
|
|
@@ -16,19 +20,15 @@ pub struct Registry {
|
|
|
16
20
|
pub _libs: Vec<Library>,
|
|
17
21
|
pub modules: Vec<ModuleDef>,
|
|
18
22
|
pub natives: Vec<NativeFnEntry>,
|
|
19
|
-
pub v8_natives: Vec<usize>,
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
|
|
23
25
|
#[derive(Clone)]
|
|
24
26
|
pub struct ModuleDef {
|
|
25
27
|
pub name: String,
|
|
26
28
|
pub js: String,
|
|
27
29
|
pub native_indices: HashMap<String, usize>,
|
|
28
|
-
pub v8_native_indices: HashMap<String, usize>,
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
#[derive(Clone, Debug, PartialEq)]
|
|
33
33
|
pub enum ParamType {
|
|
34
34
|
String, F64, Bool, Json, Buffer,
|
|
@@ -60,18 +60,9 @@ struct TitanConfig {
|
|
|
60
60
|
#[derive(serde::Deserialize)]
|
|
61
61
|
struct TitanNativeConfig {
|
|
62
62
|
path: String,
|
|
63
|
-
#[serde(default)]
|
|
64
63
|
functions: HashMap<String, TitanNativeFunc>,
|
|
65
|
-
#[serde(default)]
|
|
66
|
-
v8_functions: HashMap<String, TitanV8Func>,
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
#[derive(serde::Deserialize)]
|
|
70
|
-
struct TitanV8Func {
|
|
71
|
-
symbol: String,
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
|
|
75
66
|
#[derive(serde::Deserialize)]
|
|
76
67
|
struct TitanNativeFunc {
|
|
77
68
|
symbol: String,
|
|
@@ -108,8 +99,6 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
108
99
|
let mut modules = Vec::new();
|
|
109
100
|
let mut libs = Vec::new();
|
|
110
101
|
let mut all_natives = Vec::new();
|
|
111
|
-
let mut all_v8_natives = Vec::new();
|
|
112
|
-
|
|
113
102
|
|
|
114
103
|
let mut node_modules = root.join("node_modules");
|
|
115
104
|
if !node_modules.exists() {
|
|
@@ -120,8 +109,7 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
120
109
|
}
|
|
121
110
|
|
|
122
111
|
// Generic scanner helper
|
|
123
|
-
let scan_dir = |path: PathBuf, modules: &mut Vec<ModuleDef>, libs: &mut Vec<Library>, all_natives: &mut Vec<NativeFnEntry
|
|
124
|
-
|
|
112
|
+
let scan_dir = |path: PathBuf, modules: &mut Vec<ModuleDef>, libs: &mut Vec<Library>, all_natives: &mut Vec<NativeFnEntry>| {
|
|
125
113
|
if !path.exists() { return; }
|
|
126
114
|
for entry in WalkDir::new(&path).follow_links(true).min_depth(1).max_depth(4) {
|
|
127
115
|
let entry = match entry { Ok(e) => e, Err(_) => continue };
|
|
@@ -133,9 +121,7 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
133
121
|
Err(_) => continue,
|
|
134
122
|
};
|
|
135
123
|
let mut mod_natives_map = HashMap::new();
|
|
136
|
-
let mut mod_v8_natives_map = HashMap::new();
|
|
137
124
|
if let Some(native_conf) = config.native {
|
|
138
|
-
|
|
139
125
|
let lib_path = dir.join(&native_conf.path);
|
|
140
126
|
unsafe {
|
|
141
127
|
// Try loading library
|
|
@@ -144,28 +130,17 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
144
130
|
// But usually absolute path from `dir` works.
|
|
145
131
|
match lib_load {
|
|
146
132
|
Ok(lib) => {
|
|
147
|
-
for (fn_name, fn_conf) in
|
|
133
|
+
for (fn_name, fn_conf) in native_conf.functions {
|
|
148
134
|
let params = fn_conf.parameters.iter().map(|p| parse_type(&p.to_lowercase())).collect();
|
|
149
135
|
let ret = parse_return(&fn_conf.result.to_lowercase());
|
|
150
136
|
if let Ok(symbol) = lib.get::<*const ()>(fn_conf.symbol.as_bytes()) {
|
|
151
137
|
let idx = all_natives.len();
|
|
152
138
|
all_natives.push(NativeFnEntry { symbol_ptr: *symbol as usize, sig: Signature { params, ret } });
|
|
153
|
-
mod_natives_map.insert(fn_name
|
|
139
|
+
mod_natives_map.insert(fn_name, idx);
|
|
154
140
|
} else {
|
|
155
141
|
println!("{} {} {} -> {}", blue("[Titan]"), red("Symbol not found:"), fn_conf.symbol, config.name);
|
|
156
142
|
}
|
|
157
143
|
}
|
|
158
|
-
|
|
159
|
-
for (fn_name, fn_conf) in &native_conf.v8_functions {
|
|
160
|
-
if let Ok(symbol) = lib.get::<*const ()>(fn_conf.symbol.as_bytes()) {
|
|
161
|
-
let idx = all_v8_natives.len();
|
|
162
|
-
all_v8_natives.push(*symbol as usize);
|
|
163
|
-
mod_v8_natives_map.insert(fn_name.clone(), idx);
|
|
164
|
-
} else {
|
|
165
|
-
println!("{} {} {} -> {}", blue("[Titan]"), red("V8 Symbol not found:"), fn_conf.symbol, config.name);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
144
|
libs.push(lib);
|
|
170
145
|
},
|
|
171
146
|
Err(e) => {
|
|
@@ -175,13 +150,7 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
175
150
|
}
|
|
176
151
|
}
|
|
177
152
|
let js_path = dir.join(&config.main);
|
|
178
|
-
modules.push(ModuleDef {
|
|
179
|
-
name: config.name.clone(),
|
|
180
|
-
js: fs::read_to_string(js_path).unwrap_or_default(),
|
|
181
|
-
native_indices: mod_natives_map,
|
|
182
|
-
v8_native_indices: mod_v8_natives_map
|
|
183
|
-
});
|
|
184
|
-
|
|
153
|
+
modules.push(ModuleDef { name: config.name.clone(), js: fs::read_to_string(js_path).unwrap_or_default(), native_indices: mod_natives_map });
|
|
185
154
|
println!("{} {} {}", blue("[Titan]"), green("Extension loaded:"), config.name);
|
|
186
155
|
}
|
|
187
156
|
}
|
|
@@ -189,18 +158,16 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
189
158
|
|
|
190
159
|
// Scan node_modules
|
|
191
160
|
if node_modules.exists() {
|
|
192
|
-
scan_dir(node_modules, &mut modules, &mut libs, &mut all_natives
|
|
161
|
+
scan_dir(node_modules, &mut modules, &mut libs, &mut all_natives);
|
|
193
162
|
}
|
|
194
163
|
|
|
195
|
-
|
|
196
164
|
// Scan .ext (Production / Docker)
|
|
197
165
|
let ext_dir = root.join(".ext");
|
|
198
166
|
if ext_dir.exists() {
|
|
199
|
-
scan_dir(ext_dir, &mut modules, &mut libs, &mut all_natives
|
|
167
|
+
scan_dir(ext_dir, &mut modules, &mut libs, &mut all_natives);
|
|
200
168
|
}
|
|
201
169
|
|
|
202
|
-
*REGISTRY.lock().unwrap() = Some(Registry { _libs: libs, modules, natives: all_natives
|
|
203
|
-
|
|
170
|
+
*REGISTRY.lock().unwrap() = Some(Registry { _libs: libs, modules, natives: all_natives });
|
|
204
171
|
}
|
|
205
172
|
|
|
206
173
|
pub fn inject_external_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Object>, t_obj: v8::Local<v8::Object>) {
|
|
@@ -208,10 +175,9 @@ pub fn inject_external_extensions(scope: &mut v8::HandleScope, global: v8::Local
|
|
|
208
175
|
let invoke_key = v8_str(scope, "__titan_invoke_native");
|
|
209
176
|
global.set(scope, invoke_key.into(), invoke_fn.into());
|
|
210
177
|
|
|
211
|
-
let
|
|
212
|
-
|
|
213
|
-
} else {
|
|
214
|
-
|
|
178
|
+
let modules = if let Ok(guard) = REGISTRY.lock() {
|
|
179
|
+
guard.as_ref().map(|r| r.modules.clone()).unwrap_or_default()
|
|
180
|
+
} else { vec![] };
|
|
215
181
|
|
|
216
182
|
for module in modules {
|
|
217
183
|
let mod_obj = v8::Object::new(scope);
|
|
@@ -225,24 +191,6 @@ pub fn inject_external_extensions(scope: &mut v8::HandleScope, global: v8::Local
|
|
|
225
191
|
}
|
|
226
192
|
}
|
|
227
193
|
}
|
|
228
|
-
|
|
229
|
-
for (fn_name, &idx) in &module.v8_native_indices {
|
|
230
|
-
if let Some(&ptr) = v8_native_ptrs.get(idx) {
|
|
231
|
-
if ptr != 0 {
|
|
232
|
-
unsafe {
|
|
233
|
-
let ext = v8::External::new(scope, ptr as *mut std::ffi::c_void);
|
|
234
|
-
let templ = v8::FunctionTemplate::builder(native_invoke_v8_proxy)
|
|
235
|
-
.data(ext.into())
|
|
236
|
-
.build(scope);
|
|
237
|
-
|
|
238
|
-
if let Some(func) = templ.get_function(scope) {
|
|
239
|
-
let key = v8_str(scope, fn_name);
|
|
240
|
-
mod_obj.set(scope, key.into(), func.into());
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
194
|
let mod_key = v8_str(scope, &module.name);
|
|
247
195
|
t_obj.set(scope, mod_key.into(), mod_obj.into());
|
|
248
196
|
|
|
@@ -330,20 +278,6 @@ fn native_invoke_extension(scope: &mut v8::HandleScope, args: v8::FunctionCallba
|
|
|
330
278
|
}
|
|
331
279
|
}
|
|
332
280
|
|
|
333
|
-
fn native_invoke_v8_proxy(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, retval: v8::ReturnValue) {
|
|
334
|
-
let val = args.data();
|
|
335
|
-
if let Ok(ext) = v8::Local::<v8::External>::try_from(val) {
|
|
336
|
-
let ptr = ext.value() as *mut std::ffi::c_void;
|
|
337
|
-
if !ptr.is_null() {
|
|
338
|
-
unsafe {
|
|
339
|
-
type TitanV8Handler = extern "C" fn(&mut v8::HandleScope, v8::FunctionCallbackArguments, v8::ReturnValue);
|
|
340
|
-
let handler: TitanV8Handler = std::mem::transmute(ptr);
|
|
341
|
-
handler(scope, args, retval);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
281
|
fn arg_from_v8(scope: &mut v8::HandleScope, val: v8::Local<v8::Value>, ty: &ParamType) -> serde_json::Value {
|
|
348
282
|
match ty {
|
|
349
283
|
ParamType::String => serde_json::Value::String(val.to_rust_string_lossy(scope)),
|