mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
feat: add web send and /show bindings
This commit is contained in:
@@ -20,8 +20,18 @@ class HttpServerStartTask implements BaseHttpServerTask {
|
||||
/// Optional PIN that senders must provide to start an upload session.
|
||||
final String? pin;
|
||||
|
||||
/// Enables web send (download API) so web browsers can download the offered files.
|
||||
/// `null` disables web send.
|
||||
final WebSendParams? webSend;
|
||||
|
||||
/// Enables the internal `show` endpoint, guarded by this token, that lets another
|
||||
/// application instance request this one to show itself. `null` disables it.
|
||||
final String? showToken;
|
||||
|
||||
HttpServerStartTask({
|
||||
required this.pin,
|
||||
required this.webSend,
|
||||
required this.showToken,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,6 +69,37 @@ class HttpServerFileUploadTargetTask implements BaseHttpServerTask {
|
||||
});
|
||||
}
|
||||
|
||||
/// Answers a pending [HttpServerWebPrepareDownloadEvent].
|
||||
class HttpServerPrepareDownloadDecisionTask implements BaseHttpServerTask {
|
||||
final String sessionId;
|
||||
|
||||
/// `true` accepts the download request, `false` declines it.
|
||||
final bool accept;
|
||||
|
||||
HttpServerPrepareDownloadDecisionTask({
|
||||
required this.sessionId,
|
||||
required this.accept,
|
||||
});
|
||||
}
|
||||
|
||||
/// Answers a pending [HttpServerWebFileDownloadEvent] with the source the file
|
||||
/// content should be read from: either a file [path] or a readable [fileDescriptor] (Android).
|
||||
///
|
||||
/// The file is read and streamed by the Rust server itself.
|
||||
class HttpServerFileDownloadTargetTask implements BaseHttpServerTask {
|
||||
final String sessionId;
|
||||
final String fileId;
|
||||
final String? path;
|
||||
final int? fileDescriptor;
|
||||
|
||||
HttpServerFileDownloadTargetTask({
|
||||
required this.sessionId,
|
||||
required this.fileId,
|
||||
required this.path,
|
||||
required this.fileDescriptor,
|
||||
});
|
||||
}
|
||||
|
||||
/// A message sent from the server isolate to the main isolate.
|
||||
sealed class HttpServerEvent {}
|
||||
|
||||
@@ -127,6 +168,44 @@ class HttpServerSessionEndEvent extends HttpServerEvent {
|
||||
});
|
||||
}
|
||||
|
||||
/// A web client requests to download the shared files.
|
||||
/// Must be answered with a [HttpServerPrepareDownloadDecisionTask].
|
||||
class HttpServerWebPrepareDownloadEvent extends HttpServerEvent {
|
||||
final String ip;
|
||||
final String sessionId;
|
||||
final String? userAgent;
|
||||
|
||||
HttpServerWebPrepareDownloadEvent({
|
||||
required this.ip,
|
||||
required this.sessionId,
|
||||
required this.userAgent,
|
||||
});
|
||||
}
|
||||
|
||||
/// A web client downloads an offered file.
|
||||
/// Must be answered with a [HttpServerFileDownloadTargetTask].
|
||||
class HttpServerWebFileDownloadEvent extends HttpServerEvent {
|
||||
final String sessionId;
|
||||
final String fileId;
|
||||
final FileDto file;
|
||||
|
||||
HttpServerWebFileDownloadEvent({
|
||||
required this.sessionId,
|
||||
required this.fileId,
|
||||
required this.file,
|
||||
});
|
||||
}
|
||||
|
||||
/// Another application instance requested the running application to show itself.
|
||||
class HttpServerShowEvent extends HttpServerEvent {
|
||||
/// Command-line arguments forwarded by the other application instance.
|
||||
final List<String> args;
|
||||
|
||||
HttpServerShowEvent({
|
||||
required this.args,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setupHttpServerIsolate(
|
||||
Stream<SendToIsolateData<IsolateTask<BaseHttpServerTask>>> receiveFromMain,
|
||||
void Function(IsolateTaskStreamResult<HttpServerEvent>) sendToMain,
|
||||
@@ -157,6 +236,8 @@ Future<void> setupHttpServerIsolate(
|
||||
deviceType: syncState.deviceInfo.deviceType.toRust(),
|
||||
fingerprint: syncState.securityContext.certificateHash,
|
||||
pin: startTask.pin,
|
||||
webSend: startTask.webSend,
|
||||
showToken: startTask.showToken,
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -180,6 +261,17 @@ Future<void> setupHttpServerIsolate(
|
||||
sessionId: sessionId,
|
||||
reason: reason,
|
||||
),
|
||||
RsServerEvent_WebPrepareDownload(:final ip, :final sessionId, :final userAgent) => HttpServerWebPrepareDownloadEvent(
|
||||
ip: ip,
|
||||
sessionId: sessionId,
|
||||
userAgent: userAgent,
|
||||
),
|
||||
RsServerEvent_WebFileDownload(:final sessionId, :final fileId, :final file) => HttpServerWebFileDownloadEvent(
|
||||
sessionId: sessionId,
|
||||
fileId: fileId,
|
||||
file: file,
|
||||
),
|
||||
RsServerEvent_Show(:final args) => HttpServerShowEvent(args: args),
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -229,6 +321,24 @@ Future<void> setupHttpServerIsolate(
|
||||
),
|
||||
);
|
||||
return;
|
||||
case HttpServerPrepareDownloadDecisionTask decisionTask:
|
||||
await ref
|
||||
.read(httpServerProvider)
|
||||
.respondPrepareDownload(
|
||||
sessionId: decisionTask.sessionId,
|
||||
accept: decisionTask.accept,
|
||||
);
|
||||
return;
|
||||
case HttpServerFileDownloadTargetTask targetTask:
|
||||
await ref
|
||||
.read(httpServerProvider)
|
||||
.respondFileDownload(
|
||||
sessionId: targetTask.sessionId,
|
||||
fileId: targetTask.fileId,
|
||||
path: targetTask.path,
|
||||
fileDescriptor: targetTask.fileDescriptor,
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:localsend_app/isolate/src/isolate/child/server_isolate.dart';
|
||||
import 'package:localsend_app/isolate/src/isolate/child/upload_isolate.dart';
|
||||
import 'package:localsend_app/isolate/src/isolate/dto/send_to_isolate_data.dart';
|
||||
import 'package:localsend_app/isolate/src/isolate/parent/parent_isolate_provider.dart';
|
||||
import 'package:localsend_app/rust/api/server.dart' show WebSendParams;
|
||||
import 'package:refena_flutter/refena_flutter.dart';
|
||||
import 'package:typed_isolates/id.dart';
|
||||
import 'package:typed_isolates/typed_isolates.dart';
|
||||
@@ -193,8 +194,18 @@ class IsolateHttpUploadCancelAction extends ReduxAction<IsolateController, Paren
|
||||
class IsolateHttpServerStartAction extends ReduxActionWithResult<IsolateController, ParentIsolateState, Stream<HttpServerEvent>> {
|
||||
final String? pin;
|
||||
|
||||
/// Enables web send (download API) so web browsers can download the offered files.
|
||||
/// `null` disables web send.
|
||||
final WebSendParams? webSend;
|
||||
|
||||
/// Enables the internal `show` endpoint, guarded by this token, that lets another
|
||||
/// application instance request this one to show itself. `null` disables it.
|
||||
final String? showToken;
|
||||
|
||||
IsolateHttpServerStartAction({
|
||||
required this.pin,
|
||||
required this.webSend,
|
||||
required this.showToken,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -209,6 +220,8 @@ class IsolateHttpServerStartAction extends ReduxActionWithResult<IsolateControll
|
||||
connection.sendWrappedTaskAndListenStream(
|
||||
task: HttpServerStartTask(
|
||||
pin: pin,
|
||||
webSend: webSend,
|
||||
showToken: showToken,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -318,6 +331,81 @@ class IsolateHttpServerFileUploadTargetAction extends ReduxActionWithResult<Isol
|
||||
}
|
||||
}
|
||||
|
||||
/// Answers a pending [HttpServerWebPrepareDownloadEvent].
|
||||
class IsolateHttpServerPrepareDownloadDecisionAction extends ReduxAction<IsolateController, ParentIsolateState> {
|
||||
final String sessionId;
|
||||
|
||||
/// `true` accepts the download request, `false` declines it.
|
||||
final bool accept;
|
||||
|
||||
IsolateHttpServerPrepareDownloadDecisionAction({
|
||||
required this.sessionId,
|
||||
required this.accept,
|
||||
});
|
||||
|
||||
@override
|
||||
ParentIsolateState reduce() {
|
||||
final connection = state.httpServer;
|
||||
if (connection == null) {
|
||||
throw StateError('httpServer is not initialized');
|
||||
}
|
||||
|
||||
connection.sendToIsolate(
|
||||
SendToIsolateData(
|
||||
syncState: null,
|
||||
data: IsolateTask(
|
||||
data: HttpServerPrepareDownloadDecisionTask(
|
||||
sessionId: sessionId,
|
||||
accept: accept,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/// Answers a pending [HttpServerWebFileDownloadEvent] with the source the file
|
||||
/// content should be read from (either a [path] or a readable [fileDescriptor]).
|
||||
class IsolateHttpServerFileDownloadTargetAction extends ReduxAction<IsolateController, ParentIsolateState> {
|
||||
final String sessionId;
|
||||
final String fileId;
|
||||
final String? path;
|
||||
final int? fileDescriptor;
|
||||
|
||||
IsolateHttpServerFileDownloadTargetAction({
|
||||
required this.sessionId,
|
||||
required this.fileId,
|
||||
required this.path,
|
||||
required this.fileDescriptor,
|
||||
});
|
||||
|
||||
@override
|
||||
ParentIsolateState reduce() {
|
||||
final connection = state.httpServer;
|
||||
if (connection == null) {
|
||||
throw StateError('httpServer is not initialized');
|
||||
}
|
||||
|
||||
connection.sendToIsolate(
|
||||
SendToIsolateData(
|
||||
syncState: null,
|
||||
data: IsolateTask(
|
||||
data: HttpServerFileDownloadTargetTask(
|
||||
sessionId: sessionId,
|
||||
fileId: fileId,
|
||||
path: path,
|
||||
fileDescriptor: fileDescriptor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/// Saving a file received by the HTTP server failed.
|
||||
class HttpServerFileUploadException implements Exception {
|
||||
final String message;
|
||||
|
||||
@@ -22,6 +22,8 @@ class HttpServerService {
|
||||
required DeviceType? deviceType,
|
||||
required String fingerprint,
|
||||
required String? pin,
|
||||
required WebSendParams? webSend,
|
||||
required String? showToken,
|
||||
}) async {
|
||||
if (_server != null) {
|
||||
throw StateError('Server already running');
|
||||
@@ -36,6 +38,8 @@ class HttpServerService {
|
||||
deviceType: deviceType,
|
||||
fingerprint: fingerprint,
|
||||
pin: pin,
|
||||
webSend: webSend,
|
||||
showToken: showToken,
|
||||
);
|
||||
_server = server;
|
||||
return server.listen();
|
||||
@@ -63,6 +67,28 @@ class HttpServerService {
|
||||
);
|
||||
}
|
||||
|
||||
/// Answers a pending web prepare-download request.
|
||||
/// [accept] grants the download; `false` declines it.
|
||||
Future<void> respondPrepareDownload({required String sessionId, required bool accept}) async {
|
||||
await _requireServer().respondPrepareDownload(sessionId: sessionId, accept: accept);
|
||||
}
|
||||
|
||||
/// Answers a pending web file download with the source the file content should be
|
||||
/// read from (either a [path] or a [fileDescriptor]). The server streams the content.
|
||||
Future<void> respondFileDownload({
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required String? path,
|
||||
required int? fileDescriptor,
|
||||
}) async {
|
||||
await _requireServer().respondFileDownload(
|
||||
sessionId: sessionId,
|
||||
fileId: fileId,
|
||||
path: path,
|
||||
fileDescriptor: fileDescriptor,
|
||||
);
|
||||
}
|
||||
|
||||
/// Stops the server. The event stream returned by [start] will end.
|
||||
Future<void> stop() async {
|
||||
final server = _server;
|
||||
|
||||
@@ -10,11 +10,18 @@ import 'package:localsend_app/rust/frb_generated.dart';
|
||||
|
||||
part 'server.freezed.dart';
|
||||
|
||||
// These functions are ignored because they are not marked as `pub`: `resolve_upload_target`
|
||||
// These functions are ignored because they are not marked as `pub`: `handle_server_event`, `handle_web_event`, `recv_opt`, `resolve_file_content`, `resolve_upload_target`
|
||||
|
||||
/// Starts the HTTP server on the given port (IPv4 and IPv6).
|
||||
/// The server runs until [RsHttpServer::stop] is called.
|
||||
///
|
||||
/// Passing [web_send] additionally enables the web send (download API) so that
|
||||
/// web browsers can download the offered files.
|
||||
///
|
||||
/// Passing [show_token] enables the internal `show` endpoint that lets another
|
||||
/// application instance request this one to show itself (emitted as
|
||||
/// [RsServerEvent::Show]). The token guards the endpoint against other clients.
|
||||
///
|
||||
/// Events are received by listening to [RsHttpServer::listen].
|
||||
Future<RsHttpServer> startServer({
|
||||
required int port,
|
||||
@@ -25,6 +32,8 @@ Future<RsHttpServer> startServer({
|
||||
DeviceType? deviceType,
|
||||
required String fingerprint,
|
||||
String? pin,
|
||||
WebSendParams? webSend,
|
||||
String? showToken,
|
||||
}) => RustLib.instance.api.crateApiServerStartServer(
|
||||
port: port,
|
||||
tls: tls,
|
||||
@@ -34,19 +43,35 @@ Future<RsHttpServer> startServer({
|
||||
deviceType: deviceType,
|
||||
fingerprint: fingerprint,
|
||||
pin: pin,
|
||||
webSend: webSend,
|
||||
showToken: showToken,
|
||||
);
|
||||
|
||||
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>>
|
||||
abstract class RsHttpServer implements RustOpaqueInterface {
|
||||
/// Emits server events until the server is stopped.
|
||||
/// Can only be listened to once.
|
||||
///
|
||||
/// The v2 protocol, the web send (download API), and the internal endpoint
|
||||
/// events are all emitted on the same stream.
|
||||
Stream<RsServerEvent> listen();
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebFileDownload] event with the source
|
||||
/// the file content should be read from (either a path or a file descriptor).
|
||||
///
|
||||
/// The server reads the content and streams it to the web client.
|
||||
Future<void> respondFileDownload({required String sessionId, required String fileId, String? path, int? fileDescriptor});
|
||||
|
||||
/// Answers the pending [RsServerEvent::FileUpload] event with the target
|
||||
/// the file should be saved to (either a path or a file descriptor)
|
||||
/// and waits until the file has been received completely.
|
||||
Future<void> respondFileUpload({required String sessionId, required String fileId, String? path, int? fileDescriptor});
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebPrepareDownload] event.
|
||||
///
|
||||
/// Passing `true` accepts the download request, `false` declines it.
|
||||
Future<void> respondPrepareDownload({required String sessionId, required bool accept});
|
||||
|
||||
/// Answers the pending [RsServerEvent::PrepareUpload] event.
|
||||
///
|
||||
/// Passing the accepted file IDs (a subset of the offered files) accepts the request.
|
||||
@@ -138,6 +163,31 @@ sealed class RsServerEvent with _$RsServerEvent {
|
||||
required String sessionId,
|
||||
required SessionEndReasonV2 reason,
|
||||
}) = RsServerEvent_SessionEnd;
|
||||
|
||||
/// A web client requests to download the shared files via `POST /api/localsend/v2/prepare-download`.
|
||||
///
|
||||
/// Must be answered with [RsHttpServer::respond_prepare_download].
|
||||
const factory RsServerEvent.webPrepareDownload({
|
||||
required String ip,
|
||||
required String sessionId,
|
||||
String? userAgent,
|
||||
}) = RsServerEvent_WebPrepareDownload;
|
||||
|
||||
/// A web client downloads an offered file via `GET /api/localsend/v2/download`.
|
||||
///
|
||||
/// Must be answered with [RsHttpServer::respond_file_download].
|
||||
const factory RsServerEvent.webFileDownload({
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
required FileDto file,
|
||||
}) = RsServerEvent_WebFileDownload;
|
||||
|
||||
/// Another application instance requested the running application to show itself
|
||||
/// via `POST /api/localsend/v2/show`.
|
||||
const factory RsServerEvent.show_({
|
||||
/// Command-line arguments forwarded by the other application instance.
|
||||
required List<String> args,
|
||||
}) = RsServerEvent_Show;
|
||||
}
|
||||
|
||||
enum SessionEndReasonV2 {
|
||||
@@ -161,3 +211,80 @@ class TlsConfig {
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) || other is TlsConfig && runtimeType == other.runtimeType && cert == other.cert && privateKey == other.privateKey;
|
||||
}
|
||||
|
||||
class WebSendI18n {
|
||||
final String waiting;
|
||||
final String enterPin;
|
||||
final String invalidPin;
|
||||
final String tooManyAttempts;
|
||||
final String rejected;
|
||||
final String files;
|
||||
final String fileName;
|
||||
final String size;
|
||||
|
||||
const WebSendI18n({
|
||||
required this.waiting,
|
||||
required this.enterPin,
|
||||
required this.invalidPin,
|
||||
required this.tooManyAttempts,
|
||||
required this.rejected,
|
||||
required this.files,
|
||||
required this.fileName,
|
||||
required this.size,
|
||||
});
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
waiting.hashCode ^
|
||||
enterPin.hashCode ^
|
||||
invalidPin.hashCode ^
|
||||
tooManyAttempts.hashCode ^
|
||||
rejected.hashCode ^
|
||||
files.hashCode ^
|
||||
fileName.hashCode ^
|
||||
size.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is WebSendI18n &&
|
||||
runtimeType == other.runtimeType &&
|
||||
waiting == other.waiting &&
|
||||
enterPin == other.enterPin &&
|
||||
invalidPin == other.invalidPin &&
|
||||
tooManyAttempts == other.tooManyAttempts &&
|
||||
rejected == other.rejected &&
|
||||
files == other.files &&
|
||||
fileName == other.fileName &&
|
||||
size == other.size;
|
||||
}
|
||||
|
||||
/// Configuration for web send: files offered for download by web browsers.
|
||||
///
|
||||
/// Web send can be enabled independently of the v2 protocol endpoints. When
|
||||
/// omitted, the download API responds with 403 and only the v2 endpoints run.
|
||||
class WebSendParams {
|
||||
/// The metadata of the files offered for download, mapped by file ID.
|
||||
/// The content is requested per download via [RsServerEvent::WebFileDownload].
|
||||
final Map<String, FileDto> files;
|
||||
|
||||
/// Optional PIN that web clients must provide via the `pin` query parameter.
|
||||
final String? pin;
|
||||
|
||||
/// Translations for the web page, served via `/i18n.json`.
|
||||
final WebSendI18n i18N;
|
||||
|
||||
const WebSendParams({
|
||||
required this.files,
|
||||
this.pin,
|
||||
required this.i18N,
|
||||
});
|
||||
|
||||
@override
|
||||
int get hashCode => files.hashCode ^ pin.hashCode ^ i18N.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is WebSendParams && runtimeType == other.runtimeType && files == other.files && pin == other.pin && i18N == other.i18N;
|
||||
}
|
||||
|
||||
@@ -55,14 +55,17 @@ extension RsServerEventPatterns on RsServerEvent {
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( RsServerEvent_Register value)? register,TResult Function( RsServerEvent_PrepareUpload value)? prepareUpload,TResult Function( RsServerEvent_FileUpload value)? fileUpload,TResult Function( RsServerEvent_SessionEnd value)? sessionEnd,required TResult orElse(),}){
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( RsServerEvent_Register value)? register,TResult Function( RsServerEvent_PrepareUpload value)? prepareUpload,TResult Function( RsServerEvent_FileUpload value)? fileUpload,TResult Function( RsServerEvent_SessionEnd value)? sessionEnd,TResult Function( RsServerEvent_WebPrepareDownload value)? webPrepareDownload,TResult Function( RsServerEvent_WebFileDownload value)? webFileDownload,TResult Function( RsServerEvent_Show value)? show_,required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register() when register != null:
|
||||
return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null:
|
||||
return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null:
|
||||
return fileUpload(_that);case RsServerEvent_SessionEnd() when sessionEnd != null:
|
||||
return sessionEnd(_that);case _:
|
||||
return sessionEnd(_that);case RsServerEvent_WebPrepareDownload() when webPrepareDownload != null:
|
||||
return webPrepareDownload(_that);case RsServerEvent_WebFileDownload() when webFileDownload != null:
|
||||
return webFileDownload(_that);case RsServerEvent_Show() when show_ != null:
|
||||
return show_(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -80,14 +83,17 @@ return sessionEnd(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( RsServerEvent_Register value) register,required TResult Function( RsServerEvent_PrepareUpload value) prepareUpload,required TResult Function( RsServerEvent_FileUpload value) fileUpload,required TResult Function( RsServerEvent_SessionEnd value) sessionEnd,}){
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( RsServerEvent_Register value) register,required TResult Function( RsServerEvent_PrepareUpload value) prepareUpload,required TResult Function( RsServerEvent_FileUpload value) fileUpload,required TResult Function( RsServerEvent_SessionEnd value) sessionEnd,required TResult Function( RsServerEvent_WebPrepareDownload value) webPrepareDownload,required TResult Function( RsServerEvent_WebFileDownload value) webFileDownload,required TResult Function( RsServerEvent_Show value) show_,}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register():
|
||||
return register(_that);case RsServerEvent_PrepareUpload():
|
||||
return prepareUpload(_that);case RsServerEvent_FileUpload():
|
||||
return fileUpload(_that);case RsServerEvent_SessionEnd():
|
||||
return sessionEnd(_that);}
|
||||
return sessionEnd(_that);case RsServerEvent_WebPrepareDownload():
|
||||
return webPrepareDownload(_that);case RsServerEvent_WebFileDownload():
|
||||
return webFileDownload(_that);case RsServerEvent_Show():
|
||||
return show_(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
@@ -101,14 +107,17 @@ return sessionEnd(_that);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( RsServerEvent_Register value)? register,TResult? Function( RsServerEvent_PrepareUpload value)? prepareUpload,TResult? Function( RsServerEvent_FileUpload value)? fileUpload,TResult? Function( RsServerEvent_SessionEnd value)? sessionEnd,}){
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( RsServerEvent_Register value)? register,TResult? Function( RsServerEvent_PrepareUpload value)? prepareUpload,TResult? Function( RsServerEvent_FileUpload value)? fileUpload,TResult? Function( RsServerEvent_SessionEnd value)? sessionEnd,TResult? Function( RsServerEvent_WebPrepareDownload value)? webPrepareDownload,TResult? Function( RsServerEvent_WebFileDownload value)? webFileDownload,TResult? Function( RsServerEvent_Show value)? show_,}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register() when register != null:
|
||||
return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null:
|
||||
return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null:
|
||||
return fileUpload(_that);case RsServerEvent_SessionEnd() when sessionEnd != null:
|
||||
return sessionEnd(_that);case _:
|
||||
return sessionEnd(_that);case RsServerEvent_WebPrepareDownload() when webPrepareDownload != null:
|
||||
return webPrepareDownload(_that);case RsServerEvent_WebFileDownload() when webFileDownload != null:
|
||||
return webFileDownload(_that);case RsServerEvent_Show() when show_ != null:
|
||||
return show_(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -125,13 +134,16 @@ return sessionEnd(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( String ip, RegisterDtoV2 info)? register,TResult Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files)? prepareUpload,TResult Function( String sessionId, String fileId, FileDto file)? fileUpload,TResult Function( String sessionId, SessionEndReasonV2 reason)? sessionEnd,required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( String ip, RegisterDtoV2 info)? register,TResult Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files)? prepareUpload,TResult Function( String sessionId, String fileId, FileDto file)? fileUpload,TResult Function( String sessionId, SessionEndReasonV2 reason)? sessionEnd,TResult Function( String ip, String sessionId, String? userAgent)? webPrepareDownload,TResult Function( String sessionId, String fileId, FileDto file)? webFileDownload,TResult Function( List<String> args)? show_,required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register() when register != null:
|
||||
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload() when prepareUpload != null:
|
||||
return prepareUpload(_that.ip,_that.info,_that.files);case RsServerEvent_FileUpload() when fileUpload != null:
|
||||
return fileUpload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_SessionEnd() when sessionEnd != null:
|
||||
return sessionEnd(_that.sessionId,_that.reason);case _:
|
||||
return sessionEnd(_that.sessionId,_that.reason);case RsServerEvent_WebPrepareDownload() when webPrepareDownload != null:
|
||||
return webPrepareDownload(_that.ip,_that.sessionId,_that.userAgent);case RsServerEvent_WebFileDownload() when webFileDownload != null:
|
||||
return webFileDownload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_Show() when show_ != null:
|
||||
return show_(_that.args);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -149,13 +161,16 @@ return sessionEnd(_that.sessionId,_that.reason);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( String ip, RegisterDtoV2 info) register,required TResult Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files) prepareUpload,required TResult Function( String sessionId, String fileId, FileDto file) fileUpload,required TResult Function( String sessionId, SessionEndReasonV2 reason) sessionEnd,}) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( String ip, RegisterDtoV2 info) register,required TResult Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files) prepareUpload,required TResult Function( String sessionId, String fileId, FileDto file) fileUpload,required TResult Function( String sessionId, SessionEndReasonV2 reason) sessionEnd,required TResult Function( String ip, String sessionId, String? userAgent) webPrepareDownload,required TResult Function( String sessionId, String fileId, FileDto file) webFileDownload,required TResult Function( List<String> args) show_,}) {final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register():
|
||||
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload():
|
||||
return prepareUpload(_that.ip,_that.info,_that.files);case RsServerEvent_FileUpload():
|
||||
return fileUpload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_SessionEnd():
|
||||
return sessionEnd(_that.sessionId,_that.reason);}
|
||||
return sessionEnd(_that.sessionId,_that.reason);case RsServerEvent_WebPrepareDownload():
|
||||
return webPrepareDownload(_that.ip,_that.sessionId,_that.userAgent);case RsServerEvent_WebFileDownload():
|
||||
return webFileDownload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_Show():
|
||||
return show_(_that.args);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -169,13 +184,16 @@ return sessionEnd(_that.sessionId,_that.reason);}
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( String ip, RegisterDtoV2 info)? register,TResult? Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files)? prepareUpload,TResult? Function( String sessionId, String fileId, FileDto file)? fileUpload,TResult? Function( String sessionId, SessionEndReasonV2 reason)? sessionEnd,}) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( String ip, RegisterDtoV2 info)? register,TResult? Function( String ip, RegisterDtoV2 info, Map<String, FileDto> files)? prepareUpload,TResult? Function( String sessionId, String fileId, FileDto file)? fileUpload,TResult? Function( String sessionId, SessionEndReasonV2 reason)? sessionEnd,TResult? Function( String ip, String sessionId, String? userAgent)? webPrepareDownload,TResult? Function( String sessionId, String fileId, FileDto file)? webFileDownload,TResult? Function( List<String> args)? show_,}) {final _that = this;
|
||||
switch (_that) {
|
||||
case RsServerEvent_Register() when register != null:
|
||||
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload() when prepareUpload != null:
|
||||
return prepareUpload(_that.ip,_that.info,_that.files);case RsServerEvent_FileUpload() when fileUpload != null:
|
||||
return fileUpload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_SessionEnd() when sessionEnd != null:
|
||||
return sessionEnd(_that.sessionId,_that.reason);case _:
|
||||
return sessionEnd(_that.sessionId,_that.reason);case RsServerEvent_WebPrepareDownload() when webPrepareDownload != null:
|
||||
return webPrepareDownload(_that.ip,_that.sessionId,_that.userAgent);case RsServerEvent_WebFileDownload() when webFileDownload != null:
|
||||
return webFileDownload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_Show() when show_ != null:
|
||||
return show_(_that.args);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -463,6 +481,220 @@ as SessionEndReasonV2,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class RsServerEvent_WebPrepareDownload extends RsServerEvent {
|
||||
const RsServerEvent_WebPrepareDownload({required this.ip, required this.sessionId, this.userAgent}): super._();
|
||||
|
||||
|
||||
final String ip;
|
||||
final String sessionId;
|
||||
final String? userAgent;
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$RsServerEvent_WebPrepareDownloadCopyWith<RsServerEvent_WebPrepareDownload> get copyWith => _$RsServerEvent_WebPrepareDownloadCopyWithImpl<RsServerEvent_WebPrepareDownload>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is RsServerEvent_WebPrepareDownload&&(identical(other.ip, ip) || other.ip == ip)&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,ip,sessionId,userAgent);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RsServerEvent.webPrepareDownload(ip: $ip, sessionId: $sessionId, userAgent: $userAgent)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $RsServerEvent_WebPrepareDownloadCopyWith<$Res> implements $RsServerEventCopyWith<$Res> {
|
||||
factory $RsServerEvent_WebPrepareDownloadCopyWith(RsServerEvent_WebPrepareDownload value, $Res Function(RsServerEvent_WebPrepareDownload) _then) = _$RsServerEvent_WebPrepareDownloadCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String ip, String sessionId, String? userAgent
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$RsServerEvent_WebPrepareDownloadCopyWithImpl<$Res>
|
||||
implements $RsServerEvent_WebPrepareDownloadCopyWith<$Res> {
|
||||
_$RsServerEvent_WebPrepareDownloadCopyWithImpl(this._self, this._then);
|
||||
|
||||
final RsServerEvent_WebPrepareDownload _self;
|
||||
final $Res Function(RsServerEvent_WebPrepareDownload) _then;
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') $Res call({Object? ip = null,Object? sessionId = null,Object? userAgent = freezed,}) {
|
||||
return _then(RsServerEvent_WebPrepareDownload(
|
||||
ip: null == ip ? _self.ip : ip // ignore: cast_nullable_to_non_nullable
|
||||
as String,sessionId: null == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable
|
||||
as String,userAgent: freezed == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class RsServerEvent_WebFileDownload extends RsServerEvent {
|
||||
const RsServerEvent_WebFileDownload({required this.sessionId, required this.fileId, required this.file}): super._();
|
||||
|
||||
|
||||
final String sessionId;
|
||||
final String fileId;
|
||||
final FileDto file;
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$RsServerEvent_WebFileDownloadCopyWith<RsServerEvent_WebFileDownload> get copyWith => _$RsServerEvent_WebFileDownloadCopyWithImpl<RsServerEvent_WebFileDownload>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is RsServerEvent_WebFileDownload&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,sessionId,fileId,file);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RsServerEvent.webFileDownload(sessionId: $sessionId, fileId: $fileId, file: $file)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $RsServerEvent_WebFileDownloadCopyWith<$Res> implements $RsServerEventCopyWith<$Res> {
|
||||
factory $RsServerEvent_WebFileDownloadCopyWith(RsServerEvent_WebFileDownload value, $Res Function(RsServerEvent_WebFileDownload) _then) = _$RsServerEvent_WebFileDownloadCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String sessionId, String fileId, FileDto file
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$RsServerEvent_WebFileDownloadCopyWithImpl<$Res>
|
||||
implements $RsServerEvent_WebFileDownloadCopyWith<$Res> {
|
||||
_$RsServerEvent_WebFileDownloadCopyWithImpl(this._self, this._then);
|
||||
|
||||
final RsServerEvent_WebFileDownload _self;
|
||||
final $Res Function(RsServerEvent_WebFileDownload) _then;
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') $Res call({Object? sessionId = null,Object? fileId = null,Object? file = null,}) {
|
||||
return _then(RsServerEvent_WebFileDownload(
|
||||
sessionId: null == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable
|
||||
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
|
||||
as String,file: null == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
|
||||
as FileDto,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class RsServerEvent_Show extends RsServerEvent {
|
||||
const RsServerEvent_Show({required final List<String> args}): _args = args,super._();
|
||||
|
||||
|
||||
/// Command-line arguments forwarded by the other application instance.
|
||||
final List<String> _args;
|
||||
/// Command-line arguments forwarded by the other application instance.
|
||||
List<String> get args {
|
||||
if (_args is EqualUnmodifiableListView) return _args;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_args);
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$RsServerEvent_ShowCopyWith<RsServerEvent_Show> get copyWith => _$RsServerEvent_ShowCopyWithImpl<RsServerEvent_Show>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is RsServerEvent_Show&&const DeepCollectionEquality().equals(other._args, _args));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_args));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'RsServerEvent.show_(args: $args)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $RsServerEvent_ShowCopyWith<$Res> implements $RsServerEventCopyWith<$Res> {
|
||||
factory $RsServerEvent_ShowCopyWith(RsServerEvent_Show value, $Res Function(RsServerEvent_Show) _then) = _$RsServerEvent_ShowCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<String> args
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$RsServerEvent_ShowCopyWithImpl<$Res>
|
||||
implements $RsServerEvent_ShowCopyWith<$Res> {
|
||||
_$RsServerEvent_ShowCopyWithImpl(this._self, this._then);
|
||||
|
||||
final RsServerEvent_Show _self;
|
||||
final $Res Function(RsServerEvent_Show) _then;
|
||||
|
||||
/// Create a copy of RsServerEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') $Res call({Object? args = null,}) {
|
||||
return _then(RsServerEvent_Show(
|
||||
args: null == args ? _self._args : args // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
||||
+293
-30
@@ -72,7 +72,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||
String get codegenVersion => '2.12.0';
|
||||
|
||||
@override
|
||||
int get rustContentHash => -1220219761;
|
||||
int get rustContentHash => -1029282510;
|
||||
|
||||
static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig(
|
||||
stem: 'rust_lib_localsend_app',
|
||||
@@ -154,6 +154,14 @@ abstract class RustLibApi extends BaseApi {
|
||||
|
||||
Stream<RsServerEvent> crateApiServerRsHttpServerListen({required RsHttpServer that});
|
||||
|
||||
Future<void> crateApiServerRsHttpServerRespondFileDownload({
|
||||
required RsHttpServer that,
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
});
|
||||
|
||||
Future<void> crateApiServerRsHttpServerRespondFileUpload({
|
||||
required RsHttpServer that,
|
||||
required String sessionId,
|
||||
@@ -162,6 +170,8 @@ abstract class RustLibApi extends BaseApi {
|
||||
int? fileDescriptor,
|
||||
});
|
||||
|
||||
Future<void> crateApiServerRsHttpServerRespondPrepareDownload({required RsHttpServer that, required String sessionId, required bool accept});
|
||||
|
||||
Future<void> crateApiServerRsHttpServerRespondPrepareUpload({required RsHttpServer that, List<String>? acceptedFileIds});
|
||||
|
||||
Future<void> crateApiServerRsHttpServerStop({required RsHttpServer that});
|
||||
@@ -224,6 +234,8 @@ abstract class RustLibApi extends BaseApi {
|
||||
DeviceType? deviceType,
|
||||
required String fingerprint,
|
||||
String? pin,
|
||||
WebSendParams? webSend,
|
||||
String? showToken,
|
||||
});
|
||||
|
||||
Future<void> crateApiCryptoVerifyCert({required String cert, required String publicKey});
|
||||
@@ -689,7 +701,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiServerRsHttpServerRespondFileUpload({
|
||||
Future<void> crateApiServerRsHttpServerRespondFileDownload({
|
||||
required RsHttpServer that,
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
@@ -711,6 +723,41 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
decodeErrorData: sse_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiServerRsHttpServerRespondFileDownloadConstMeta,
|
||||
argValues: [that, sessionId, fileId, path, fileDescriptor],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiServerRsHttpServerRespondFileDownloadConstMeta => const TaskConstMeta(
|
||||
debugName: 'RsHttpServer_respond_file_download',
|
||||
argNames: ['that', 'sessionId', 'fileId', 'path', 'fileDescriptor'],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiServerRsHttpServerRespondFileUpload({
|
||||
required RsHttpServer that,
|
||||
required String sessionId,
|
||||
required String fileId,
|
||||
String? path,
|
||||
int? fileDescriptor,
|
||||
}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_String(fileId, serializer);
|
||||
sse_encode_opt_String(path, serializer);
|
||||
sse_encode_opt_box_autoadd_i_32(fileDescriptor, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 13, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
decodeErrorData: sse_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiServerRsHttpServerRespondFileUploadConstMeta,
|
||||
argValues: [that, sessionId, fileId, path, fileDescriptor],
|
||||
apiImpl: this,
|
||||
@@ -723,6 +770,33 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
argNames: ['that', 'sessionId', 'fileId', 'path', 'fileDescriptor'],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiServerRsHttpServerRespondPrepareDownload({required RsHttpServer that, required String sessionId, required bool accept}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_bool(accept, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 14, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
decodeErrorData: sse_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiServerRsHttpServerRespondPrepareDownloadConstMeta,
|
||||
argValues: [that, sessionId, accept],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TaskConstMeta get kCrateApiServerRsHttpServerRespondPrepareDownloadConstMeta => const TaskConstMeta(
|
||||
debugName: 'RsHttpServer_respond_prepare_download',
|
||||
argNames: ['that', 'sessionId', 'accept'],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> crateApiServerRsHttpServerRespondPrepareUpload({required RsHttpServer that, List<String>? acceptedFileIds}) {
|
||||
return handler.executeNormal(
|
||||
@@ -731,7 +805,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer);
|
||||
sse_encode_opt_list_String(acceptedFileIds, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 13, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 15, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -756,7 +830,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 14, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 16, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -781,7 +855,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(that, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 15, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 17, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_String,
|
||||
@@ -809,7 +883,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(that, serializer);
|
||||
sse_encode_StreamSink_list_prim_u_8_strict_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 16, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 18, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -837,7 +911,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(that, serializer);
|
||||
sse_encode_list_prim_u_8_loose(data, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 17, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 19, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -862,7 +936,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 18, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 20, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -890,7 +964,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_StreamSink_rtc_file_error_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 19, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 21, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -917,7 +991,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 20, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 22, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_list_file_dto,
|
||||
@@ -945,7 +1019,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 21, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 23, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -975,7 +1049,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_StreamSink_rtc_status_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 22, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 24, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1003,7 +1077,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_box_autoadd_rtc_send_file_response(status, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 23, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 25, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1029,7 +1103,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_String(pin, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 24, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 26, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1055,7 +1129,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
|
||||
sse_encode_Set_String_None(selection, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 25, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 27, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1083,7 +1157,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
|
||||
sse_encode_StreamSink_rtc_file_error_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 26, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 28, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1110,7 +1184,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 27, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 29, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_Set_String_None,
|
||||
@@ -1138,7 +1212,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
|
||||
sse_encode_StreamSink_rtc_status_Sse(sink, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 28, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 30, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1166,7 +1240,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
|
||||
sse_encode_String(fileId, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 29, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 31, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender,
|
||||
@@ -1192,7 +1266,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
|
||||
sse_encode_String(pin, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 30, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 32, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1231,7 +1305,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
onConnection,
|
||||
serializer,
|
||||
);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 31, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 33, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1257,7 +1331,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
SyncTask(
|
||||
callFfi: () {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 32)!;
|
||||
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 34)!;
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsCancellationToken,
|
||||
@@ -1285,7 +1359,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_String(cert, serializer);
|
||||
sse_encode_ls_http_client_version(version, serializer);
|
||||
sse_encode_opt_box_autoadd_u_32(timeoutMs, serializer);
|
||||
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 33)!;
|
||||
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 35)!;
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpClient,
|
||||
@@ -1309,7 +1383,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 34, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 36, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData:
|
||||
@@ -1334,7 +1408,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 35, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 37, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1358,7 +1432,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
NormalTask(
|
||||
callFfi: (port_) {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 36, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 38, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_key_pair,
|
||||
@@ -1386,6 +1460,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
DeviceType? deviceType,
|
||||
required String fingerprint,
|
||||
String? pin,
|
||||
WebSendParams? webSend,
|
||||
String? showToken,
|
||||
}) {
|
||||
return handler.executeNormal(
|
||||
NormalTask(
|
||||
@@ -1399,14 +1475,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_opt_box_autoadd_device_type(deviceType, serializer);
|
||||
sse_encode_String(fingerprint, serializer);
|
||||
sse_encode_opt_String(pin, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 37, port: port_);
|
||||
sse_encode_opt_box_autoadd_web_send_params(webSend, serializer);
|
||||
sse_encode_opt_String(showToken, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 39, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer,
|
||||
decodeErrorData: sse_decode_AnyhowException,
|
||||
),
|
||||
constMeta: kCrateApiServerStartServerConstMeta,
|
||||
argValues: [port, tls, alias, version, deviceModel, deviceType, fingerprint, pin],
|
||||
argValues: [port, tls, alias, version, deviceModel, deviceType, fingerprint, pin, webSend, showToken],
|
||||
apiImpl: this,
|
||||
),
|
||||
);
|
||||
@@ -1414,7 +1492,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
|
||||
TaskConstMeta get kCrateApiServerStartServerConstMeta => const TaskConstMeta(
|
||||
debugName: 'start_server',
|
||||
argNames: ['port', 'tls', 'alias', 'version', 'deviceModel', 'deviceType', 'fingerprint', 'pin'],
|
||||
argNames: ['port', 'tls', 'alias', 'version', 'deviceModel', 'deviceType', 'fingerprint', 'pin', 'webSend', 'showToken'],
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -1425,7 +1503,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||
sse_encode_String(cert, serializer);
|
||||
sse_encode_String(publicKey, serializer);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 38, port: port_);
|
||||
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 40, port: port_);
|
||||
},
|
||||
codec: SseCodec(
|
||||
decodeSuccessData: sse_decode_unit,
|
||||
@@ -1918,6 +1996,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw as int;
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_box_autoadd_web_send_params(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return dco_decode_web_send_params(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2137,6 +2221,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return raw == null ? null : dco_decode_box_autoadd_u_32(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams? dco_decode_opt_box_autoadd_web_send_params(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
return raw == null ? null : dco_decode_box_autoadd_web_send_params(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
List<String>? dco_decode_opt_list_String(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2370,6 +2460,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sessionId: dco_decode_String(raw[1]),
|
||||
reason: dco_decode_session_end_reason_v_2(raw[2]),
|
||||
);
|
||||
case 4:
|
||||
return RsServerEvent_WebPrepareDownload(
|
||||
ip: dco_decode_String(raw[1]),
|
||||
sessionId: dco_decode_String(raw[2]),
|
||||
userAgent: dco_decode_opt_String(raw[3]),
|
||||
);
|
||||
case 5:
|
||||
return RsServerEvent_WebFileDownload(
|
||||
sessionId: dco_decode_String(raw[1]),
|
||||
fileId: dco_decode_String(raw[2]),
|
||||
file: dco_decode_box_autoadd_file_dto(raw[3]),
|
||||
);
|
||||
case 6:
|
||||
return RsServerEvent_Show(
|
||||
args: dco_decode_list_String(raw[1]),
|
||||
);
|
||||
default:
|
||||
throw Exception('unreachable');
|
||||
}
|
||||
@@ -2478,6 +2584,35 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return dcoDecodeU64(raw);
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendI18n dco_decode_web_send_i_18_n(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
final arr = raw as List<dynamic>;
|
||||
if (arr.length != 8) throw Exception('unexpected arr length: expect 8 but see ${arr.length}');
|
||||
return WebSendI18n(
|
||||
waiting: dco_decode_String(arr[0]),
|
||||
enterPin: dco_decode_String(arr[1]),
|
||||
invalidPin: dco_decode_String(arr[2]),
|
||||
tooManyAttempts: dco_decode_String(arr[3]),
|
||||
rejected: dco_decode_String(arr[4]),
|
||||
files: dco_decode_String(arr[5]),
|
||||
fileName: dco_decode_String(arr[6]),
|
||||
size: dco_decode_String(arr[7]),
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_web_send_params(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
final arr = raw as List<dynamic>;
|
||||
if (arr.length != 3) throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
|
||||
return WebSendParams(
|
||||
files: dco_decode_Map_String_file_dto_None(arr[0]),
|
||||
pin: dco_decode_opt_String(arr[1]),
|
||||
i18N: dco_decode_web_send_i_18_n(arr[2]),
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
WsServerMessage dco_decode_ws_server_message(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
@@ -2937,6 +3072,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return (sse_decode_u_32(deserializer));
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_box_autoadd_web_send_params(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
return (sse_decode_web_send_params(deserializer));
|
||||
}
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -3230,6 +3371,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams? sse_decode_opt_box_autoadd_web_send_params(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
|
||||
if (sse_decode_bool(deserializer)) {
|
||||
return (sse_decode_box_autoadd_web_send_params(deserializer));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -3448,6 +3600,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
var var_sessionId = sse_decode_String(deserializer);
|
||||
var var_reason = sse_decode_session_end_reason_v_2(deserializer);
|
||||
return RsServerEvent_SessionEnd(sessionId: var_sessionId, reason: var_reason);
|
||||
case 4:
|
||||
var var_ip = sse_decode_String(deserializer);
|
||||
var var_sessionId = sse_decode_String(deserializer);
|
||||
var var_userAgent = sse_decode_opt_String(deserializer);
|
||||
return RsServerEvent_WebPrepareDownload(ip: var_ip, sessionId: var_sessionId, userAgent: var_userAgent);
|
||||
case 5:
|
||||
var var_sessionId = sse_decode_String(deserializer);
|
||||
var var_fileId = sse_decode_String(deserializer);
|
||||
var var_file = sse_decode_box_autoadd_file_dto(deserializer);
|
||||
return RsServerEvent_WebFileDownload(sessionId: var_sessionId, fileId: var_fileId, file: var_file);
|
||||
case 6:
|
||||
var var_args = sse_decode_list_String(deserializer);
|
||||
return RsServerEvent_Show(args: var_args);
|
||||
default:
|
||||
throw UnimplementedError('');
|
||||
}
|
||||
@@ -3548,6 +3713,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
return deserializer.buffer.getBigUint64();
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendI18n sse_decode_web_send_i_18_n(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
var var_waiting = sse_decode_String(deserializer);
|
||||
var var_enterPin = sse_decode_String(deserializer);
|
||||
var var_invalidPin = sse_decode_String(deserializer);
|
||||
var var_tooManyAttempts = sse_decode_String(deserializer);
|
||||
var var_rejected = sse_decode_String(deserializer);
|
||||
var var_files = sse_decode_String(deserializer);
|
||||
var var_fileName = sse_decode_String(deserializer);
|
||||
var var_size = sse_decode_String(deserializer);
|
||||
return WebSendI18n(
|
||||
waiting: var_waiting,
|
||||
enterPin: var_enterPin,
|
||||
invalidPin: var_invalidPin,
|
||||
tooManyAttempts: var_tooManyAttempts,
|
||||
rejected: var_rejected,
|
||||
files: var_files,
|
||||
fileName: var_fileName,
|
||||
size: var_size,
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_web_send_params(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
var var_files = sse_decode_Map_String_file_dto_None(deserializer);
|
||||
var var_pin = sse_decode_opt_String(deserializer);
|
||||
var var_i18N = sse_decode_web_send_i_18_n(deserializer);
|
||||
return WebSendParams(files: var_files, pin: var_pin, i18N: var_i18N);
|
||||
}
|
||||
|
||||
@protected
|
||||
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4102,6 +4299,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_u_32(self, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_web_send_params(WebSendParams self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_web_send_params(self, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4354,6 +4557,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_web_send_params(WebSendParams? 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_web_send_params(self, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4527,6 +4740,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_i_32(3, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_session_end_reason_v_2(reason, serializer);
|
||||
case RsServerEvent_WebPrepareDownload(ip: final ip, sessionId: final sessionId, userAgent: final userAgent):
|
||||
sse_encode_i_32(4, serializer);
|
||||
sse_encode_String(ip, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_opt_String(userAgent, serializer);
|
||||
case RsServerEvent_WebFileDownload(sessionId: final sessionId, fileId: final fileId, file: final file):
|
||||
sse_encode_i_32(5, serializer);
|
||||
sse_encode_String(sessionId, serializer);
|
||||
sse_encode_String(fileId, serializer);
|
||||
sse_encode_box_autoadd_file_dto(file, serializer);
|
||||
case RsServerEvent_Show(args: final args):
|
||||
sse_encode_i_32(6, serializer);
|
||||
sse_encode_list_String(args, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4617,6 +4843,27 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
serializer.buffer.putBigUint64(self);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_i_18_n(WebSendI18n self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_String(self.waiting, serializer);
|
||||
sse_encode_String(self.enterPin, serializer);
|
||||
sse_encode_String(self.invalidPin, serializer);
|
||||
sse_encode_String(self.tooManyAttempts, serializer);
|
||||
sse_encode_String(self.rejected, serializer);
|
||||
sse_encode_String(self.files, serializer);
|
||||
sse_encode_String(self.fileName, serializer);
|
||||
sse_encode_String(self.size, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_params(WebSendParams self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_Map_String_file_dto_None(self.files, serializer);
|
||||
sse_encode_opt_String(self.pin, serializer);
|
||||
sse_encode_web_send_i_18_n(self.i18N, serializer);
|
||||
}
|
||||
|
||||
@protected
|
||||
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
@@ -4852,16 +5099,32 @@ class RsHttpServerImpl extends RustOpaque implements RsHttpServer {
|
||||
|
||||
/// Emits server events until the server is stopped.
|
||||
/// Can only be listened to once.
|
||||
///
|
||||
/// The v2 protocol, the web send (download API), and the internal endpoint
|
||||
/// events are all emitted on the same stream.
|
||||
Stream<RsServerEvent> listen() => RustLib.instance.api.crateApiServerRsHttpServerListen(
|
||||
that: this,
|
||||
);
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebFileDownload] event with the source
|
||||
/// the file content should be read from (either a path or a file descriptor).
|
||||
///
|
||||
/// The server reads the content and streams it to the web client.
|
||||
Future<void> respondFileDownload({required String sessionId, required String fileId, String? path, int? fileDescriptor}) => RustLib.instance.api
|
||||
.crateApiServerRsHttpServerRespondFileDownload(that: this, sessionId: sessionId, fileId: fileId, path: path, fileDescriptor: fileDescriptor);
|
||||
|
||||
/// Answers the pending [RsServerEvent::FileUpload] event with the target
|
||||
/// the file should be saved to (either a path or a file descriptor)
|
||||
/// and waits until the file has been received completely.
|
||||
Future<void> respondFileUpload({required String sessionId, required String fileId, String? path, int? fileDescriptor}) => RustLib.instance.api
|
||||
.crateApiServerRsHttpServerRespondFileUpload(that: this, sessionId: sessionId, fileId: fileId, path: path, fileDescriptor: fileDescriptor);
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebPrepareDownload] event.
|
||||
///
|
||||
/// Passing `true` accepts the download request, `false` declines it.
|
||||
Future<void> respondPrepareDownload({required String sessionId, required bool accept}) =>
|
||||
RustLib.instance.api.crateApiServerRsHttpServerRespondPrepareDownload(that: this, sessionId: sessionId, accept: accept);
|
||||
|
||||
/// Answers the pending [RsServerEvent::PrepareUpload] event.
|
||||
///
|
||||
/// Passing the accepted file IDs (a subset of the offered files) accepts the request.
|
||||
|
||||
@@ -252,6 +252,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int dco_decode_box_autoadd_u_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_box_autoadd_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
|
||||
|
||||
@@ -340,6 +343,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams? dco_decode_opt_box_autoadd_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
List<String>? dco_decode_opt_list_String(dynamic raw);
|
||||
|
||||
@@ -427,6 +433,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
BigInt dco_decode_usize(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendI18n dco_decode_web_send_i_18_n(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
WsServerMessage dco_decode_ws_server_message(dynamic raw);
|
||||
|
||||
@@ -647,6 +659,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_box_autoadd_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer);
|
||||
|
||||
@@ -737,6 +752,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams? sse_decode_opt_box_autoadd_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer);
|
||||
|
||||
@@ -824,6 +842,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendI18n sse_decode_web_send_i_18_n(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
|
||||
|
||||
@@ -1089,6 +1113,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_web_send_params(WebSendParams self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer);
|
||||
|
||||
@@ -1179,6 +1206,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_web_send_params(WebSendParams? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer);
|
||||
|
||||
@@ -1267,6 +1297,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_i_18_n(WebSendI18n self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_params(WebSendParams self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer);
|
||||
|
||||
|
||||
@@ -254,6 +254,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int dco_decode_box_autoadd_u_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_box_autoadd_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
|
||||
|
||||
@@ -342,6 +345,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams? dco_decode_opt_box_autoadd_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
List<String>? dco_decode_opt_list_String(dynamic raw);
|
||||
|
||||
@@ -429,6 +435,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
BigInt dco_decode_usize(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendI18n dco_decode_web_send_i_18_n(dynamic raw);
|
||||
|
||||
@protected
|
||||
WebSendParams dco_decode_web_send_params(dynamic raw);
|
||||
|
||||
@protected
|
||||
WsServerMessage dco_decode_ws_server_message(dynamic raw);
|
||||
|
||||
@@ -649,6 +661,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_box_autoadd_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer);
|
||||
|
||||
@@ -739,6 +754,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams? sse_decode_opt_box_autoadd_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer);
|
||||
|
||||
@@ -826,6 +844,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
BigInt sse_decode_usize(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendI18n sse_decode_web_send_i_18_n(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WebSendParams sse_decode_web_send_params(SseDeserializer deserializer);
|
||||
|
||||
@protected
|
||||
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
|
||||
|
||||
@@ -1091,6 +1115,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_web_send_params(WebSendParams self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer);
|
||||
|
||||
@@ -1181,6 +1208,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_box_autoadd_web_send_params(WebSendParams? self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer);
|
||||
|
||||
@@ -1269,6 +1299,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
@protected
|
||||
void sse_encode_usize(BigInt self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_i_18_n(WebSendI18n self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_web_send_params(WebSendParams self, SseSerializer serializer);
|
||||
|
||||
@protected
|
||||
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer);
|
||||
|
||||
|
||||
+300
-42
@@ -4,11 +4,14 @@ pub use localsend::http::dto_v2::{ProtocolTypeV2, RegisterDtoV2};
|
||||
use localsend::http::server::ServerConfigV2;
|
||||
pub use localsend::http::server::TlsConfig;
|
||||
use localsend::http::server::common::save::FileUploadTarget;
|
||||
use localsend::http::server::internal::{InternalConfig, InternalEvent};
|
||||
pub use localsend::http::server::v2::SessionEndReasonV2;
|
||||
use localsend::http::server::v2::{PrepareUploadDecisionV2, ServerEventV2};
|
||||
pub use localsend::http::server::web::WebSendI18n;
|
||||
use localsend::http::server::web::{WebSendConfig, WebSendEvent};
|
||||
use localsend::http::state::ClientInfo;
|
||||
use localsend::model::discovery::DeviceType;
|
||||
use localsend::model::transfer::FileDto;
|
||||
use localsend::model::transfer::{FileContent, FileDto};
|
||||
use std::collections::HashMap;
|
||||
use tokio::sync::{Mutex, mpsc, oneshot};
|
||||
|
||||
@@ -39,6 +42,31 @@ pub enum RsServerEvent {
|
||||
session_id: String,
|
||||
reason: SessionEndReasonV2,
|
||||
},
|
||||
|
||||
/// A web client requests to download the shared files via `POST /api/localsend/v2/prepare-download`.
|
||||
///
|
||||
/// Must be answered with [RsHttpServer::respond_prepare_download].
|
||||
WebPrepareDownload {
|
||||
ip: String,
|
||||
session_id: String,
|
||||
user_agent: Option<String>,
|
||||
},
|
||||
|
||||
/// A web client downloads an offered file via `GET /api/localsend/v2/download`.
|
||||
///
|
||||
/// Must be answered with [RsHttpServer::respond_file_download].
|
||||
WebFileDownload {
|
||||
session_id: String,
|
||||
file_id: String,
|
||||
file: FileDto,
|
||||
},
|
||||
|
||||
/// Another application instance requested the running application to show itself
|
||||
/// via `POST /api/localsend/v2/show`.
|
||||
Show {
|
||||
/// Command-line arguments forwarded by the other application instance.
|
||||
args: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct RsHttpServer {
|
||||
@@ -46,11 +74,38 @@ pub struct RsHttpServer {
|
||||
stop_tx: Mutex<Option<oneshot::Sender<()>>>,
|
||||
pending_decision: Mutex<Option<oneshot::Sender<PrepareUploadDecisionV2>>>,
|
||||
pending_uploads: Mutex<HashMap<(String, String), oneshot::Sender<FileUploadTarget>>>,
|
||||
web_event_rx: Mutex<Option<mpsc::Receiver<WebSendEvent>>>,
|
||||
pending_download_decisions: Mutex<HashMap<String, oneshot::Sender<bool>>>,
|
||||
pending_downloads: Mutex<HashMap<(String, String), oneshot::Sender<FileContent>>>,
|
||||
internal_event_rx: Mutex<Option<mpsc::Receiver<InternalEvent>>>,
|
||||
}
|
||||
|
||||
/// Configuration for web send: files offered for download by web browsers.
|
||||
///
|
||||
/// Web send can be enabled independently of the v2 protocol endpoints. When
|
||||
/// omitted, the download API responds with 403 and only the v2 endpoints run.
|
||||
pub struct WebSendParams {
|
||||
/// The metadata of the files offered for download, mapped by file ID.
|
||||
/// The content is requested per download via [RsServerEvent::WebFileDownload].
|
||||
pub files: HashMap<String, FileDto>,
|
||||
|
||||
/// Optional PIN that web clients must provide via the `pin` query parameter.
|
||||
pub pin: Option<String>,
|
||||
|
||||
/// Translations for the web page, served via `/i18n.json`.
|
||||
pub i18n: WebSendI18n,
|
||||
}
|
||||
|
||||
/// Starts the HTTP server on the given port (IPv4 and IPv6).
|
||||
/// The server runs until [RsHttpServer::stop] is called.
|
||||
///
|
||||
/// Passing [web_send] additionally enables the web send (download API) so that
|
||||
/// web browsers can download the offered files.
|
||||
///
|
||||
/// Passing [show_token] enables the internal `show` endpoint that lets another
|
||||
/// application instance request this one to show itself (emitted as
|
||||
/// [RsServerEvent::Show]). The token guards the endpoint against other clients.
|
||||
///
|
||||
/// Events are received by listening to [RsHttpServer::listen].
|
||||
pub async fn start_server(
|
||||
port: u16,
|
||||
@@ -61,10 +116,38 @@ pub async fn start_server(
|
||||
device_type: Option<DeviceType>,
|
||||
fingerprint: String,
|
||||
pin: Option<String>,
|
||||
web_send: Option<WebSendParams>,
|
||||
show_token: Option<String>,
|
||||
) -> anyhow::Result<RsHttpServer> {
|
||||
let (event_tx, event_rx) = mpsc::channel::<ServerEventV2>(16);
|
||||
let (stop_tx, stop_rx) = oneshot::channel::<()>();
|
||||
|
||||
let (web_send_config, web_event_rx) = match web_send {
|
||||
Some(web_send) => {
|
||||
let (web_event_tx, web_event_rx) = mpsc::channel::<WebSendEvent>(16);
|
||||
let config = WebSendConfig {
|
||||
files: web_send.files,
|
||||
pin: web_send.pin,
|
||||
i18n: web_send.i18n,
|
||||
event_tx: web_event_tx,
|
||||
};
|
||||
(Some(config), Some(web_event_rx))
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
let (internal_config, internal_event_rx) = match show_token {
|
||||
Some(show_token) => {
|
||||
let (internal_event_tx, internal_event_rx) = mpsc::channel::<InternalEvent>(16);
|
||||
let config = InternalConfig {
|
||||
show_token,
|
||||
event_tx: internal_event_tx,
|
||||
};
|
||||
(Some(config), Some(internal_event_rx))
|
||||
}
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
localsend::http::server::start_with_port(
|
||||
port,
|
||||
tls,
|
||||
@@ -75,9 +158,9 @@ pub async fn start_server(
|
||||
device_type,
|
||||
token: fingerprint,
|
||||
},
|
||||
None,
|
||||
internal_config,
|
||||
Some(ServerConfigV2 { pin, event_tx }),
|
||||
None,
|
||||
web_send_config,
|
||||
stop_rx,
|
||||
)
|
||||
.await?;
|
||||
@@ -87,63 +170,139 @@ pub async fn start_server(
|
||||
stop_tx: Mutex::new(Some(stop_tx)),
|
||||
pending_decision: Mutex::new(None),
|
||||
pending_uploads: Mutex::new(HashMap::new()),
|
||||
web_event_rx: Mutex::new(web_event_rx),
|
||||
pending_download_decisions: Mutex::new(HashMap::new()),
|
||||
pending_downloads: Mutex::new(HashMap::new()),
|
||||
internal_event_rx: Mutex::new(internal_event_rx),
|
||||
})
|
||||
}
|
||||
|
||||
impl RsHttpServer {
|
||||
/// Emits server events until the server is stopped.
|
||||
/// Can only be listened to once.
|
||||
///
|
||||
/// The v2 protocol, the web send (download API), and the internal endpoint
|
||||
/// events are all emitted on the same stream.
|
||||
pub async fn listen(&self, sink: StreamSink<RsServerEvent>) {
|
||||
let Some(mut event_rx) = self.event_rx.lock().await.take() else {
|
||||
let _ = sink.add_error(anyhow::anyhow!("Server events already listened to"));
|
||||
return;
|
||||
};
|
||||
let mut web_event_rx = self.web_event_rx.lock().await.take();
|
||||
let mut internal_event_rx = self.internal_event_rx.lock().await.take();
|
||||
|
||||
while let Some(event) = event_rx.recv().await {
|
||||
match event {
|
||||
ServerEventV2::Register { ip, info } => {
|
||||
let _ = sink.add(RsServerEvent::Register {
|
||||
ip: ip.to_string(),
|
||||
info,
|
||||
});
|
||||
let mut v2_open = true;
|
||||
loop {
|
||||
tokio::select! {
|
||||
event = event_rx.recv(), if v2_open => {
|
||||
match event {
|
||||
Some(event) => self.handle_server_event(&sink, event).await,
|
||||
None => v2_open = false,
|
||||
}
|
||||
}
|
||||
ServerEventV2::PrepareUpload {
|
||||
ip,
|
||||
event = recv_opt(&mut web_event_rx) => {
|
||||
match event {
|
||||
Some(event) => self.handle_web_event(&sink, event).await,
|
||||
None => web_event_rx = None,
|
||||
}
|
||||
}
|
||||
event = recv_opt(&mut internal_event_rx) => {
|
||||
match event {
|
||||
Some(InternalEvent::Show { args }) => {
|
||||
let _ = sink.add(RsServerEvent::Show { args });
|
||||
}
|
||||
None => internal_event_rx = None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !v2_open && web_event_rx.is_none() && internal_event_rx.is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_server_event(&self, sink: &StreamSink<RsServerEvent>, event: ServerEventV2) {
|
||||
match event {
|
||||
ServerEventV2::Register { ip, info } => {
|
||||
let _ = sink.add(RsServerEvent::Register {
|
||||
ip: ip.to_string(),
|
||||
info,
|
||||
});
|
||||
}
|
||||
ServerEventV2::PrepareUpload {
|
||||
ip,
|
||||
info,
|
||||
files,
|
||||
decision_tx,
|
||||
} => {
|
||||
*self.pending_decision.lock().await = Some(decision_tx);
|
||||
let _ = sink.add(RsServerEvent::PrepareUpload {
|
||||
ip: ip.to_string(),
|
||||
info,
|
||||
files,
|
||||
decision_tx,
|
||||
} => {
|
||||
*self.pending_decision.lock().await = Some(decision_tx);
|
||||
let _ = sink.add(RsServerEvent::PrepareUpload {
|
||||
ip: ip.to_string(),
|
||||
info,
|
||||
files,
|
||||
});
|
||||
}
|
||||
ServerEventV2::FileUpload {
|
||||
});
|
||||
}
|
||||
ServerEventV2::FileUpload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
target_tx,
|
||||
} => {
|
||||
self.pending_uploads
|
||||
.lock()
|
||||
.await
|
||||
.insert((session_id.clone(), file_id.clone()), target_tx);
|
||||
let _ = sink.add(RsServerEvent::FileUpload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
target_tx,
|
||||
} => {
|
||||
self.pending_uploads
|
||||
.lock()
|
||||
.await
|
||||
.insert((session_id.clone(), file_id.clone()), target_tx);
|
||||
let _ = sink.add(RsServerEvent::FileUpload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
});
|
||||
}
|
||||
ServerEventV2::SessionEnd { session_id, reason } => {
|
||||
// Drop stale upload responders of this session (their requests already ended).
|
||||
self.pending_uploads
|
||||
.lock()
|
||||
.await
|
||||
.retain(|(sid, _), _| sid != &session_id);
|
||||
let _ = sink.add(RsServerEvent::SessionEnd { session_id, reason });
|
||||
}
|
||||
});
|
||||
}
|
||||
ServerEventV2::SessionEnd { session_id, reason } => {
|
||||
// Drop stale upload responders of this session (their requests already ended).
|
||||
self.pending_uploads
|
||||
.lock()
|
||||
.await
|
||||
.retain(|(sid, _), _| sid != &session_id);
|
||||
let _ = sink.add(RsServerEvent::SessionEnd { session_id, reason });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_web_event(&self, sink: &StreamSink<RsServerEvent>, event: WebSendEvent) {
|
||||
match event {
|
||||
WebSendEvent::PrepareDownload {
|
||||
ip,
|
||||
session_id,
|
||||
user_agent,
|
||||
decision_tx,
|
||||
} => {
|
||||
self.pending_download_decisions
|
||||
.lock()
|
||||
.await
|
||||
.insert(session_id.clone(), decision_tx);
|
||||
let _ = sink.add(RsServerEvent::WebPrepareDownload {
|
||||
ip: ip.to_string(),
|
||||
session_id,
|
||||
user_agent,
|
||||
});
|
||||
}
|
||||
WebSendEvent::FileDownload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
content_tx,
|
||||
} => {
|
||||
self.pending_downloads
|
||||
.lock()
|
||||
.await
|
||||
.insert((session_id.clone(), file_id.clone()), content_tx);
|
||||
let _ = sink.add(RsServerEvent::WebFileDownload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,6 +364,59 @@ impl RsHttpServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebPrepareDownload] event.
|
||||
///
|
||||
/// Passing `true` accepts the download request, `false` declines it.
|
||||
pub async fn respond_prepare_download(
|
||||
&self,
|
||||
session_id: String,
|
||||
accept: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(decision_tx) = self
|
||||
.pending_download_decisions
|
||||
.lock()
|
||||
.await
|
||||
.remove(&session_id)
|
||||
else {
|
||||
return Err(anyhow::anyhow!("No pending prepare-download request"));
|
||||
};
|
||||
|
||||
decision_tx
|
||||
.send(accept)
|
||||
.map_err(|_| anyhow::anyhow!("Prepare-download request already ended"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Answers the pending [RsServerEvent::WebFileDownload] event with the source
|
||||
/// the file content should be read from (either a path or a file descriptor).
|
||||
///
|
||||
/// The server reads the content and streams it to the web client.
|
||||
pub async fn respond_file_download(
|
||||
&self,
|
||||
session_id: String,
|
||||
file_id: String,
|
||||
path: Option<String>,
|
||||
file_descriptor: Option<i32>,
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(content_tx) = self
|
||||
.pending_downloads
|
||||
.lock()
|
||||
.await
|
||||
.remove(&(session_id, file_id))
|
||||
else {
|
||||
return Err(anyhow::anyhow!("No pending file download for this file"));
|
||||
};
|
||||
|
||||
let content = resolve_file_content(path, file_descriptor)?;
|
||||
|
||||
content_tx
|
||||
.send(content)
|
||||
.map_err(|_| anyhow::anyhow!("Download request already ended"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stops the server.
|
||||
pub async fn stop(&self) {
|
||||
if let Some(stop_tx) = self.stop_tx.lock().await.take() {
|
||||
@@ -213,6 +425,15 @@ impl RsHttpServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Receives the next event from an optional channel, or pends forever when the
|
||||
/// channel is absent (i.e. that feature is disabled).
|
||||
async fn recv_opt<T>(rx: &mut Option<mpsc::Receiver<T>>) -> Option<T> {
|
||||
match rx {
|
||||
Some(rx) => rx.recv().await,
|
||||
None => std::future::pending::<Option<T>>().await,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_upload_target(
|
||||
path: Option<String>,
|
||||
file_descriptor: Option<i32>,
|
||||
@@ -245,6 +466,43 @@ fn resolve_upload_target(
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_file_content(
|
||||
path: Option<String>,
|
||||
file_descriptor: Option<i32>,
|
||||
) -> anyhow::Result<FileContent> {
|
||||
match (path, file_descriptor) {
|
||||
(Some(path), None) => Ok(FileContent::Path(path.into())),
|
||||
(None, Some(file_descriptor)) => {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
Ok(FileContent::Fd(file_descriptor))
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let _ = file_descriptor;
|
||||
Err(anyhow::anyhow!(
|
||||
"File descriptors are only supported on Android"
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err(anyhow::anyhow!(
|
||||
"Exactly one download source must be provided"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[frb(mirror(WebSendI18n))]
|
||||
pub struct _WebSendI18n {
|
||||
pub waiting: String,
|
||||
pub enter_pin: String,
|
||||
pub invalid_pin: String,
|
||||
pub too_many_attempts: String,
|
||||
pub rejected: String,
|
||||
pub files: String,
|
||||
pub file_name: String,
|
||||
pub size: String,
|
||||
}
|
||||
|
||||
#[frb(mirror(TlsConfig))]
|
||||
pub struct _TlsConfig {
|
||||
pub cert: String,
|
||||
|
||||
+395
-28
@@ -42,7 +42,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
|
||||
default_rust_auto_opaque = RustAutoOpaqueMoi,
|
||||
);
|
||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
|
||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1220219761;
|
||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1029282510;
|
||||
|
||||
// Section: executor
|
||||
|
||||
@@ -773,6 +773,72 @@ fn wire__crate__api__server__RsHttpServer_listen_impl(
|
||||
},
|
||||
)
|
||||
}
|
||||
fn wire__crate__api__server__RsHttpServer_respond_file_download_impl(
|
||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||
rust_vec_len_: i32,
|
||||
data_len_: i32,
|
||||
) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
|
||||
flutter_rust_bridge::for_generated::TaskInfo {
|
||||
debug_name: "RsHttpServer_respond_file_download",
|
||||
port: Some(port_),
|
||||
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||
},
|
||||
move || {
|
||||
let message = unsafe {
|
||||
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||
ptr_,
|
||||
rust_vec_len_,
|
||||
data_len_,
|
||||
)
|
||||
};
|
||||
let mut deserializer =
|
||||
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||
let api_that = <RustOpaqueMoi<
|
||||
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>,
|
||||
>>::sse_decode(&mut deserializer);
|
||||
let api_session_id = <String>::sse_decode(&mut deserializer);
|
||||
let api_file_id = <String>::sse_decode(&mut deserializer);
|
||||
let api_path = <Option<String>>::sse_decode(&mut deserializer);
|
||||
let api_file_descriptor = <Option<i32>>::sse_decode(&mut deserializer);
|
||||
deserializer.end();
|
||||
move |context| async move {
|
||||
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||
(move || async move {
|
||||
let mut api_that_guard = None;
|
||||
let decode_indices_ =
|
||||
flutter_rust_bridge::for_generated::lockable_compute_decode_order(
|
||||
vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||
&api_that, 0, false,
|
||||
)],
|
||||
);
|
||||
for i in decode_indices_ {
|
||||
match i {
|
||||
0 => {
|
||||
api_that_guard =
|
||||
Some(api_that.lockable_decode_async_ref().await)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
let api_that_guard = api_that_guard.unwrap();
|
||||
let output_ok = crate::api::server::RsHttpServer::respond_file_download(
|
||||
&*api_that_guard,
|
||||
api_session_id,
|
||||
api_file_id,
|
||||
api_path,
|
||||
api_file_descriptor,
|
||||
)
|
||||
.await?;
|
||||
Ok(output_ok)
|
||||
})()
|
||||
.await,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
fn wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
|
||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||
@@ -839,6 +905,68 @@ fn wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
|
||||
},
|
||||
)
|
||||
}
|
||||
fn wire__crate__api__server__RsHttpServer_respond_prepare_download_impl(
|
||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||
rust_vec_len_: i32,
|
||||
data_len_: i32,
|
||||
) {
|
||||
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
|
||||
flutter_rust_bridge::for_generated::TaskInfo {
|
||||
debug_name: "RsHttpServer_respond_prepare_download",
|
||||
port: Some(port_),
|
||||
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||
},
|
||||
move || {
|
||||
let message = unsafe {
|
||||
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||
ptr_,
|
||||
rust_vec_len_,
|
||||
data_len_,
|
||||
)
|
||||
};
|
||||
let mut deserializer =
|
||||
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||
let api_that = <RustOpaqueMoi<
|
||||
flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>,
|
||||
>>::sse_decode(&mut deserializer);
|
||||
let api_session_id = <String>::sse_decode(&mut deserializer);
|
||||
let api_accept = <bool>::sse_decode(&mut deserializer);
|
||||
deserializer.end();
|
||||
move |context| async move {
|
||||
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||
(move || async move {
|
||||
let mut api_that_guard = None;
|
||||
let decode_indices_ =
|
||||
flutter_rust_bridge::for_generated::lockable_compute_decode_order(
|
||||
vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
|
||||
&api_that, 0, false,
|
||||
)],
|
||||
);
|
||||
for i in decode_indices_ {
|
||||
match i {
|
||||
0 => {
|
||||
api_that_guard =
|
||||
Some(api_that.lockable_decode_async_ref().await)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
let api_that_guard = api_that_guard.unwrap();
|
||||
let output_ok = crate::api::server::RsHttpServer::respond_prepare_download(
|
||||
&*api_that_guard,
|
||||
api_session_id,
|
||||
api_accept,
|
||||
)
|
||||
.await?;
|
||||
Ok(output_ok)
|
||||
})()
|
||||
.await,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
fn wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl(
|
||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||
@@ -2146,6 +2274,9 @@ fn wire__crate__api__server__start_server_impl(
|
||||
<Option<crate::api::model::DeviceType>>::sse_decode(&mut deserializer);
|
||||
let api_fingerprint = <String>::sse_decode(&mut deserializer);
|
||||
let api_pin = <Option<String>>::sse_decode(&mut deserializer);
|
||||
let api_web_send =
|
||||
<Option<crate::api::server::WebSendParams>>::sse_decode(&mut deserializer);
|
||||
let api_show_token = <Option<String>>::sse_decode(&mut deserializer);
|
||||
deserializer.end();
|
||||
move |context| async move {
|
||||
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||
@@ -2159,6 +2290,8 @@ fn wire__crate__api__server__start_server_impl(
|
||||
api_device_type,
|
||||
api_fingerprint,
|
||||
api_pin,
|
||||
api_web_send,
|
||||
api_show_token,
|
||||
)
|
||||
.await?;
|
||||
Ok(output_ok)
|
||||
@@ -2322,6 +2455,17 @@ const _: fn() = || {
|
||||
let _: String = TlsConfig.cert;
|
||||
let _: String = TlsConfig.private_key;
|
||||
}
|
||||
{
|
||||
let WebSendI18n = None::<crate::api::server::WebSendI18n>.unwrap();
|
||||
let _: String = WebSendI18n.waiting;
|
||||
let _: String = WebSendI18n.enter_pin;
|
||||
let _: String = WebSendI18n.invalid_pin;
|
||||
let _: String = WebSendI18n.too_many_attempts;
|
||||
let _: String = WebSendI18n.rejected;
|
||||
let _: String = WebSendI18n.files;
|
||||
let _: String = WebSendI18n.file_name;
|
||||
let _: String = WebSendI18n.size;
|
||||
}
|
||||
match None::<crate::api::webrtc::WsServerMessage>.unwrap() {
|
||||
crate::api::webrtc::WsServerMessage::Hello { client, peers } => {
|
||||
let _: crate::api::webrtc::ClientInfo = client;
|
||||
@@ -3087,6 +3231,19 @@ impl SseDecode for Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<crate::api::server::WebSendParams> {
|
||||
// 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(<crate::api::server::WebSendParams>::sse_decode(
|
||||
deserializer,
|
||||
));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for Option<Vec<String>> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -3378,6 +3535,30 @@ impl SseDecode for crate::api::server::RsServerEvent {
|
||||
reason: var_reason,
|
||||
};
|
||||
}
|
||||
4 => {
|
||||
let mut var_ip = <String>::sse_decode(deserializer);
|
||||
let mut var_sessionId = <String>::sse_decode(deserializer);
|
||||
let mut var_userAgent = <Option<String>>::sse_decode(deserializer);
|
||||
return crate::api::server::RsServerEvent::WebPrepareDownload {
|
||||
ip: var_ip,
|
||||
session_id: var_sessionId,
|
||||
user_agent: var_userAgent,
|
||||
};
|
||||
}
|
||||
5 => {
|
||||
let mut var_sessionId = <String>::sse_decode(deserializer);
|
||||
let mut var_fileId = <String>::sse_decode(deserializer);
|
||||
let mut var_file = <crate::api::model::FileDto>::sse_decode(deserializer);
|
||||
return crate::api::server::RsServerEvent::WebFileDownload {
|
||||
session_id: var_sessionId,
|
||||
file_id: var_fileId,
|
||||
file: var_file,
|
||||
};
|
||||
}
|
||||
6 => {
|
||||
let mut var_args = <Vec<String>>::sse_decode(deserializer);
|
||||
return crate::api::server::RsServerEvent::Show { args: var_args };
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
@@ -3512,6 +3693,47 @@ impl SseDecode for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for crate::api::server::WebSendI18n {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
let mut var_waiting = <String>::sse_decode(deserializer);
|
||||
let mut var_enterPin = <String>::sse_decode(deserializer);
|
||||
let mut var_invalidPin = <String>::sse_decode(deserializer);
|
||||
let mut var_tooManyAttempts = <String>::sse_decode(deserializer);
|
||||
let mut var_rejected = <String>::sse_decode(deserializer);
|
||||
let mut var_files = <String>::sse_decode(deserializer);
|
||||
let mut var_fileName = <String>::sse_decode(deserializer);
|
||||
let mut var_size = <String>::sse_decode(deserializer);
|
||||
return crate::api::server::WebSendI18n {
|
||||
waiting: var_waiting,
|
||||
enter_pin: var_enterPin,
|
||||
invalid_pin: var_invalidPin,
|
||||
too_many_attempts: var_tooManyAttempts,
|
||||
rejected: var_rejected,
|
||||
files: var_files,
|
||||
file_name: var_fileName,
|
||||
size: var_size,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for crate::api::server::WebSendParams {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
let mut var_files =
|
||||
<std::collections::HashMap<String, crate::api::model::FileDto>>::sse_decode(
|
||||
deserializer,
|
||||
);
|
||||
let mut var_pin = <Option<String>>::sse_decode(deserializer);
|
||||
let mut var_i18N = <crate::api::server::WebSendI18n>::sse_decode(deserializer);
|
||||
return crate::api::server::WebSendParams {
|
||||
files: var_files,
|
||||
pin: var_pin,
|
||||
i18n: var_i18N,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl SseDecode for crate::api::webrtc::WsServerMessage {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
@@ -3617,118 +3839,130 @@ fn pde_ffi_dispatcher_primary_impl(
|
||||
9 => wire__crate__api__http__RsHttpClient_register_impl(port, ptr, rust_vec_len, data_len),
|
||||
10 => wire__crate__api__http__RsHttpClient_upload_impl(port, ptr, rust_vec_len, data_len),
|
||||
11 => wire__crate__api__server__RsHttpServer_listen_impl(port, ptr, rust_vec_len, data_len),
|
||||
12 => wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
|
||||
12 => wire__crate__api__server__RsHttpServer_respond_file_download_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
13 => wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl(
|
||||
13 => wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
14 => wire__crate__api__server__RsHttpServer_stop_impl(port, ptr, rust_vec_len, data_len),
|
||||
15 => wire__crate__api__webrtc__RtcFileReceiver_get_file_id_impl(
|
||||
14 => wire__crate__api__server__RsHttpServer_respond_prepare_download_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
16 => wire__crate__api__webrtc__RtcFileReceiver_receive_impl(
|
||||
15 => wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
17 => wire__crate__api__webrtc__RtcFileSender_send_impl(port, ptr, rust_vec_len, data_len),
|
||||
18 => wire__crate__api__webrtc__RtcReceiveController_decline_impl(
|
||||
16 => wire__crate__api__server__RsHttpServer_stop_impl(port, ptr, rust_vec_len, data_len),
|
||||
17 => wire__crate__api__webrtc__RtcFileReceiver_get_file_id_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
19 => wire__crate__api__webrtc__RtcReceiveController_listen_error_impl(
|
||||
18 => wire__crate__api__webrtc__RtcFileReceiver_receive_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
20 => wire__crate__api__webrtc__RtcReceiveController_listen_files_impl(
|
||||
19 => wire__crate__api__webrtc__RtcFileSender_send_impl(port, ptr, rust_vec_len, data_len),
|
||||
20 => wire__crate__api__webrtc__RtcReceiveController_decline_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
21 => wire__crate__api__webrtc__RtcReceiveController_listen_receiving_impl(
|
||||
21 => wire__crate__api__webrtc__RtcReceiveController_listen_error_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
22 => wire__crate__api__webrtc__RtcReceiveController_listen_status_impl(
|
||||
22 => wire__crate__api__webrtc__RtcReceiveController_listen_files_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
23 => wire__crate__api__webrtc__RtcReceiveController_send_file_status_impl(
|
||||
23 => wire__crate__api__webrtc__RtcReceiveController_listen_receiving_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
24 => wire__crate__api__webrtc__RtcReceiveController_send_pin_impl(
|
||||
24 => wire__crate__api__webrtc__RtcReceiveController_listen_status_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
25 => wire__crate__api__webrtc__RtcReceiveController_send_selection_impl(
|
||||
25 => wire__crate__api__webrtc__RtcReceiveController_send_file_status_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
26 => wire__crate__api__webrtc__RtcSendController_listen_error_impl(
|
||||
26 => wire__crate__api__webrtc__RtcReceiveController_send_pin_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
27 => wire__crate__api__webrtc__RtcSendController_listen_selected_files_impl(
|
||||
27 => wire__crate__api__webrtc__RtcReceiveController_send_selection_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
28 => wire__crate__api__webrtc__RtcSendController_listen_status_impl(
|
||||
28 => wire__crate__api__webrtc__RtcSendController_listen_error_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
29 => wire__crate__api__webrtc__RtcSendController_send_file_impl(
|
||||
29 => wire__crate__api__webrtc__RtcSendController_listen_selected_files_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
30 => wire__crate__api__webrtc__RtcSendController_send_pin_impl(
|
||||
30 => wire__crate__api__webrtc__RtcSendController_listen_status_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
31 => wire__crate__api__webrtc__connect_impl(port, ptr, rust_vec_len, data_len),
|
||||
34 => wire__crate__api__stream__create_stream_impl(port, ptr, rust_vec_len, data_len),
|
||||
35 => {
|
||||
31 => wire__crate__api__webrtc__RtcSendController_send_file_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
32 => wire__crate__api__webrtc__RtcSendController_send_pin_impl(
|
||||
port,
|
||||
ptr,
|
||||
rust_vec_len,
|
||||
data_len,
|
||||
),
|
||||
33 => wire__crate__api__webrtc__connect_impl(port, ptr, rust_vec_len, data_len),
|
||||
36 => wire__crate__api__stream__create_stream_impl(port, ptr, rust_vec_len, data_len),
|
||||
37 => {
|
||||
wire__crate__api__logging__enable_debug_logging_impl(port, ptr, rust_vec_len, data_len)
|
||||
}
|
||||
36 => wire__crate__api__crypto__generate_key_pair_impl(port, ptr, rust_vec_len, data_len),
|
||||
37 => wire__crate__api__server__start_server_impl(port, ptr, rust_vec_len, data_len),
|
||||
38 => wire__crate__api__crypto__verify_cert_impl(port, ptr, rust_vec_len, data_len),
|
||||
38 => wire__crate__api__crypto__generate_key_pair_impl(port, ptr, rust_vec_len, data_len),
|
||||
39 => wire__crate__api__server__start_server_impl(port, ptr, rust_vec_len, data_len),
|
||||
40 => wire__crate__api__crypto__verify_cert_impl(port, ptr, rust_vec_len, data_len),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -3743,8 +3977,8 @@ fn pde_ffi_dispatcher_sync_impl(
|
||||
match func_id {
|
||||
2 => wire__crate__api__stream__Dart2RustStreamSink_close_impl(ptr, rust_vec_len, data_len),
|
||||
6 => wire__crate__api__http__RsCancellationToken_cancel_impl(ptr, rust_vec_len, data_len),
|
||||
32 => wire__crate__api__http__create_cancellation_token_impl(ptr, rust_vec_len, data_len),
|
||||
33 => wire__crate__api__http__create_client_impl(ptr, rust_vec_len, data_len),
|
||||
34 => wire__crate__api__http__create_cancellation_token_impl(ptr, rust_vec_len, data_len),
|
||||
35 => wire__crate__api__http__create_client_impl(ptr, rust_vec_len, data_len),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -4422,6 +4656,31 @@ impl flutter_rust_bridge::IntoDart for crate::api::server::RsServerEvent {
|
||||
reason.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart(),
|
||||
crate::api::server::RsServerEvent::WebPrepareDownload {
|
||||
ip,
|
||||
session_id,
|
||||
user_agent,
|
||||
} => [
|
||||
4.into_dart(),
|
||||
ip.into_into_dart().into_dart(),
|
||||
session_id.into_into_dart().into_dart(),
|
||||
user_agent.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart(),
|
||||
crate::api::server::RsServerEvent::WebFileDownload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
} => [
|
||||
5.into_dart(),
|
||||
session_id.into_into_dart().into_dart(),
|
||||
file_id.into_into_dart().into_dart(),
|
||||
file.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart(),
|
||||
crate::api::server::RsServerEvent::Show { args } => {
|
||||
[6.into_dart(), args.into_into_dart().into_dart()].into_dart()
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
@@ -4556,6 +4815,55 @@ impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<crate::api::server::TlsConfig>
|
||||
}
|
||||
}
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
impl flutter_rust_bridge::IntoDart for FrbWrapper<crate::api::server::WebSendI18n> {
|
||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||
[
|
||||
self.0.waiting.into_into_dart().into_dart(),
|
||||
self.0.enter_pin.into_into_dart().into_dart(),
|
||||
self.0.invalid_pin.into_into_dart().into_dart(),
|
||||
self.0.too_many_attempts.into_into_dart().into_dart(),
|
||||
self.0.rejected.into_into_dart().into_dart(),
|
||||
self.0.files.into_into_dart().into_dart(),
|
||||
self.0.file_name.into_into_dart().into_dart(),
|
||||
self.0.size.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart()
|
||||
}
|
||||
}
|
||||
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||
for FrbWrapper<crate::api::server::WebSendI18n>
|
||||
{
|
||||
}
|
||||
impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<crate::api::server::WebSendI18n>>
|
||||
for crate::api::server::WebSendI18n
|
||||
{
|
||||
fn into_into_dart(self) -> FrbWrapper<crate::api::server::WebSendI18n> {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
impl flutter_rust_bridge::IntoDart for crate::api::server::WebSendParams {
|
||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||
[
|
||||
self.files.into_into_dart().into_dart(),
|
||||
self.pin.into_into_dart().into_dart(),
|
||||
self.i18n.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart()
|
||||
}
|
||||
}
|
||||
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||
for crate::api::server::WebSendParams
|
||||
{
|
||||
}
|
||||
impl flutter_rust_bridge::IntoIntoDart<crate::api::server::WebSendParams>
|
||||
for crate::api::server::WebSendParams
|
||||
{
|
||||
fn into_into_dart(self) -> crate::api::server::WebSendParams {
|
||||
self
|
||||
}
|
||||
}
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
impl flutter_rust_bridge::IntoDart for FrbWrapper<crate::api::webrtc::WsServerMessage> {
|
||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||
match self.0 {
|
||||
@@ -5220,6 +5528,16 @@ impl SseEncode for Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<crate::api::server::WebSendParams> {
|
||||
// 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 {
|
||||
<crate::api::server::WebSendParams>::sse_encode(value, serializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for Option<Vec<String>> {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
@@ -5445,6 +5763,30 @@ impl SseEncode for crate::api::server::RsServerEvent {
|
||||
<String>::sse_encode(session_id, serializer);
|
||||
<crate::api::server::SessionEndReasonV2>::sse_encode(reason, serializer);
|
||||
}
|
||||
crate::api::server::RsServerEvent::WebPrepareDownload {
|
||||
ip,
|
||||
session_id,
|
||||
user_agent,
|
||||
} => {
|
||||
<i32>::sse_encode(4, serializer);
|
||||
<String>::sse_encode(ip, serializer);
|
||||
<String>::sse_encode(session_id, serializer);
|
||||
<Option<String>>::sse_encode(user_agent, serializer);
|
||||
}
|
||||
crate::api::server::RsServerEvent::WebFileDownload {
|
||||
session_id,
|
||||
file_id,
|
||||
file,
|
||||
} => {
|
||||
<i32>::sse_encode(5, serializer);
|
||||
<String>::sse_encode(session_id, serializer);
|
||||
<String>::sse_encode(file_id, serializer);
|
||||
<crate::api::model::FileDto>::sse_encode(file, serializer);
|
||||
}
|
||||
crate::api::server::RsServerEvent::Show { args } => {
|
||||
<i32>::sse_encode(6, serializer);
|
||||
<Vec<String>>::sse_encode(args, serializer);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
@@ -5572,6 +5914,31 @@ impl SseEncode for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for crate::api::server::WebSendI18n {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
<String>::sse_encode(self.waiting, serializer);
|
||||
<String>::sse_encode(self.enter_pin, serializer);
|
||||
<String>::sse_encode(self.invalid_pin, serializer);
|
||||
<String>::sse_encode(self.too_many_attempts, serializer);
|
||||
<String>::sse_encode(self.rejected, serializer);
|
||||
<String>::sse_encode(self.files, serializer);
|
||||
<String>::sse_encode(self.file_name, serializer);
|
||||
<String>::sse_encode(self.size, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for crate::api::server::WebSendParams {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
<std::collections::HashMap<String, crate::api::model::FileDto>>::sse_encode(
|
||||
self.files, serializer,
|
||||
);
|
||||
<Option<String>>::sse_encode(self.pin, serializer);
|
||||
<crate::api::server::WebSendI18n>::sse_encode(self.i18n, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
impl SseEncode for crate::api::webrtc::WsServerMessage {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg(feature = "http")]
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures_util::StreamExt;
|
||||
use localsend::http::client::{ClientError, LsHttpClientV2};
|
||||
use localsend::http::dto::ProtocolType;
|
||||
use localsend::http::dto_v2::{PrepareUploadRequestDtoV2, ProtocolTypeV2, RegisterDtoV2};
|
||||
@@ -14,7 +15,6 @@ use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicU16, AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use futures_util::StreamExt;
|
||||
use tokio::sync::{mpsc, oneshot, Mutex};
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
@@ -223,12 +223,11 @@ async fn upload_bytes(
|
||||
// The caller now owns building the request body; track cumulative bytes
|
||||
// sent so the progress assertion below still holds.
|
||||
let progress = sent.clone();
|
||||
let body = localsend::reqwest::Body::wrap_stream(ReceiverStream::new(rx).map(
|
||||
move |chunk: Bytes| {
|
||||
let body =
|
||||
localsend::reqwest::Body::wrap_stream(ReceiverStream::new(rx).map(move |chunk: Bytes| {
|
||||
progress.fetch_add(chunk.len() as u64, Ordering::Relaxed);
|
||||
Ok::<Bytes, std::io::Error>(chunk)
|
||||
},
|
||||
));
|
||||
}));
|
||||
let result = client
|
||||
.upload(
|
||||
ProtocolType::Http,
|
||||
|
||||
Reference in New Issue
Block a user