diff --git a/lib/app.dart b/lib/app.dart index 03a3e9e..469bf46 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -24,6 +24,7 @@ import 'api/analytics.dart'; import 'api/api.dart'; import 'common/helper/system_helper.dart'; import 'common/io/rs_http.dart'; +import 'common/rust/api/go_api.dart'; import 'common/rust/frb_generated.dart'; import 'common/rust/api/win32_api.dart' as win32; import 'data/app_version_data.dart'; @@ -128,6 +129,9 @@ class AppGlobalModel extends _$AppGlobalModel { await RSHttp.init(); dPrint("---- rust bridge init -----"); + final r = await pingGo(ping: "PING"); + dPrint("pingGo == $r"); + // init Hive try { Hive.init("$applicationSupportDir/db"); diff --git a/lib/common/rust/api/go_api.dart b/lib/common/rust/api/go_api.dart new file mode 100644 index 0000000..e6211f1 --- /dev/null +++ b/lib/common/rust/api/go_api.dart @@ -0,0 +1,10 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.6.0. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +Future pingGo({required String ping}) => + RustLib.instance.api.crateApiGoApiPingGo(ping: ping); diff --git a/lib/common/rust/frb_generated.dart b/lib/common/rust/frb_generated.dart index f20f230..875d5cb 100644 --- a/lib/common/rust/frb_generated.dart +++ b/lib/common/rust/frb_generated.dart @@ -4,6 +4,7 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field import 'api/asar_api.dart'; +import 'api/go_api.dart'; import 'api/http_api.dart'; import 'api/rs_process.dart'; import 'api/win32_api.dart'; @@ -70,7 +71,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.6.0'; @override - int get rustContentHash => 1832496273; + int get rustContentHash => -809105468; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -96,6 +97,8 @@ abstract class RustLibApi extends BaseApi { Future crateApiAsarApiGetRsiLauncherAsarData( {required String asarPath}); + Future crateApiGoApiPingGo({required String ping}); + Future crateApiAsarApiRsiLauncherAsarDataWriteMainJs( {required RsiLauncherAsarData that, required List content}); @@ -244,6 +247,28 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["asarPath"], ); + @override + Future crateApiGoApiPingGo({required String ping}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + var arg0 = cst_encode_String(ping); + return wire.wire__crate__api__go_api__ping_go(port_, arg0); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_String, + decodeErrorData: null, + ), + constMeta: kCrateApiGoApiPingGoConstMeta, + argValues: [ping], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiGoApiPingGoConstMeta => const TaskConstMeta( + debugName: "ping_go", + argNames: ["ping"], + ); + @override Future crateApiAsarApiRsiLauncherAsarDataWriteMainJs( {required RsiLauncherAsarData that, required List content}) { diff --git a/lib/common/rust/frb_generated.io.dart b/lib/common/rust/frb_generated.io.dart index 7f0a667..f3a19db 100644 --- a/lib/common/rust/frb_generated.io.dart +++ b/lib/common/rust/frb_generated.io.dart @@ -4,6 +4,7 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field import 'api/asar_api.dart'; +import 'api/go_api.dart'; import 'api/http_api.dart'; import 'api/rs_process.dart'; import 'api/win32_api.dart'; @@ -661,6 +662,25 @@ class RustLibWire implements BaseWire { _wire__crate__api__asar_api__get_rsi_launcher_asar_dataPtr.asFunction< void Function(int, ffi.Pointer)>(); + void wire__crate__api__go_api__ping_go( + int port_, + ffi.Pointer ping, + ) { + return _wire__crate__api__go_api__ping_go( + port_, + ping, + ); + } + + late final _wire__crate__api__go_api__ping_goPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Int64, ffi.Pointer)>>( + 'frbgen_starcitizen_doctor_wire__crate__api__go_api__ping_go'); + late final _wire__crate__api__go_api__ping_go = + _wire__crate__api__go_api__ping_goPtr.asFunction< + void Function(int, ffi.Pointer)>(); + void wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js( int port_, ffi.Pointer that, @@ -931,14 +951,14 @@ class RustLibWire implements BaseWire { _dummy_method_to_enforce_bundlingPtr.asFunction(); } -typedef DartPostCObjectFnType - = ffi.Pointer>; +typedef DartPort = ffi.Int64; +typedef DartDartPort = int; typedef DartPostCObjectFnTypeFunction = ffi.Bool Function( DartPort port_id, ffi.Pointer message); typedef DartDartPostCObjectFnTypeFunction = bool Function( DartDartPort port_id, ffi.Pointer message); -typedef DartPort = ffi.Int64; -typedef DartDartPort = int; +typedef DartPostCObjectFnType + = ffi.Pointer>; final class wire_cst_list_prim_u_8_strict extends ffi.Struct { external ffi.Pointer ptr; diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 1b97e58..871efbf 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -11,7 +11,7 @@ PODS: - FlutterMacOS - rust_builder (0.0.1): - FlutterMacOS - - screen_retriever (0.0.1): + - screen_retriever_macos (0.0.1): - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS @@ -25,7 +25,7 @@ DEPENDENCIES: - macos_window_utils (from `Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - rust_builder (from `Flutter/ephemeral/.symlinks/plugins/rust_builder/macos`) - - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) + - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) @@ -42,8 +42,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin rust_builder: :path: Flutter/ephemeral/.symlinks/plugins/rust_builder/macos - screen_retriever: - :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos + screen_retriever_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos window_manager: @@ -51,15 +51,15 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: desktop_webview_window: d4365e71bcd4e1aa0c14cf0377aa24db0c16a7e2 - device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 + device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 macos_window_utils: 933f91f64805e2eb91a5bd057cf97cd097276663 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 rust_builder: 4b521d57bf67224da65f32b529be8fab420fca32 - screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 + screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161 url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef64..8e02df2 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 160d59d..6dd2900 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -19,11 +19,16 @@ once_cell = "1.20" reqwest = { version = "0.12", features = ["rustls-tls-webpki-roots", "cookies", "gzip", "json", "stream"] } hickory-resolver = { version = "0.24" } anyhow = "1.0" - scopeguard = "1.2" notify-rust = "4" asar = "0.3.0" +# golang support +rust2go = {version = "0.3.17"} + +[build-dependencies] +rust2go = { version = "0.3.17", features = ["build"] } + [target.'cfg(windows)'.dependencies] windows = { version = "0.58.0", features = ["Win32_UI_WindowsAndMessaging"] } win32job = "2" diff --git a/rust/build.rs b/rust/build.rs new file mode 100644 index 0000000..01f4391 --- /dev/null +++ b/rust/build.rs @@ -0,0 +1,12 @@ +use rust2go::RegenArgs; + +fn main() { + rust2go::Builder::new() + .with_go_src("./go") + .with_regen_arg(RegenArgs { + src: "./src/go/go_api.rs".into(), + dst: "./go/rs_gen.go".into(), + ..Default::default() + }) + .build(); +} \ No newline at end of file diff --git a/rust/go/go.mod b/rust/go/go.mod new file mode 100644 index 0000000..b229154 --- /dev/null +++ b/rust/go/go.mod @@ -0,0 +1,3 @@ +module github.com/StarCitizenToolBox/app/downloader + +go 1.23.3 diff --git a/rust/go/rs_gen.go b/rust/go/rs_gen.go new file mode 100644 index 0000000..84b440e --- /dev/null +++ b/rust/go/rs_gen.go @@ -0,0 +1,195 @@ +package main + +/* +// Generated by rust2go. Please DO NOT edit this C part manually. + +#include +#include +#include +#include + +typedef struct ListRef { + const void *ptr; + uintptr_t len; +} ListRef; + +typedef struct StringRef { + const uint8_t *ptr; + uintptr_t len; +} StringRef; + +// hack from: https://stackoverflow.com/a/69904977 +__attribute__((weak)) +inline void RsCallGo_ping_cb(const void *f_ptr, struct StringRef resp, const void *slot) { +((void (*)(struct StringRef, const void*))f_ptr)(resp, slot); +} +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +var RsCallGoImpl RsCallGo + +type RsCallGo interface { + ping(ping string) string +} + +//export CRsCallGo_ping +func CRsCallGo_ping(ping C.StringRef, slot *C.void, cb *C.void) { + _new_ping := newString(ping) + resp := RsCallGoImpl.ping(_new_ping) + resp_ref, buffer := cvt_ref(cntString, refString)(&resp) + C.RsCallGo_ping_cb(unsafe.Pointer(cb), resp_ref, unsafe.Pointer(slot)) + runtime.KeepAlive(resp) + runtime.KeepAlive(buffer) +} + +func newString(s_ref C.StringRef) string { + return unsafe.String((*byte)(unsafe.Pointer(s_ref.ptr)), s_ref.len) +} +func refString(s *string, _ *[]byte) C.StringRef { + return C.StringRef{ + ptr: (*C.uint8_t)(unsafe.StringData(*s)), + len: C.uintptr_t(len(*s)), + } +} + +func cntString(_ *string, _ *uint) [0]C.StringRef { return [0]C.StringRef{} } +func new_list_mapper[T1, T2 any](f func(T1) T2) func(C.ListRef) []T2 { + return func(x C.ListRef) []T2 { + input := unsafe.Slice((*T1)(unsafe.Pointer(x.ptr)), x.len) + output := make([]T2, len(input)) + for i, v := range input { + output[i] = f(v) + } + return output + } +} +func new_list_mapper_primitive[T1, T2 any](_ func(T1) T2) func(C.ListRef) []T2 { + return func(x C.ListRef) []T2 { + return unsafe.Slice((*T2)(unsafe.Pointer(x.ptr)), x.len) + } +} + +// only handle non-primitive type T +func cnt_list_mapper[T, R any](f func(s *T, cnt *uint) [0]R) func(s *[]T, cnt *uint) [0]C.ListRef { + return func(s *[]T, cnt *uint) [0]C.ListRef { + for _, v := range *s { + f(&v, cnt) + } + *cnt += uint(len(*s)) * size_of[R]() + return [0]C.ListRef{} + } +} + +// only handle primitive type T +func cnt_list_mapper_primitive[T, R any](_ func(s *T, cnt *uint) [0]R) func(s *[]T, cnt *uint) [0]C.ListRef { + return func(s *[]T, cnt *uint) [0]C.ListRef { return [0]C.ListRef{} } +} + +// only handle non-primitive type T +func ref_list_mapper[T, R any](f func(s *T, buffer *[]byte) R) func(s *[]T, buffer *[]byte) C.ListRef { + return func(s *[]T, buffer *[]byte) C.ListRef { + if len(*buffer) == 0 { + return C.ListRef{ + ptr: unsafe.Pointer(nil), + len: C.uintptr_t(len(*s)), + } + } + ret := C.ListRef{ + ptr: unsafe.Pointer(&(*buffer)[0]), + len: C.uintptr_t(len(*s)), + } + children_bytes := int(size_of[R]()) * len(*s) + children := (*buffer)[:children_bytes] + *buffer = (*buffer)[children_bytes:] + for _, v := range *s { + child := f(&v, buffer) + len := unsafe.Sizeof(child) + copy(children, unsafe.Slice((*byte)(unsafe.Pointer(&child)), len)) + children = children[len:] + } + return ret + } +} + +// only handle primitive type T +func ref_list_mapper_primitive[T, R any](_ func(s *T, buffer *[]byte) R) func(s *[]T, buffer *[]byte) C.ListRef { + return func(s *[]T, buffer *[]byte) C.ListRef { + if len(*s) == 0 { + return C.ListRef{ + ptr: unsafe.Pointer(nil), + len: C.uintptr_t(0), + } + } + return C.ListRef{ + ptr: unsafe.Pointer(&(*s)[0]), + len: C.uintptr_t(len(*s)), + } + } +} +func size_of[T any]() uint { + var t T + return uint(unsafe.Sizeof(t)) +} +func cvt_ref[R, CR any](cnt_f func(s *R, cnt *uint) [0]CR, ref_f func(p *R, buffer *[]byte) CR) func(p *R) (CR, []byte) { + return func(p *R) (CR, []byte) { + var cnt uint + cnt_f(p, &cnt) + buffer := make([]byte, cnt) + return ref_f(p, &buffer), buffer + } +} +func cvt_ref_cap[R, CR any](cnt_f func(s *R, cnt *uint) [0]CR, ref_f func(p *R, buffer *[]byte) CR, add_cap uint) func(p *R) (CR, []byte) { + return func(p *R) (CR, []byte) { + var cnt uint + cnt_f(p, &cnt) + buffer := make([]byte, cnt, cnt+add_cap) + return ref_f(p, &buffer), buffer + } +} + +func newC_uint8_t(n C.uint8_t) uint8 { return uint8(n) } +func newC_uint16_t(n C.uint16_t) uint16 { return uint16(n) } +func newC_uint32_t(n C.uint32_t) uint32 { return uint32(n) } +func newC_uint64_t(n C.uint64_t) uint64 { return uint64(n) } +func newC_int8_t(n C.int8_t) int8 { return int8(n) } +func newC_int16_t(n C.int16_t) int16 { return int16(n) } +func newC_int32_t(n C.int32_t) int32 { return int32(n) } +func newC_int64_t(n C.int64_t) int64 { return int64(n) } +func newC_bool(n C.bool) bool { return bool(n) } +func newC_uintptr_t(n C.uintptr_t) uint { return uint(n) } +func newC_intptr_t(n C.intptr_t) int { return int(n) } +func newC_float(n C.float) float32 { return float32(n) } +func newC_double(n C.double) float64 { return float64(n) } + +func cntC_uint8_t(_ *uint8, _ *uint) [0]C.uint8_t { return [0]C.uint8_t{} } +func cntC_uint16_t(_ *uint16, _ *uint) [0]C.uint16_t { return [0]C.uint16_t{} } +func cntC_uint32_t(_ *uint32, _ *uint) [0]C.uint32_t { return [0]C.uint32_t{} } +func cntC_uint64_t(_ *uint64, _ *uint) [0]C.uint64_t { return [0]C.uint64_t{} } +func cntC_int8_t(_ *int8, _ *uint) [0]C.int8_t { return [0]C.int8_t{} } +func cntC_int16_t(_ *int16, _ *uint) [0]C.int16_t { return [0]C.int16_t{} } +func cntC_int32_t(_ *int32, _ *uint) [0]C.int32_t { return [0]C.int32_t{} } +func cntC_int64_t(_ *int64, _ *uint) [0]C.int64_t { return [0]C.int64_t{} } +func cntC_bool(_ *bool, _ *uint) [0]C.bool { return [0]C.bool{} } +func cntC_uintptr_t(_ *uint, _ *uint) [0]C.uintptr_t { return [0]C.uintptr_t{} } +func cntC_intptr_t(_ *int, _ *uint) [0]C.intptr_t { return [0]C.intptr_t{} } +func cntC_float(_ *float32, _ *uint) [0]C.float { return [0]C.float{} } +func cntC_double(_ *float64, _ *uint) [0]C.double { return [0]C.double{} } + +func refC_uint8_t(p *uint8, _ *[]byte) C.uint8_t { return C.uint8_t(*p) } +func refC_uint16_t(p *uint16, _ *[]byte) C.uint16_t { return C.uint16_t(*p) } +func refC_uint32_t(p *uint32, _ *[]byte) C.uint32_t { return C.uint32_t(*p) } +func refC_uint64_t(p *uint64, _ *[]byte) C.uint64_t { return C.uint64_t(*p) } +func refC_int8_t(p *int8, _ *[]byte) C.int8_t { return C.int8_t(*p) } +func refC_int16_t(p *int16, _ *[]byte) C.int16_t { return C.int16_t(*p) } +func refC_int32_t(p *int32, _ *[]byte) C.int32_t { return C.int32_t(*p) } +func refC_int64_t(p *int64, _ *[]byte) C.int64_t { return C.int64_t(*p) } +func refC_bool(p *bool, _ *[]byte) C.bool { return C.bool(*p) } +func refC_uintptr_t(p *uint, _ *[]byte) C.uintptr_t { return C.uintptr_t(*p) } +func refC_intptr_t(p *int, _ *[]byte) C.intptr_t { return C.intptr_t(*p) } +func refC_float(p *float32, _ *[]byte) C.float { return C.float(*p) } +func refC_double(p *float64, _ *[]byte) C.double { return C.double(*p) } +func main() {} diff --git a/rust/go/rs_impl.go b/rust/go/rs_impl.go new file mode 100644 index 0000000..3819bf9 --- /dev/null +++ b/rust/go/rs_impl.go @@ -0,0 +1,14 @@ +package main + +type RustCallGo struct{} + +func (r RustCallGo) ping(ping string) string { + if ping == "PING" { + return "PONG" + } + panic("invalid ping") +} + +func init() { + RsCallGoImpl = RustCallGo{} +} diff --git a/rust/src/api/go_api.rs b/rust/src/api/go_api.rs new file mode 100644 index 0000000..9389c92 --- /dev/null +++ b/rust/src/api/go_api.rs @@ -0,0 +1,5 @@ +use crate::go::go_api::{RsCallGo, RsCallGoImpl}; + +pub fn ping_go(ping: String) -> String { + RsCallGoImpl::ping(ping) +} diff --git a/rust/src/api/mod.rs b/rust/src/api/mod.rs index cb0e8f9..7a03554 100644 --- a/rust/src/api/mod.rs +++ b/rust/src/api/mod.rs @@ -5,3 +5,4 @@ pub mod http_api; pub mod rs_process; pub mod win32_api; pub mod asar_api; +pub mod go_api; diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 2be8edc..34dfc64 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueNom, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.6.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1832496273; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -809105468; // Section: executor @@ -161,6 +161,27 @@ fn wire__crate__api__asar_api__get_rsi_launcher_asar_data_impl( }, ) } +fn wire__crate__api__go_api__ping_go_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ping: impl CstDecode, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "ping_go", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let api_ping = ping.cst_decode(); + move |context| { + transform_result_dco::<_, _, ()>((move || { + let output_ok = Result::<_, ()>::Ok(crate::api::go_api::ping_go(api_ping))?; + Ok(output_ok) + })()) + } + }, + ) +} fn wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js_impl( port_: flutter_rust_bridge::for_generated::MessagePort, that: impl CstDecode, @@ -1406,6 +1427,14 @@ mod io { wire__crate__api__asar_api__get_rsi_launcher_asar_data_impl(port_, asar_path) } + #[no_mangle] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__go_api__ping_go( + port_: i64, + ping: *mut wire_cst_list_prim_u_8_strict, + ) { + wire__crate__api__go_api__ping_go_impl(port_, ping) + } + #[no_mangle] pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js( port_: i64, diff --git a/rust/src/go/go_api.rs b/rust/src/go/go_api.rs new file mode 100644 index 0000000..eeb4168 --- /dev/null +++ b/rust/src/go/go_api.rs @@ -0,0 +1,9 @@ +pub mod binding { + #![allow(warnings)] + rust2go::r2g_include_binding!(); +} + +#[rust2go::r2g] +pub trait RsCallGo { + fn ping(ping: String) -> String; +} \ No newline at end of file diff --git a/rust/src/go/mod.rs b/rust/src/go/mod.rs new file mode 100644 index 0000000..bf4b15a --- /dev/null +++ b/rust/src/go/mod.rs @@ -0,0 +1 @@ +pub mod go_api; \ No newline at end of file diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 2c46138..7ef1b7f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,3 +1,4 @@ pub mod api; mod frb_generated; pub mod http_package; +pub mod go;