mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
feat: add batched Rust-backed upload task
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:localsend_app/isolate/isolate.dart';
|
||||
@@ -6,8 +5,8 @@ import 'package:localsend_app/isolate/model/device.dart';
|
||||
import 'package:localsend_app/isolate/src/isolate/child/main.dart';
|
||||
import 'package:localsend_app/isolate/src/isolate/dto/send_to_isolate_data.dart';
|
||||
import 'package:localsend_app/isolate/src/task/upload/http_upload.dart';
|
||||
import 'package:localsend_app/isolate/util/stream.dart';
|
||||
import 'package:localsend_app/rust/api/http.dart';
|
||||
import 'package:localsend_app/util/native/channel/android_channel.dart';
|
||||
import 'package:localsend_app/util/rust.dart';
|
||||
import 'package:refena_flutter/refena_flutter.dart';
|
||||
import 'package:typed_isolates/typed_isolates.dart';
|
||||
@@ -42,6 +41,39 @@ class HttpUploadTask implements BaseHttpUploadTask {
|
||||
});
|
||||
}
|
||||
|
||||
class HttpUploadFile {
|
||||
final String remoteFileToken;
|
||||
final String fileId;
|
||||
final String? filePath;
|
||||
final List<int>? fileBytes;
|
||||
final int fileSize;
|
||||
|
||||
HttpUploadFile({
|
||||
required this.remoteFileToken,
|
||||
required this.fileId,
|
||||
required this.filePath,
|
||||
required this.fileBytes,
|
||||
required this.fileSize,
|
||||
});
|
||||
}
|
||||
|
||||
/// Uploads a list of files as one isolate task.
|
||||
///
|
||||
/// This task is intended to replace the file scheduling loop in the parent
|
||||
/// isolate. Files are uploaded sequentially and progress is reported across
|
||||
/// the complete list.
|
||||
class HttpUploadFilesTask implements BaseHttpUploadTask {
|
||||
final String? remoteSessionId;
|
||||
final List<HttpUploadFile> files;
|
||||
final Device device;
|
||||
|
||||
HttpUploadFilesTask({
|
||||
required this.remoteSessionId,
|
||||
required this.files,
|
||||
required this.device,
|
||||
});
|
||||
}
|
||||
|
||||
class HttpUploadCancelTask implements BaseHttpUploadTask {
|
||||
final int taskId;
|
||||
|
||||
@@ -61,8 +93,6 @@ abstract class UriContentStreamResolver {
|
||||
Stream<Uint8List> resolve(Uri uri);
|
||||
}
|
||||
|
||||
UriContentStreamResolver? _uriContentStreamResolver;
|
||||
|
||||
Future<void> setupHttpUploadIsolate(
|
||||
Stream<SendToIsolateData<IsolateTask<BaseHttpUploadTask>>> receiveFromMain,
|
||||
void Function(IsolateTaskStreamResult<double>) sendToMain,
|
||||
@@ -74,17 +104,33 @@ Future<void> setupHttpUploadIsolate(
|
||||
sendToMain: sendToMain,
|
||||
initialData: initialData,
|
||||
handler: (ref, task) async {
|
||||
final HttpUploadTask uploadTask;
|
||||
final String? remoteSessionId;
|
||||
final List<HttpUploadFile> files;
|
||||
final Device device;
|
||||
switch (task.data) {
|
||||
case HttpUploadSetContentStreamResolverTask task:
|
||||
final rootIsolateToken = ref.read(syncProvider).rootIsolateToken;
|
||||
task.resolver.init(
|
||||
rootIsolateToken: rootIsolateToken,
|
||||
);
|
||||
_uriContentStreamResolver = task.resolver;
|
||||
return;
|
||||
case HttpUploadTask task:
|
||||
uploadTask = task;
|
||||
remoteSessionId = task.remoteSessionId;
|
||||
files = [
|
||||
HttpUploadFile(
|
||||
remoteFileToken: task.remoteFileToken,
|
||||
fileId: task.fileId,
|
||||
filePath: task.filePath,
|
||||
fileBytes: task.fileBytes,
|
||||
fileSize: task.fileSize,
|
||||
),
|
||||
];
|
||||
device = task.device;
|
||||
break;
|
||||
case HttpUploadFilesTask task:
|
||||
remoteSessionId = task.remoteSessionId;
|
||||
files = task.files;
|
||||
device = task.device;
|
||||
break;
|
||||
case HttpUploadCancelTask task:
|
||||
final cancelToken = ref.read(_cancelTokenProvider)[task.taskId];
|
||||
@@ -93,37 +139,42 @@ Future<void> setupHttpUploadIsolate(
|
||||
return;
|
||||
}
|
||||
|
||||
final Stream<List<int>>? fileStream = uploadTask.filePath != null
|
||||
? _uriContentStreamResolver != null && uploadTask.filePath!.startsWith('content://')
|
||||
? _uriContentStreamResolver!.resolve(Uri.parse(uploadTask.filePath!))
|
||||
: File(uploadTask.filePath!).openRead()
|
||||
: null;
|
||||
|
||||
final (streamController, subscription) = fileStream?.digested() ?? (null, null);
|
||||
|
||||
try {
|
||||
final cancelToken = createCancellationToken();
|
||||
ref.read(_cancelTokenProvider).putIfAbsent(task.id, () => cancelToken);
|
||||
final totalSize = files.fold<int>(0, (sum, file) => sum + file.fileSize);
|
||||
var completedSize = 0;
|
||||
|
||||
await ref
|
||||
.read(httpUploadProvider)
|
||||
.upload(
|
||||
stream: streamController?.stream ?? Stream.fromIterable([uploadTask.fileBytes!]),
|
||||
contentLength: uploadTask.fileSize,
|
||||
target: uploadTask.device,
|
||||
remoteSessionId: uploadTask.remoteSessionId,
|
||||
fileId: uploadTask.fileId,
|
||||
token: uploadTask.remoteFileToken,
|
||||
onSendProgress: (progress) {
|
||||
sendToMain(
|
||||
IsolateTaskStreamResult.event(
|
||||
id: task.id,
|
||||
data: progress,
|
||||
),
|
||||
);
|
||||
},
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
for (final file in files) {
|
||||
final filePath = file.filePath;
|
||||
final isContentUri = filePath?.startsWith('content://') ?? false;
|
||||
final fileDescriptor = isContentUri ? await getFileDescriptorAndroid(uri: filePath!) : null;
|
||||
|
||||
await ref
|
||||
.read(httpUploadProvider)
|
||||
.upload(
|
||||
stream: filePath == null && file.fileBytes != null ? Stream.value(file.fileBytes!) : null,
|
||||
path: !isContentUri ? filePath : null,
|
||||
fileDescriptor: fileDescriptor,
|
||||
contentLength: file.fileSize,
|
||||
target: device,
|
||||
remoteSessionId: remoteSessionId,
|
||||
fileId: file.fileId,
|
||||
token: file.remoteFileToken,
|
||||
onSendProgress: (progress) {
|
||||
final totalProgress = totalSize == 0 ? 1.0 : (completedSize + progress * file.fileSize) / totalSize;
|
||||
sendToMain(
|
||||
IsolateTaskStreamResult.event(
|
||||
id: task.id,
|
||||
data: totalProgress,
|
||||
),
|
||||
);
|
||||
},
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
|
||||
completedSize += file.fileSize;
|
||||
}
|
||||
|
||||
sendToMain(
|
||||
IsolateTaskStreamResult.done(
|
||||
@@ -138,13 +189,7 @@ Future<void> setupHttpUploadIsolate(
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
// Close the stream if it is still open
|
||||
// ignore: unawaited_futures
|
||||
streamController?.close();
|
||||
|
||||
// Cancel the subscription if it is still open
|
||||
// ignore: unawaited_futures
|
||||
subscription?.cancel();
|
||||
ref.read(_cancelTokenProvider).remove(task.id);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -172,6 +172,42 @@ class IsolateHttpUploadAction extends ReduxActionWithResult<IsolateController, P
|
||||
}
|
||||
}
|
||||
|
||||
class IsolateHttpUploadFilesAction extends ReduxActionWithResult<IsolateController, ParentIsolateState, IsolateHttpUploadActionResult> {
|
||||
final int isolateIndex;
|
||||
final String? remoteSessionId;
|
||||
final List<HttpUploadFile> files;
|
||||
final Device device;
|
||||
|
||||
IsolateHttpUploadFilesAction({
|
||||
required this.isolateIndex,
|
||||
required this.remoteSessionId,
|
||||
required this.files,
|
||||
required this.device,
|
||||
});
|
||||
|
||||
@override
|
||||
(ParentIsolateState, IsolateHttpUploadActionResult) reduce() {
|
||||
final connection = state.httpUpload[isolateIndex];
|
||||
final taskId = IdProvider.instance.getNextId();
|
||||
final progress = connection.sendWrappedTaskAndListenStream(
|
||||
task: HttpUploadFilesTask(
|
||||
remoteSessionId: remoteSessionId,
|
||||
files: files,
|
||||
device: device,
|
||||
),
|
||||
taskId: taskId,
|
||||
);
|
||||
|
||||
return (
|
||||
state,
|
||||
IsolateHttpUploadActionResult(
|
||||
taskId: taskId,
|
||||
progress: progress,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class IsolateHttpUploadCancelAction extends ReduxAction<IsolateController, ParentIsolateState> {
|
||||
final int isolateIndex;
|
||||
final int taskId;
|
||||
|
||||
@@ -16,7 +16,9 @@ class HttpUploadService {
|
||||
HttpUploadService(this._client);
|
||||
|
||||
Future<void> upload({
|
||||
required Stream<List<int>> stream,
|
||||
required Stream<List<int>>? stream,
|
||||
required String? path,
|
||||
required int? fileDescriptor,
|
||||
required int contentLength,
|
||||
required Device target,
|
||||
required String? remoteSessionId,
|
||||
@@ -25,25 +27,29 @@ class HttpUploadService {
|
||||
required void Function(double progress) onSendProgress,
|
||||
required RsCancellationToken cancelToken,
|
||||
}) async {
|
||||
final (sink, receiver) = await createStream();
|
||||
final (sink, receiver) = stream != null ? await createStream() : (null, null);
|
||||
|
||||
final uploadFuture = _client.upload(
|
||||
protocol: target.getProtocolType(),
|
||||
ip: target.ip!,
|
||||
port: target.port,
|
||||
publicKey: null,
|
||||
sessionId: remoteSessionId ?? '',
|
||||
fileId: fileId,
|
||||
token: token,
|
||||
binary: receiver,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
final uploadFuture = _client
|
||||
.upload(
|
||||
protocol: target.getProtocolType(),
|
||||
ip: target.ip!,
|
||||
port: target.port,
|
||||
publicKey: null,
|
||||
sessionId: remoteSessionId ?? '',
|
||||
fileId: fileId,
|
||||
token: token,
|
||||
binary: receiver,
|
||||
path: path,
|
||||
fileDescriptor: fileDescriptor,
|
||||
contentLength: BigInt.from(contentLength),
|
||||
cancelToken: cancelToken,
|
||||
)
|
||||
.forEach(onSendProgress);
|
||||
|
||||
try {
|
||||
int sent = 0;
|
||||
await for (final chunk in stream) {
|
||||
await for (final chunk in stream ?? const Stream<List<int>>.empty()) {
|
||||
try {
|
||||
await sink.add(data: chunk);
|
||||
await sink!.add(data: chunk);
|
||||
} catch (_) {
|
||||
// The Rust side dropped the receiver, i.e. the upload request already
|
||||
// ended (e.g. rejected by the receiver or cancelled).
|
||||
@@ -51,10 +57,8 @@ class HttpUploadService {
|
||||
await uploadFuture;
|
||||
rethrow;
|
||||
}
|
||||
sent += chunk.length;
|
||||
onSendProgress(sent / contentLength);
|
||||
}
|
||||
sink.close();
|
||||
sink?.close();
|
||||
} catch (e) {
|
||||
// The source stream failed, so the upload request must be aborted.
|
||||
// [e] is the root cause, thus the error of the upload request is swallowed.
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:localsend_app/rust/frb_generated.dart';
|
||||
|
||||
part 'http.freezed.dart';
|
||||
|
||||
// These functions are ignored because they are not marked as `pub`: `resolve_file_content`
|
||||
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `from`
|
||||
|
||||
RsHttpClient createClient({
|
||||
@@ -57,7 +58,7 @@ abstract class RsHttpClient implements RustOpaqueInterface {
|
||||
required RegisterDto payload,
|
||||
});
|
||||
|
||||
Future<void> upload({
|
||||
Stream<double> upload({
|
||||
required ProtocolType protocol,
|
||||
required String ip,
|
||||
required int port,
|
||||
@@ -65,7 +66,10 @@ abstract class RsHttpClient implements RustOpaqueInterface {
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required String token,
|
||||
required Dart2RustStreamReceiver binary,
|
||||
Dart2RustStreamReceiver? binary,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
required BigInt contentLength,
|
||||
required RsCancellationToken cancelToken,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'package:localsend_app/rust/frb_generated.dart';
|
||||
|
||||
Future<(Dart2RustStreamSink, Dart2RustStreamReceiver)> createStream() => RustLib.instance.api.crateApiStreamCreateStream();
|
||||
|
||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamReceiver>>
|
||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Dart2RustStreamReceiver>>
|
||||
abstract class Dart2RustStreamReceiver implements RustOpaqueInterface {}
|
||||
|
||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamSink>>
|
||||
|
||||
+249
-50
@@ -145,7 +145,7 @@ abstract class RustLibApi extends BaseApi {
|
||||
required RegisterDto payload,
|
||||
});
|
||||
|
||||
Future<void> crateApiHttpRsHttpClientUpload({
|
||||
Stream<double> crateApiHttpRsHttpClientUpload({
|
||||
required RsHttpClient that,
|
||||
required ProtocolType protocol,
|
||||
required String ip,
|
||||
@@ -154,7 +154,10 @@ abstract class RustLibApi extends BaseApi {
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required String token,
|
||||
required Dart2RustStreamReceiver binary,
|
||||
Dart2RustStreamReceiver? binary,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
required BigInt contentLength,
|
||||
required RsCancellationToken cancelToken,
|
||||
});
|
||||
|
||||
@@ -725,7 +728,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiHttpRsHttpClientUpload({
|
||||
Stream<double> crateApiHttpRsHttpClientUpload({
|
||||
required RsHttpClient that,
|
||||
required ProtocolType protocol,
|
||||
required String ip,
|
||||
@@ -734,65 +737,81 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required String token,
|
||||
required Dart2RustStreamReceiver binary,
|
||||
Dart2RustStreamReceiver? binary,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
required BigInt contentLength,
|
||||
required RsCancellationToken cancelToken,
|
||||
}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpClient(
|
||||
final sink = RustStreamSink<double>();
|
||||
unawaited(
|
||||
handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpClient(
|
||||
that,
|
||||
serializer,
|
||||
);
|
||||
sse_encode_StreamSink_f_64_Sse(sink, serializer);
|
||||
sse_encode_protocol_type(protocol, serializer);
|
||||
sse_encode_String(ip, serializer);
|
||||
sse_encode_u_16(port, serializer);
|
||||
sse_encode_opt_String(publicKey, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_String(fileId, serializer);
|
||||
sse_encode_String(token, serializer);
|
||||
sse_encode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
binary,
|
||||
serializer,
|
||||
);
|
||||
sse_encode_opt_String(path, serializer);
|
||||
sse_encode_opt_box_autoadd_i_32(fileDescriptor, serializer);
|
||||
sse_encode_u_64(contentLength, serializer);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsCancellationToken(
|
||||
cancelToken,
|
||||
serializer,
|
||||
);
|
||||
pdeCallFfi(
|
||||
generalizedFrbRustBinding,
|
||||
serializer,
|
||||
funcId: 10,
|
||||
port: port_,
|
||||
);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
decodeErrorData: sse_decode_rs_http_client_error,
|
||||
),
|
||||
constMeta: kCrateApiHttpRsHttpClientUploadConstMeta,
|
||||
argValues: [
|
||||
that,
|
||||
serializer,
|
||||
);
|
||||
sse_encode_protocol_type(protocol, serializer);
|
||||
sse_encode_String(ip, serializer);
|
||||
sse_encode_u_16(port, serializer);
|
||||
sse_encode_opt_String(publicKey, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_String(fileId, serializer);
|
||||
sse_encode_String(token, serializer);
|
||||
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
sink,
|
||||
protocol,
|
||||
ip,
|
||||
port,
|
||||
publicKey,
|
||||
sessionId,
|
||||
fileId,
|
||||
token,
|
||||
binary,
|
||||
serializer,
|
||||
);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsCancellationToken(
|
||||
path,
|
||||
fileDescriptor,
|
||||
contentLength,
|
||||
cancelToken,
|
||||
serializer,
|
||||
);
|
||||
pdeCallFfi(
|
||||
generalizedFrbRustBinding,
|
||||
serializer,
|
||||
funcId: 10,
|
||||
port: port_,
|
||||
);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
decodeErrorData: sse_decode_rs_http_client_error,
|
||||
],
|
||||
apiImpl: this,
|
||||
),
|
||||
constMeta: kCrateApiHttpRsHttpClientUploadConstMeta,
|
||||
argValues: [
|
||||
that,
|
||||
protocol,
|
||||
ip,
|
||||
port,
|
||||
publicKey,
|
||||
sessionId,
|
||||
fileId,
|
||||
token,
|
||||
binary,
|
||||
cancelToken,
|
||||
],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
return sink.stream;
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiHttpRsHttpClientUploadConstMeta => const TaskConstMeta(
|
||||
debugName: 'RsHttpClient_upload',
|
||||
argNames: [
|
||||
'that',
|
||||
'sink',
|
||||
'protocol',
|
||||
'ip',
|
||||
'port',
|
||||
@@ -801,6 +820,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
'fileId',
|
||||
'token',
|
||||
'binary',
|
||||
'path',
|
||||
'fileDescriptor',
|
||||
'contentLength',
|
||||
'cancelToken',
|
||||
],
|
||||
);
|
||||
@@ -2001,6 +2023,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> dco_decode_StreamSink_f_64_Sse(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> dco_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
dynamic raw,
|
||||
@@ -2049,6 +2077,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw as bool;
|
||||
}
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver dco_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
raw,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
ClientInfo dco_decode_box_autoadd_client_info(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2081,6 +2119,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return dco_decode_file_metadata(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
int dco_decode_box_autoadd_i_32(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return raw as int;
|
||||
}
|
||||
|
||||
@protected
|
||||
PinConfig dco_decode_box_autoadd_pin_config(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2183,6 +2227,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
double dco_decode_f_64(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return raw as double;
|
||||
}
|
||||
|
||||
@protected
|
||||
FileDto dco_decode_file_dto(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2287,6 +2337,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw == null ? null : dco_decode_String(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
dco_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return raw == null
|
||||
? null
|
||||
: dco_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
raw,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
DeviceType? dco_decode_opt_box_autoadd_device_type(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2307,6 +2370,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw == null ? null : dco_decode_box_autoadd_file_metadata(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
int? dco_decode_opt_box_autoadd_i_32(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return raw == null ? null : dco_decode_box_autoadd_i_32(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
PinConfig? dco_decode_opt_box_autoadd_pin_config(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2987,6 +3056,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
throw UnimplementedError('Unreachable ()');
|
||||
}
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> sse_decode_StreamSink_f_64_Sse(
|
||||
SseDeserializer deserializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
throw UnimplementedError('Unreachable ()');
|
||||
}
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> sse_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
SseDeserializer deserializer,
|
||||
@@ -3039,6 +3116,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return deserializer.buffer.getUint8() != 0;
|
||||
}
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver sse_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
return (sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
deserializer,
|
||||
));
|
||||
}
|
||||
|
||||
@protected
|
||||
ClientInfo sse_decode_box_autoadd_client_info(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -3075,6 +3162,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return (sse_decode_file_metadata(deserializer));
|
||||
}
|
||||
|
||||
@protected
|
||||
int sse_decode_box_autoadd_i_32(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
return (sse_decode_i_32(deserializer));
|
||||
}
|
||||
|
||||
@protected
|
||||
PinConfig sse_decode_box_autoadd_pin_config(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -3190,6 +3283,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return ExpectingPublicKey(publicKey: var_publicKey, kind: var_kind);
|
||||
}
|
||||
|
||||
@protected
|
||||
double sse_decode_f_64(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
return deserializer.buffer.getFloat64();
|
||||
}
|
||||
|
||||
@protected
|
||||
FileDto sse_decode_file_dto(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -3337,6 +3436,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
sse_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
if (sse_decode_bool(deserializer)) {
|
||||
return (sse_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
deserializer,
|
||||
));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
DeviceType? sse_decode_opt_box_autoadd_device_type(
|
||||
SseDeserializer deserializer,
|
||||
@@ -3376,6 +3491,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
if (sse_decode_bool(deserializer)) {
|
||||
return (sse_decode_box_autoadd_i_32(deserializer));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
PinConfig? sse_decode_opt_box_autoadd_pin_config(
|
||||
SseDeserializer deserializer,
|
||||
@@ -4152,6 +4278,23 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_f_64_Sse(
|
||||
RustStreamSink<double> self,
|
||||
SseSerializer serializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_String(
|
||||
self.setupAndSerialize(
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_f_64,
|
||||
decodeErrorData: sse_decode_AnyhowException,
|
||||
),
|
||||
),
|
||||
serializer,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
RustStreamSink<Uint8List> self,
|
||||
@@ -4238,6 +4381,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
serializer.buffer.putUint8(self ? 1 : 0);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver self,
|
||||
SseSerializer serializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
self,
|
||||
serializer,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_client_info(
|
||||
ClientInfo self,
|
||||
@@ -4283,6 +4438,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_file_metadata(self, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_i_32(self, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_pin_config(
|
||||
PinConfig self,
|
||||
@@ -4392,6 +4553,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_String(self.kind, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_f_64(double self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
serializer.buffer.putFloat64(self);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_file_dto(FileDto self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4525,6 +4692,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver? self,
|
||||
SseSerializer serializer,
|
||||
) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
sse_encode_bool(self != null, serializer);
|
||||
if (self != null) {
|
||||
sse_encode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
self,
|
||||
serializer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_device_type(
|
||||
DeviceType? self,
|
||||
@@ -4564,6 +4747,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
sse_encode_bool(self != null, serializer);
|
||||
if (self != null) {
|
||||
sse_encode_box_autoadd_i_32(self, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_pin_config(
|
||||
PinConfig? self,
|
||||
@@ -5057,7 +5250,7 @@ class RsHttpClientImpl extends RustOpaque implements RsHttpClient {
|
||||
payload: payload,
|
||||
);
|
||||
|
||||
Future<void> upload({
|
||||
Stream<double> upload({
|
||||
required ProtocolType protocol,
|
||||
required String ip,
|
||||
required int port,
|
||||
@@ -5065,7 +5258,10 @@ class RsHttpClientImpl extends RustOpaque implements RsHttpClient {
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required String token,
|
||||
required Dart2RustStreamReceiver binary,
|
||||
Dart2RustStreamReceiver? binary,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
required BigInt contentLength,
|
||||
required RsCancellationToken cancelToken,
|
||||
}) => RustLib.instance.api.crateApiHttpRsHttpClientUpload(
|
||||
that: this,
|
||||
@@ -5077,6 +5273,9 @@ class RsHttpClientImpl extends RustOpaque implements RsHttpClient {
|
||||
fileId: fileId,
|
||||
token: token,
|
||||
binary: binary,
|
||||
path: path,
|
||||
fileDescriptor: fileDescriptor,
|
||||
contentLength: contentLength,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -213,6 +213,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> dco_decode_StreamSink_f_64_Sse(dynamic raw);
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> dco_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
dynamic raw,
|
||||
@@ -240,6 +243,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
bool dco_decode_bool(dynamic raw);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver dco_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
ClientInfo dco_decode_box_autoadd_client_info(dynamic raw);
|
||||
|
||||
@@ -257,6 +265,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
FileMetadata dco_decode_box_autoadd_file_metadata(dynamic raw);
|
||||
|
||||
@protected
|
||||
int dco_decode_box_autoadd_i_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
PinConfig dco_decode_box_autoadd_pin_config(dynamic raw);
|
||||
|
||||
@@ -299,6 +310,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
ExpectingPublicKey dco_decode_expecting_public_key(dynamic raw);
|
||||
|
||||
@protected
|
||||
double dco_decode_f_64(dynamic raw);
|
||||
|
||||
@protected
|
||||
FileDto dco_decode_file_dto(dynamic raw);
|
||||
|
||||
@@ -341,6 +355,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String? dco_decode_opt_String(dynamic raw);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
dco_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
DeviceType? dco_decode_opt_box_autoadd_device_type(dynamic raw);
|
||||
|
||||
@@ -352,6 +372,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
FileMetadata? dco_decode_opt_box_autoadd_file_metadata(dynamic raw);
|
||||
|
||||
@protected
|
||||
int? dco_decode_opt_box_autoadd_i_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
PinConfig? dco_decode_opt_box_autoadd_pin_config(dynamic raw);
|
||||
|
||||
@@ -595,6 +618,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> sse_decode_StreamSink_f_64_Sse(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> sse_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
SseDeserializer deserializer,
|
||||
@@ -624,6 +652,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
bool sse_decode_bool(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver sse_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
ClientInfo sse_decode_box_autoadd_client_info(SseDeserializer deserializer);
|
||||
|
||||
@@ -645,6 +678,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
int sse_decode_box_autoadd_i_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
PinConfig sse_decode_box_autoadd_pin_config(SseDeserializer deserializer);
|
||||
|
||||
@@ -695,6 +731,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
double sse_decode_f_64(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
FileDto sse_decode_file_dto(SseDeserializer deserializer);
|
||||
|
||||
@@ -743,6 +782,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String? sse_decode_opt_String(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
sse_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
DeviceType? sse_decode_opt_box_autoadd_device_type(
|
||||
SseDeserializer deserializer,
|
||||
@@ -758,6 +803,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
PinConfig? sse_decode_opt_box_autoadd_pin_config(
|
||||
SseDeserializer deserializer,
|
||||
@@ -1067,6 +1115,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_f_64_Sse(
|
||||
RustStreamSink<double> self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
RustStreamSink<Uint8List> self,
|
||||
@@ -1100,6 +1154,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_client_info(
|
||||
ClientInfo self,
|
||||
@@ -1130,6 +1190,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_pin_config(
|
||||
PinConfig self,
|
||||
@@ -1193,6 +1256,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_f_64(double self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_file_dto(FileDto self, SseSerializer serializer);
|
||||
|
||||
@@ -1250,6 +1316,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_opt_String(String? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver? self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_device_type(
|
||||
DeviceType? self,
|
||||
@@ -1268,6 +1340,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_pin_config(
|
||||
PinConfig? self,
|
||||
|
||||
@@ -215,6 +215,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> dco_decode_StreamSink_f_64_Sse(dynamic raw);
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> dco_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
dynamic raw,
|
||||
@@ -242,6 +245,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
bool dco_decode_bool(dynamic raw);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver dco_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
ClientInfo dco_decode_box_autoadd_client_info(dynamic raw);
|
||||
|
||||
@@ -259,6 +267,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
FileMetadata dco_decode_box_autoadd_file_metadata(dynamic raw);
|
||||
|
||||
@protected
|
||||
int dco_decode_box_autoadd_i_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
PinConfig dco_decode_box_autoadd_pin_config(dynamic raw);
|
||||
|
||||
@@ -301,6 +312,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
ExpectingPublicKey dco_decode_expecting_public_key(dynamic raw);
|
||||
|
||||
@protected
|
||||
double dco_decode_f_64(dynamic raw);
|
||||
|
||||
@protected
|
||||
FileDto dco_decode_file_dto(dynamic raw);
|
||||
|
||||
@@ -343,6 +357,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String? dco_decode_opt_String(dynamic raw);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
dco_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
dynamic raw,
|
||||
);
|
||||
|
||||
@protected
|
||||
DeviceType? dco_decode_opt_box_autoadd_device_type(dynamic raw);
|
||||
|
||||
@@ -354,6 +374,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
FileMetadata? dco_decode_opt_box_autoadd_file_metadata(dynamic raw);
|
||||
|
||||
@protected
|
||||
int? dco_decode_opt_box_autoadd_i_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
PinConfig? dco_decode_opt_box_autoadd_pin_config(dynamic raw);
|
||||
|
||||
@@ -597,6 +620,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<double> sse_decode_StreamSink_f_64_Sse(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
RustStreamSink<Uint8List> sse_decode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
SseDeserializer deserializer,
|
||||
@@ -626,6 +654,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
bool sse_decode_bool(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver sse_decode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
ClientInfo sse_decode_box_autoadd_client_info(SseDeserializer deserializer);
|
||||
|
||||
@@ -647,6 +680,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
int sse_decode_box_autoadd_i_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
PinConfig sse_decode_box_autoadd_pin_config(SseDeserializer deserializer);
|
||||
|
||||
@@ -697,6 +733,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
double sse_decode_f_64(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
FileDto sse_decode_file_dto(SseDeserializer deserializer);
|
||||
|
||||
@@ -745,6 +784,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
String? sse_decode_opt_String(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
Dart2RustStreamReceiver?
|
||||
sse_decode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
DeviceType? sse_decode_opt_box_autoadd_device_type(
|
||||
SseDeserializer deserializer,
|
||||
@@ -760,6 +805,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseDeserializer deserializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
PinConfig? sse_decode_opt_box_autoadd_pin_config(
|
||||
SseDeserializer deserializer,
|
||||
@@ -1069,6 +1117,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_f_64_Sse(
|
||||
RustStreamSink<double> self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_StreamSink_list_prim_u_8_strict_Sse(
|
||||
RustStreamSink<Uint8List> self,
|
||||
@@ -1102,6 +1156,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_bool(bool self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_client_info(
|
||||
ClientInfo self,
|
||||
@@ -1132,6 +1192,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_pin_config(
|
||||
PinConfig self,
|
||||
@@ -1195,6 +1258,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_f_64(double self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_file_dto(FileDto self, SseSerializer serializer);
|
||||
|
||||
@@ -1252,6 +1318,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_opt_String(String? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
Dart2RustStreamReceiver? self,
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_device_type(
|
||||
DeviceType? self,
|
||||
@@ -1270,6 +1342,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
SseSerializer serializer,
|
||||
);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_pin_config(
|
||||
PinConfig? self,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::api::stream;
|
||||
use crate::frb_generated::StreamSink;
|
||||
use flutter_rust_bridge::frb;
|
||||
pub use localsend::http::client::{ClientError, LsHttpClientVersion};
|
||||
pub use localsend::http::dto::{
|
||||
@@ -86,6 +87,7 @@ impl RsHttpClient {
|
||||
|
||||
pub async fn upload(
|
||||
&self,
|
||||
sink: StreamSink<f64>,
|
||||
protocol: ProtocolType,
|
||||
ip: &str,
|
||||
port: u16,
|
||||
@@ -93,9 +95,22 @@ impl RsHttpClient {
|
||||
session_id: &str,
|
||||
file_id: &str,
|
||||
token: &str,
|
||||
binary: stream::Dart2RustStreamReceiver,
|
||||
binary: Option<stream::Dart2RustStreamReceiver>,
|
||||
path: Option<String>,
|
||||
file_descriptor: Option<i32>,
|
||||
content_length: u64,
|
||||
cancel_token: &RsCancellationToken,
|
||||
) -> Result<(), RsHttpClientError> {
|
||||
let content = resolve_file_content(binary, path, file_descriptor)?;
|
||||
let progress = move |sent| {
|
||||
let progress = if content_length == 0 {
|
||||
1.0
|
||||
} else {
|
||||
(sent as f64 / content_length as f64).min(1.0)
|
||||
};
|
||||
let _ = sink.add(progress);
|
||||
};
|
||||
|
||||
self.inner
|
||||
.upload(
|
||||
protocol,
|
||||
@@ -105,7 +120,8 @@ impl RsHttpClient {
|
||||
session_id,
|
||||
file_id,
|
||||
token,
|
||||
localsend::model::transfer::FileContent::Stream(binary.receiver),
|
||||
content,
|
||||
progress,
|
||||
cancel_token.inner.clone(),
|
||||
)
|
||||
.await
|
||||
@@ -130,6 +146,35 @@ impl RsHttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_file_content(
|
||||
binary: Option<stream::Dart2RustStreamReceiver>,
|
||||
path: Option<String>,
|
||||
file_descriptor: Option<i32>,
|
||||
) -> Result<localsend::model::transfer::FileContent, RsHttpClientError> {
|
||||
match (binary, path, file_descriptor) {
|
||||
(Some(binary), None, None) => Ok(localsend::model::transfer::FileContent::Stream(
|
||||
binary.receiver,
|
||||
)),
|
||||
(None, Some(path), None) => Ok(localsend::model::transfer::FileContent::Path(path.into())),
|
||||
(None, None, Some(file_descriptor)) => {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
Ok(localsend::model::transfer::FileContent::Fd(file_descriptor))
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = file_descriptor;
|
||||
Err(RsHttpClientError::Other(
|
||||
"File descriptors are only supported on Android".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err(RsHttpClientError::Other(
|
||||
"Exactly one upload content source must be provided".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RsHttpClientError {
|
||||
StatusCode {
|
||||
status: u16,
|
||||
|
||||
@@ -633,6 +633,10 @@ fn wire__crate__api__http__RsHttpClient_upload_impl(
|
||||
let api_that = <RustOpaqueMoi<
|
||||
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpClient>,
|
||||
>>::sse_decode(&mut deserializer);
|
||||
let api_sink =
|
||||
<StreamSink<f64, flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(
|
||||
&mut deserializer,
|
||||
);
|
||||
let api_protocol = <crate::api::model::ProtocolType>::sse_decode(&mut deserializer);
|
||||
let api_ip = <String>::sse_decode(&mut deserializer);
|
||||
let api_port = <u16>::sse_decode(&mut deserializer);
|
||||
@@ -640,7 +644,10 @@ fn wire__crate__api__http__RsHttpClient_upload_impl(
|
||||
let api_session_id = <String>::sse_decode(&mut deserializer);
|
||||
let api_file_id = <String>::sse_decode(&mut deserializer);
|
||||
let api_token = <String>::sse_decode(&mut deserializer);
|
||||
let api_binary = <Dart2RustStreamReceiver>::sse_decode(&mut deserializer);
|
||||
let api_binary = <Option<Dart2RustStreamReceiver>>::sse_decode(&mut deserializer);
|
||||
let api_path = <Option<String>>::sse_decode(&mut deserializer);
|
||||
let api_file_descriptor = <Option<i32>>::sse_decode(&mut deserializer);
|
||||
let api_content_length = <u64>::sse_decode(&mut deserializer);
|
||||
let api_cancel_token = <RustOpaqueMoi<
|
||||
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsCancellationToken>,
|
||||
>>::sse_decode(&mut deserializer);
|
||||
@@ -680,6 +687,7 @@ fn wire__crate__api__http__RsHttpClient_upload_impl(
|
||||
let api_cancel_token_guard = api_cancel_token_guard.unwrap();
|
||||
let output_ok = crate::api::http::RsHttpClient::upload(
|
||||
&*api_that_guard,
|
||||
api_sink,
|
||||
api_protocol,
|
||||
&api_ip,
|
||||
api_port,
|
||||
@@ -688,6 +696,9 @@ fn wire__crate__api__http__RsHttpClient_upload_impl(
|
||||
&api_file_id,
|
||||
&api_token,
|
||||
api_binary,
|
||||
api_path,
|
||||
api_file_descriptor,
|
||||
api_content_length,
|
||||
&*api_cancel_token_guard,
|
||||
)
|
||||
.await?;
|
||||
@@ -2323,6 +2334,14 @@ impl SseDecode for StreamSink<RTCFileReceiver, flutter_rust_bridge::for_generate
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for StreamSink<f64, flutter_rust_bridge::for_generated::SseCodec> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
let mut inner = <String>::sse_decode(deserializer);
|
||||
return StreamSink::deserialize(inner);
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for StreamSink<Vec<u8>, flutter_rust_bridge::for_generated::SseCodec> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -2452,6 +2471,13 @@ impl SseDecode for crate::api::webrtc::ExpectingPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for f64 {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
deserializer.cursor.read_f64::<NativeEndian>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for crate::api::model::FileDto {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -2609,6 +2635,17 @@ impl SseDecode for Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<Dart2RustStreamReceiver> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
if (<bool>::sse_decode(deserializer)) {
|
||||
return Some(<Dart2RustStreamReceiver>::sse_decode(deserializer));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<crate::api::model::DeviceType> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -2644,6 +2681,17 @@ impl SseDecode for Option<crate::api::model::FileMetadata> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<i32> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
if (<bool>::sse_decode(deserializer)) {
|
||||
return Some(<i32>::sse_decode(deserializer));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<crate::api::webrtc::PinConfig> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -4147,6 +4195,13 @@ impl SseEncode for StreamSink<RTCFileReceiver, flutter_rust_bridge::for_generate
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for StreamSink<f64, flutter_rust_bridge::for_generated::SseCodec> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
unimplemented!("")
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for StreamSink<Vec<u8>, flutter_rust_bridge::for_generated::SseCodec> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
@@ -4255,6 +4310,13 @@ impl SseEncode for crate::api::webrtc::ExpectingPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for f64 {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
serializer.cursor.write_f64::<NativeEndian>(self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for crate::api::model::FileDto {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
@@ -4387,6 +4449,16 @@ impl SseEncode for Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<Dart2RustStreamReceiver> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
<bool>::sse_encode(self.is_some(), serializer);
|
||||
if let Some(value) = self {
|
||||
<Dart2RustStreamReceiver>::sse_encode(value, serializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<crate::api::model::DeviceType> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
@@ -4417,6 +4489,16 @@ impl SseEncode for Option<crate::api::model::FileMetadata> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<i32> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
<bool>::sse_encode(self.is_some(), serializer);
|
||||
if let Some(value) = self {
|
||||
<i32>::sse_encode(value, serializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<crate::api::webrtc::PinConfig> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
@@ -4770,14 +4852,14 @@ mod io {
|
||||
pub extern "C" fn frbgen_localsend_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
ptr: *const std::ffi::c_void,
|
||||
) {
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamReceiver>>::increment_strong_count(ptr as _);
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Dart2RustStreamReceiver>>::increment_strong_count(ptr as _);
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn frbgen_localsend_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
ptr: *const std::ffi::c_void,
|
||||
) {
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamReceiver>>::decrement_strong_count(ptr as _);
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Dart2RustStreamReceiver>>::decrement_strong_count(ptr as _);
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -4923,14 +5005,14 @@ mod web {
|
||||
pub fn rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
ptr: *const std::ffi::c_void,
|
||||
) {
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamReceiver>>::increment_strong_count(ptr as _);
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Dart2RustStreamReceiver>>::increment_strong_count(ptr as _);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDart2RustStreamReceiver(
|
||||
ptr: *const std::ffi::c_void,
|
||||
) {
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Dart2RustStreamReceiver>>::decrement_strong_count(ptr as _);
|
||||
MoiArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner< Dart2RustStreamReceiver>>::decrement_strong_count(ptr as _);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import 'dart:async' as _i4;
|
||||
|
||||
import 'package:flutter/material.dart' as _i8;
|
||||
import 'package:localsend_app/gen/strings.g.dart' as _i10;
|
||||
import 'package:localsend_app/isolate/model/device.dart' as _i12;
|
||||
import 'package:localsend_app/isolate/model/stored_security_context.dart' as _i2;
|
||||
import 'package:localsend_app/gen/strings.g.dart' as _i10;
|
||||
import 'package:localsend_app/model/persistence/color_mode.dart' as _i9;
|
||||
import 'package:localsend_app/model/persistence/favorite_device.dart' as _i6;
|
||||
import 'package:localsend_app/model/persistence/receive_history_entry.dart' as _i5;
|
||||
|
||||
@@ -114,20 +114,23 @@ impl LsHttpClient {
|
||||
file_id: &str,
|
||||
token: &str,
|
||||
content: model::transfer::FileContent,
|
||||
progress: impl Fn(u64) + Send + 'static,
|
||||
cancel: tokio_util::sync::CancellationToken,
|
||||
) -> Result<(), ClientError> {
|
||||
match self {
|
||||
LsHttpClient::V2(client) => {
|
||||
client
|
||||
.upload(
|
||||
protocol, ip, port, public_key, session_id, file_id, token, content, cancel,
|
||||
protocol, ip, port, public_key, session_id, file_id, token, content,
|
||||
progress, cancel,
|
||||
)
|
||||
.await
|
||||
}
|
||||
LsHttpClient::V3(client) => {
|
||||
client
|
||||
.upload(
|
||||
protocol, ip, port, public_key, session_id, file_id, token, content, cancel,
|
||||
protocol, ip, port, public_key, session_id, file_id, token, content,
|
||||
progress, cancel,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ impl LsHttpClientV2 {
|
||||
/// * `file_id` - File ID to upload
|
||||
/// * `token` - File-specific token from prepare_upload
|
||||
/// * `content` - The file content to upload (a chunk stream or a raw file descriptor)
|
||||
/// * `progress` - Called with the cumulative number of bytes read for the upload
|
||||
/// * `cancel` - Cancellation token; cancelling it aborts the upload with [`ClientError::Cancelled`]
|
||||
///
|
||||
/// # Errors
|
||||
@@ -217,6 +218,7 @@ impl LsHttpClientV2 {
|
||||
file_id: &str,
|
||||
token: &str,
|
||||
content: model::transfer::FileContent,
|
||||
progress: impl Fn(u64) + Send + 'static,
|
||||
cancel: CancellationToken,
|
||||
) -> Result<(), ClientError> {
|
||||
let url = TargetUrl {
|
||||
@@ -233,7 +235,12 @@ impl LsHttpClientV2 {
|
||||
}
|
||||
.to_string();
|
||||
|
||||
let stream = ReceiverStream::new(content.into_receiver()).map(Ok::<Bytes, anyhow::Error>);
|
||||
let mut sent = 0_u64;
|
||||
let stream = ReceiverStream::new(content.into_receiver()).map(move |chunk| {
|
||||
sent += chunk.len() as u64;
|
||||
progress(sent);
|
||||
Ok::<Bytes, anyhow::Error>(chunk)
|
||||
});
|
||||
let body = reqwest::Body::wrap_stream(stream);
|
||||
|
||||
let res = tokio::select! {
|
||||
|
||||
@@ -187,6 +187,8 @@ impl LsHttpClientV3 {
|
||||
|
||||
/// Uploads a file to the server.
|
||||
///
|
||||
/// `progress` is called with the cumulative number of bytes read for the upload.
|
||||
///
|
||||
/// `cancel` is a cancellation token; cancelling it aborts the upload with
|
||||
/// [`ClientError::Cancelled`].
|
||||
pub async fn upload(
|
||||
@@ -199,6 +201,7 @@ impl LsHttpClientV3 {
|
||||
file_id: &str,
|
||||
token: &str,
|
||||
content: model::transfer::FileContent,
|
||||
progress: impl Fn(u64) + Send + 'static,
|
||||
cancel: CancellationToken,
|
||||
) -> Result<(), ClientError> {
|
||||
let send = self
|
||||
@@ -219,8 +222,12 @@ impl LsHttpClientV3 {
|
||||
.to_string(),
|
||||
)
|
||||
.body({
|
||||
let stream =
|
||||
ReceiverStream::new(content.into_receiver()).map(Ok::<Bytes, anyhow::Error>);
|
||||
let mut sent = 0_u64;
|
||||
let stream = ReceiverStream::new(content.into_receiver()).map(move |chunk| {
|
||||
sent += chunk.len() as u64;
|
||||
progress(sent);
|
||||
Ok::<Bytes, anyhow::Error>(chunk)
|
||||
});
|
||||
reqwest::Body::wrap_stream(stream)
|
||||
})
|
||||
.send();
|
||||
|
||||
@@ -11,7 +11,7 @@ use localsend::http::state::ClientInfo;
|
||||
use localsend::model::transfer::{FileContent, FileDto};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicU16, Ordering};
|
||||
use std::sync::atomic::{AtomicU16, AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{mpsc, oneshot, Mutex};
|
||||
@@ -209,6 +209,7 @@ async fn upload_bytes(
|
||||
) -> Result<(), ClientError> {
|
||||
let (tx, rx) = mpsc::channel::<Bytes>(4);
|
||||
let chunks: Vec<Vec<u8>> = bytes.chunks(1024).map(|chunk| chunk.to_vec()).collect();
|
||||
let sent = Arc::new(AtomicU64::new(0));
|
||||
tokio::spawn(async move {
|
||||
for chunk in chunks {
|
||||
if tx.send(Bytes::from(chunk)).await.is_err() {
|
||||
@@ -217,7 +218,8 @@ async fn upload_bytes(
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
let progress = sent.clone();
|
||||
let result = client
|
||||
.upload(
|
||||
ProtocolType::Http,
|
||||
"127.0.0.1",
|
||||
@@ -227,9 +229,18 @@ async fn upload_bytes(
|
||||
file_id,
|
||||
token,
|
||||
FileContent::Stream(rx),
|
||||
move |bytes_sent| {
|
||||
progress.store(bytes_sent, Ordering::Relaxed);
|
||||
},
|
||||
CancellationToken::new(),
|
||||
)
|
||||
.await
|
||||
.await;
|
||||
|
||||
if result.is_ok() {
|
||||
assert_eq!(sent.load(Ordering::Relaxed), bytes.len() as u64);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn assert_status(result: Result<impl Sized, ClientError>, expected_status: u16) {
|
||||
|
||||
Reference in New Issue
Block a user