mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-14 20:33:41 +00:00
feat: flutter ui integration
This commit is contained in:
1 parent
0fc133e46d
commit
c4a30dc4c2
170 files changed
+7783
-1
No files matched your search
@@ -0,0 +1,22 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:gopeed/core/common/libgopeed_interface.dart';
|
||||
import 'package:gopeed/core/common/start_config.dart';
|
||||
|
||||
class LibgopeedChannel implements LibgopeedInterface {
|
||||
static const _channel = MethodChannel('gopeed.com/libgopeed');
|
||||
|
||||
@override
|
||||
Future<int> start(StartConfig cfg) async {
|
||||
final port = await _channel.invokeMethod('start', {
|
||||
'cfg': jsonEncode(cfg),
|
||||
});
|
||||
return port as int;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stop() async {
|
||||
return await _channel.invokeMethod('stop');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:gopeed/core/ffi/libgopeed_bind.dart';
|
||||
|
||||
import 'libgopeed_interface.dart';
|
||||
import 'start_config.dart';
|
||||
|
||||
class LibgopeedFFi implements LibgopeedInterface {
|
||||
late LibgopeedBind _libgopeed;
|
||||
|
||||
LibgopeedFFi(LibgopeedBind libgopeed) {
|
||||
_libgopeed = libgopeed;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> start(StartConfig cfg) {
|
||||
var completer = Completer<int>();
|
||||
var result = _libgopeed.Start(jsonEncode(cfg).toNativeUtf8().cast());
|
||||
if (result.r1 != nullptr) {
|
||||
completer.completeError(result.r1.cast<Utf8>().toDartString());
|
||||
} else {
|
||||
completer.complete(result.r0);
|
||||
}
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stop() {
|
||||
var completer = Completer<void>();
|
||||
_libgopeed.Stop();
|
||||
completer.complete();
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import 'package:gopeed/core/common/start_config.dart';
|
||||
|
||||
abstract class LibgopeedInterface {
|
||||
Future<int> start(StartConfig cfg);
|
||||
|
||||
Future<void> stop();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'start_config.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class StartConfig {
|
||||
String network;
|
||||
String address;
|
||||
String storage;
|
||||
String storageDir;
|
||||
int refreshInterval;
|
||||
|
||||
StartConfig({
|
||||
required this.network,
|
||||
required this.address,
|
||||
required this.storage,
|
||||
required this.storageDir,
|
||||
required this.refreshInterval,
|
||||
});
|
||||
|
||||
factory StartConfig.fromJson(Map<String, dynamic> json) =>
|
||||
_$StartConfigFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$StartConfigToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'start_config.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
StartConfig _$StartConfigFromJson(Map<String, dynamic> json) => StartConfig(
|
||||
network: json['network'] as String,
|
||||
address: json['address'] as String,
|
||||
storage: json['storage'] as String,
|
||||
storageDir: json['storageDir'] as String,
|
||||
refreshInterval: json['refreshInterval'] as int,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$StartConfigToJson(StartConfig instance) =>
|
||||
<String, dynamic>{
|
||||
'network': instance.network,
|
||||
'address': instance.address,
|
||||
'storage': instance.storage,
|
||||
'storageDir': instance.storageDir,
|
||||
'refreshInterval': instance.refreshInterval,
|
||||
};
|
||||
@@ -0,0 +1,241 @@
|
||||
// AUTO GENERATED FILE, DO NOT EDIT.
|
||||
//
|
||||
// Generated by `package:ffigen`.
|
||||
import 'dart:ffi' as ffi;
|
||||
|
||||
/// Bindings to gopeed core.
|
||||
class LibgopeedBind {
|
||||
/// Holds the symbol lookup function.
|
||||
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
_lookup;
|
||||
|
||||
/// The symbols are looked up in [dynamicLibrary].
|
||||
LibgopeedBind(ffi.DynamicLibrary dynamicLibrary)
|
||||
: _lookup = dynamicLibrary.lookup;
|
||||
|
||||
/// The symbols are looked up with [lookup].
|
||||
LibgopeedBind.fromLookup(
|
||||
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
lookup)
|
||||
: _lookup = lookup;
|
||||
|
||||
Start_return Start(
|
||||
ffi.Pointer<ffi.Char> cfg,
|
||||
) {
|
||||
return _Start(
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
late final _StartPtr =
|
||||
_lookup<ffi.NativeFunction<Start_return Function(ffi.Pointer<ffi.Char>)>>(
|
||||
'Start');
|
||||
late final _Start =
|
||||
_StartPtr.asFunction<Start_return Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
void Stop() {
|
||||
return _Stop();
|
||||
}
|
||||
|
||||
late final _StopPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function()>>('Stop');
|
||||
late final _Stop = _StopPtr.asFunction<void Function()>();
|
||||
}
|
||||
|
||||
class __mbstate_t extends ffi.Union {
|
||||
@ffi.Array.multi([128])
|
||||
external ffi.Array<ffi.Char> __mbstate8;
|
||||
|
||||
@ffi.LongLong()
|
||||
external int _mbstateL;
|
||||
}
|
||||
|
||||
class __darwin_pthread_handler_rec extends ffi.Struct {
|
||||
external ffi
|
||||
.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>
|
||||
__routine;
|
||||
|
||||
external ffi.Pointer<ffi.Void> __arg;
|
||||
|
||||
external ffi.Pointer<__darwin_pthread_handler_rec> __next;
|
||||
}
|
||||
|
||||
class _opaque_pthread_attr_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([56])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_cond_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([40])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_condattr_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([8])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_mutex_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([56])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_mutexattr_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([8])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_once_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([8])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_rwlock_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([192])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_rwlockattr_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
@ffi.Array.multi([16])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _opaque_pthread_t extends ffi.Struct {
|
||||
@ffi.Long()
|
||||
external int __sig;
|
||||
|
||||
external ffi.Pointer<__darwin_pthread_handler_rec> __cleanup_stack;
|
||||
|
||||
@ffi.Array.multi([8176])
|
||||
external ffi.Array<ffi.Char> __opaque;
|
||||
}
|
||||
|
||||
class _GoString_ extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Char> p;
|
||||
|
||||
@ptrdiff_t()
|
||||
external int n;
|
||||
}
|
||||
|
||||
typedef ptrdiff_t = __darwin_ptrdiff_t;
|
||||
typedef __darwin_ptrdiff_t = ffi.Long;
|
||||
|
||||
class GoInterface extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Void> t;
|
||||
|
||||
external ffi.Pointer<ffi.Void> v;
|
||||
}
|
||||
|
||||
class GoSlice extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Void> data;
|
||||
|
||||
@GoInt()
|
||||
external int len;
|
||||
|
||||
@GoInt()
|
||||
external int cap;
|
||||
}
|
||||
|
||||
typedef GoInt = GoInt64;
|
||||
typedef GoInt64 = ffi.LongLong;
|
||||
|
||||
class Start_return extends ffi.Struct {
|
||||
@GoInt()
|
||||
external int r0;
|
||||
|
||||
external ffi.Pointer<ffi.Char> r1;
|
||||
}
|
||||
|
||||
const int __DARWIN_ONLY_64_BIT_INO_T = 1;
|
||||
|
||||
const int __DARWIN_ONLY_UNIX_CONFORMANCE = 1;
|
||||
|
||||
const int __DARWIN_ONLY_VERS_1050 = 1;
|
||||
|
||||
const int __DARWIN_UNIX03 = 1;
|
||||
|
||||
const int __DARWIN_64_BIT_INO_T = 1;
|
||||
|
||||
const int __DARWIN_VERS_1050 = 1;
|
||||
|
||||
const int __DARWIN_NON_CANCELABLE = 0;
|
||||
|
||||
const String __DARWIN_SUF_EXTSN = '\$DARWIN_EXTSN';
|
||||
|
||||
const int __DARWIN_C_ANSI = 4096;
|
||||
|
||||
const int __DARWIN_C_FULL = 900000;
|
||||
|
||||
const int __DARWIN_C_LEVEL = 900000;
|
||||
|
||||
const int __STDC_WANT_LIB_EXT1__ = 1;
|
||||
|
||||
const int __DARWIN_NO_LONG_LONG = 0;
|
||||
|
||||
const int _DARWIN_FEATURE_64_BIT_INODE = 1;
|
||||
|
||||
const int _DARWIN_FEATURE_ONLY_64_BIT_INODE = 1;
|
||||
|
||||
const int _DARWIN_FEATURE_ONLY_VERS_1050 = 1;
|
||||
|
||||
const int _DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE = 1;
|
||||
|
||||
const int _DARWIN_FEATURE_UNIX_CONFORMANCE = 3;
|
||||
|
||||
const int __has_ptrcheck = 0;
|
||||
|
||||
const int __DARWIN_NULL = 0;
|
||||
|
||||
const int __PTHREAD_SIZE__ = 8176;
|
||||
|
||||
const int __PTHREAD_ATTR_SIZE__ = 56;
|
||||
|
||||
const int __PTHREAD_MUTEXATTR_SIZE__ = 8;
|
||||
|
||||
const int __PTHREAD_MUTEX_SIZE__ = 56;
|
||||
|
||||
const int __PTHREAD_CONDATTR_SIZE__ = 8;
|
||||
|
||||
const int __PTHREAD_COND_SIZE__ = 40;
|
||||
|
||||
const int __PTHREAD_ONCE_SIZE__ = 8;
|
||||
|
||||
const int __PTHREAD_RWLOCK_SIZE__ = 192;
|
||||
|
||||
const int __PTHREAD_RWLOCKATTR_SIZE__ = 16;
|
||||
|
||||
const int __DARWIN_WCHAR_MAX = 2147483647;
|
||||
|
||||
const int __DARWIN_WCHAR_MIN = -2147483648;
|
||||
|
||||
const int __DARWIN_WEOF = -1;
|
||||
|
||||
const int _FORTIFY_SOURCE = 2;
|
||||
|
||||
const int NULL = 0;
|
||||
|
||||
const int USER_ADDR_NULL = 0;
|
||||
@@ -0,0 +1,171 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:gopeed/core/common/libgopeed_channel.dart';
|
||||
import 'package:gopeed/core/common/libgopeed_ffi.dart';
|
||||
import 'package:gopeed/core/common/start_config.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../util/util.dart';
|
||||
import 'common/libgopeed_interface.dart';
|
||||
import 'ffi/libgopeed_bind.dart';
|
||||
|
||||
const unixSocketPath = 'gopeed.sock';
|
||||
|
||||
class LibgopeedBoot {
|
||||
String network = "";
|
||||
String address = "";
|
||||
int port = 0;
|
||||
int refreshInterval = 250;
|
||||
|
||||
late LibgopeedInterface _libgopeed;
|
||||
late SendPort _childSendPort;
|
||||
|
||||
static LibgopeedBoot? _instance;
|
||||
|
||||
static LibgopeedBoot get instance {
|
||||
if (_instance == null) {
|
||||
_instance = LibgopeedBoot._internal();
|
||||
if (!Util.isDesktop()) {
|
||||
_instance!._libgopeed = LibgopeedChannel();
|
||||
}
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
LibgopeedBoot._internal();
|
||||
|
||||
Future<void> start() async {
|
||||
var storageDir = "./";
|
||||
if (!Util.isUnix()) {
|
||||
// not support unix socket, use tcp
|
||||
network = "tcp";
|
||||
address = "127.0.0.1:0";
|
||||
} else {
|
||||
network = "unix";
|
||||
if (Util.isDesktop()) {
|
||||
address = unixSocketPath;
|
||||
} else if (Platform.isAndroid) {
|
||||
address = "${(await getTemporaryDirectory()).path}/$unixSocketPath";
|
||||
storageDir = (await getExternalStorageDirectory())?.path ?? "";
|
||||
}
|
||||
}
|
||||
final cfg = StartConfig(
|
||||
network: network,
|
||||
address: address,
|
||||
storage: 'bolt',
|
||||
storageDir: storageDir,
|
||||
refreshInterval: refreshInterval);
|
||||
if (Util.isDesktop()) {
|
||||
port = await _ffiStart(cfg);
|
||||
} else {
|
||||
port = await _libgopeed.start(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
if (Util.isDesktop()) {
|
||||
await _ffiStop();
|
||||
} else {
|
||||
await _libgopeed.stop();
|
||||
}
|
||||
}
|
||||
|
||||
_ffiInit() {
|
||||
if (Platform.isMacOS) {
|
||||
_libgopeed =
|
||||
LibgopeedFFi(LibgopeedBind(DynamicLibrary.open('libgopeed.dylib')));
|
||||
}
|
||||
}
|
||||
|
||||
// FFI run in isolate
|
||||
Future<int> _ffiStart(StartConfig cfg) async {
|
||||
var startCompleter = Completer<int>();
|
||||
|
||||
var mainReceive = ReceivePort();
|
||||
var isolate = await Isolate.spawn((SendPort sendPort) {
|
||||
_ffiInit();
|
||||
var childReceive = ReceivePort();
|
||||
sendPort.send(childReceive.sendPort);
|
||||
|
||||
childReceive.listen((message) async {
|
||||
late _Result result;
|
||||
try {
|
||||
if (message is _StartParam) {
|
||||
result = _StartResult();
|
||||
(result as _StartResult).port = await _libgopeed.start(message.cfg);
|
||||
}
|
||||
if (message is _StopParam) {
|
||||
result = _StopResult();
|
||||
await _libgopeed.stop();
|
||||
childReceive.close();
|
||||
Isolate.exit(sendPort);
|
||||
}
|
||||
} on Exception catch (e) {
|
||||
result.exception = e;
|
||||
}
|
||||
sendPort.send(result);
|
||||
});
|
||||
}, mainReceive.sendPort);
|
||||
|
||||
var childCompleter = Completer<void>();
|
||||
mainReceive.listen((message) {
|
||||
if (message is SendPort) {
|
||||
_childSendPort = message;
|
||||
childCompleter.complete();
|
||||
}
|
||||
if (message is _StartResult) {
|
||||
if (message.exception != null) {
|
||||
startCompleter.completeError(message.exception!);
|
||||
} else {
|
||||
startCompleter.complete(message.port!);
|
||||
}
|
||||
}
|
||||
if (message is _StopResult) {
|
||||
isolate.kill();
|
||||
if (message.exception != null) {
|
||||
_stopCompleter.completeError(message.exception!);
|
||||
} else {
|
||||
_stopCompleter.complete();
|
||||
}
|
||||
}
|
||||
});
|
||||
await childCompleter.future;
|
||||
_childSendPort.send(_StartParam(cfg: cfg));
|
||||
return startCompleter.future;
|
||||
}
|
||||
|
||||
late Completer<void> _stopCompleter;
|
||||
|
||||
Future<void> _ffiStop() async {
|
||||
_stopCompleter = Completer<void>();
|
||||
_childSendPort.send(_StopParam());
|
||||
return _stopCompleter.future;
|
||||
}
|
||||
}
|
||||
|
||||
class _Result {
|
||||
Exception? exception;
|
||||
|
||||
_Result();
|
||||
}
|
||||
|
||||
class _StartParam {
|
||||
final StartConfig cfg;
|
||||
|
||||
_StartParam({required this.cfg});
|
||||
}
|
||||
|
||||
class _StartResult extends _Result {
|
||||
int? port;
|
||||
|
||||
_StartResult();
|
||||
}
|
||||
|
||||
class _StopParam {}
|
||||
|
||||
class _StopResult extends _Result {
|
||||
_StopResult();
|
||||
}
|
||||
Reference in new issue
Block a user