Skip to content

Commit 6b68d0d

Browse files
committed
auto deserialize JsonPayload data over bridge
1 parent 9da5c38 commit 6b68d0d

File tree

6 files changed

+89
-36
lines changed

6 files changed

+89
-36
lines changed

packages/globe_runtime/lib/src/runtime_data.dart

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ enum FFITypeId {
1717
integer(2),
1818
double(3),
1919
bool(4),
20-
bytes(5);
20+
bytes(5),
21+
json_payload(6);
2122

2223
final int value;
2324
const FFITypeId(this.value);
@@ -30,9 +31,10 @@ extension FFITypeExtension on Object {
3031
double() => FFIDouble(this as double),
3132
bool() => FFIBool(this as bool),
3233
List<int>() => FFIBytes(this as List<int>),
33-
JsonPayload() => FFIBytes((this as JsonPayload).data),
34-
_ =>
35-
throw UnimplementedError('FFIConvertible not found for $runtimeType'),
34+
Map() => FFIJsonPayload(this),
35+
List() => FFIJsonPayload(this),
36+
Set() => FFIJsonPayload(this),
37+
_ => FFIJsonPayload(this as Map),
3638
};
3739
}
3840

@@ -62,6 +64,14 @@ class FFIInt implements FFIConvertible {
6264
FFITypeId get typeId => FFITypeId.integer;
6365
}
6466

67+
class FFIJsonPayload<T> extends FFIBytes {
68+
final T data;
69+
FFIJsonPayload(this.data) : super(msg_parkr.serialize(data));
70+
71+
@override
72+
FFITypeId get typeId => FFITypeId.json_payload;
73+
}
74+
6575
class FFIDouble implements FFIConvertible {
6676
final double value;
6777
FFIDouble(this.value);
@@ -154,8 +164,5 @@ extension MessagePackrExtensionForListInt on List<int> {
154164
}
155165

156166
extension MessagePackrExtensionForObject<T> on T {
157-
FFIBytes pack() {
158-
final bytes = msg_parkr.serialize(this);
159-
return FFIBytes(bytes);
160-
}
167+
FFIJsonPayload pack() => FFIJsonPayload(this);
161168
}

packages/globe_runtime/test/module.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ const sdk = {
1818
})
1919
);
2020
},
21-
json_decode: function (_, encoded, DartCallbackId) {
22-
const data = JsonPayload.decode(encoded);
23-
24-
const mapKeys = Object.keys(data);
25-
21+
json_decode: function (_, jsonData, DartCallbackId) {
22+
const mapKeys = Object.keys(jsonData);
2623
Dart.send_value(DartCallbackId, JsonPayload.encode(mapKeys));
2724
},
2825
say_hello: function (_, name, DartCallbackId) {
@@ -60,6 +57,9 @@ const sdk = {
6057
Dart.send_error(DartCallbackId, `Fetch failed: ${err.message}`);
6158
}
6259
},
60+
throw_error: function (_, DartCallbackId) {
61+
throw new Error("This is a simulated error");
62+
},
6363
},
6464
};
6565

packages/globe_runtime/test/runtime_test.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ void main() {
8888
});
8989

9090
test('should decode object', () async {
91-
final mapDataAsArg = mapData.pack();
92-
final result = await callJsFunction('json_decode', args: [mapDataAsArg])
91+
final result = await callJsFunction('json_decode', args: [mapData.pack()])
9392
.then((data) => data.unpack());
9493

9594
expect(
@@ -154,4 +153,16 @@ void main() {
154153
]),
155154
);
156155
});
156+
157+
test('should catch errors from Javascript', () async {
158+
try {
159+
runtime.callFunction(
160+
moduleName,
161+
function: 'throw_error',
162+
onData: (data) => true,
163+
);
164+
} catch (e) {
165+
expect(e, isA<StateError>());
166+
}
167+
});
157168
}

src/dart_runtime.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
DartJSService,
44
RpcResponse,
55
SendValueRequest,
6-
JsonPayload,
76
} from "./dart_runtime_entry.ts";
87
import * as msgPackr from "ext:js_msg_packr/index.js";
98

src/js_runtime.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ pub enum FFITypeId {
226226
Double = 3,
227227
Bool = 4,
228228
Bytes = 5,
229+
JsonPayload = 6,
229230
}
230231

231232
impl FFITypeId {
@@ -238,6 +239,7 @@ impl FFITypeId {
238239
3 => Some(FFITypeId::Double),
239240
4 => Some(FFITypeId::Bool),
240241
5 => Some(FFITypeId::Bytes),
242+
6 => Some(FFITypeId::JsonPayload),
241243
_ => None,
242244
}
243245
}
@@ -287,15 +289,10 @@ pub fn c_args_to_v8_args_global(
287289
v8::Boolean::new(scope, bool_value).into()
288290
}
289291
Some(FFITypeId::Bytes) => {
290-
let byte_array =
291-
unsafe { std::slice::from_raw_parts(arg_ptr as *const u8, size as usize) };
292-
293-
let v8_array = v8::ArrayBuffer::new_backing_store_from_boxed_slice(
294-
byte_array.to_vec().into_boxed_slice(),
295-
);
296-
let v8_shared_array = v8_array.make_shared();
297-
let v8_buffer = v8::ArrayBuffer::with_backing_store(scope, &v8_shared_array);
298-
v8_buffer.into()
292+
parse_byte_data(scope, arg_ptr as *const u8, size as usize).into()
293+
}
294+
Some(FFITypeId::JsonPayload) => {
295+
parse_json_payload_bytes(scope, arg_ptr as *const u8, size as usize).into()
299296
}
300297
_ => v8::undefined(scope).into(),
301298
};
@@ -307,6 +304,50 @@ pub fn c_args_to_v8_args_global(
307304
v8_args
308305
}
309306

307+
fn parse_byte_data<'a>(
308+
scope: &mut v8::HandleScope<'a>,
309+
arg_ptr: *const u8,
310+
size: usize,
311+
) -> v8::Local<'a, v8::ArrayBuffer> {
312+
let byte_array = unsafe { std::slice::from_raw_parts(arg_ptr, size) };
313+
314+
let v8_array =
315+
v8::ArrayBuffer::new_backing_store_from_boxed_slice(byte_array.to_vec().into_boxed_slice());
316+
let v8_shared_array = v8_array.make_shared();
317+
let v8_buffer = v8::ArrayBuffer::with_backing_store(scope, &v8_shared_array);
318+
v8_buffer
319+
}
320+
321+
fn parse_json_payload_bytes<'a>(
322+
scope: &mut v8::HandleScope<'a>,
323+
arg_ptr: *const u8,
324+
size: usize,
325+
) -> v8::Local<'a, v8::Value> {
326+
let v8_buffer = parse_byte_data(scope, arg_ptr, size);
327+
328+
// call JsonPayload.decode() from the runtime add pass the v8_buffer as an argument
329+
let json_payload = v8::String::new(scope, "JsonPayload").unwrap();
330+
let json_payload_value = scope
331+
.get_current_context()
332+
.global(scope)
333+
.get(scope, json_payload.into())
334+
.unwrap();
335+
336+
let decode_function = v8::String::new(scope, "decode").unwrap();
337+
let decode_function_value = json_payload_value
338+
.to_object(scope)
339+
.unwrap()
340+
.get(scope, decode_function.into())
341+
.unwrap();
342+
let decode_function = v8::Local::<v8::Function>::try_from(decode_function_value).unwrap();
343+
let args = vec![v8_buffer.into()];
344+
let result = decode_function
345+
.call(scope, json_payload_value.into(), &args)
346+
.unwrap();
347+
let result = v8::Local::<v8::Value>::try_from(result).unwrap();
348+
result
349+
}
350+
310351
pub fn c_args_to_v8_args_local<'s>(
311352
scope: &mut v8::HandleScope<'s>,
312353
args: *const *const c_void,
@@ -350,15 +391,10 @@ pub fn c_args_to_v8_args_local<'s>(
350391
v8::Boolean::new(scope, bool_value).into()
351392
}
352393
Some(FFITypeId::Bytes) => {
353-
let byte_array =
354-
unsafe { std::slice::from_raw_parts(arg_ptr as *const u8, size as usize) };
355-
356-
let v8_array = v8::ArrayBuffer::new_backing_store_from_boxed_slice(
357-
byte_array.to_vec().into_boxed_slice(),
358-
);
359-
let v8_shared_array = v8_array.make_shared();
360-
let v8_buffer = v8::ArrayBuffer::with_backing_store(scope, &v8_shared_array);
361-
v8_buffer.into()
394+
parse_byte_data(scope, arg_ptr as *const u8, size as usize).into()
395+
}
396+
Some(FFITypeId::JsonPayload) => {
397+
parse_json_payload_bytes(scope, arg_ptr as *const u8, size as usize).into()
362398
}
363399
_ => v8::undefined(scope).into(),
364400
};

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,11 @@ pub unsafe extern "C" fn call_js_function(
241241

242242
// Wait for module execution
243243
if let Err(e) = javascript_runtime.run_event_loop(Default::default()).await {
244-
return Err(format!("Error running event loop: {}", e));
244+
return Err(e.to_string());
245245
}
246246

247247
if let Err(e) = fnc_call.await {
248-
return Err(format!("Error running function: {}", e));
248+
return Err(e.to_string());
249249
}
250250

251251
Ok(())

0 commit comments

Comments
 (0)