feat: add web send and /show bindings
CI / format (push) Has been cancelled
CI / test (push) Has been cancelled
CI / packaging (push) Has been cancelled

This commit is contained in:
Tien Do Nam
2026-07-17 15:53:01 +02:00
parent d108a9c0de
commit bee0718733
11 changed files with 1660 additions and 118 deletions
@@ -20,8 +20,18 @@ class HttpServerStartTask implements BaseHttpServerTask {
/// Optional PIN that senders must provide to start an upload session. /// Optional PIN that senders must provide to start an upload session.
final String? pin; 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({ HttpServerStartTask({
required this.pin, 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. /// A message sent from the server isolate to the main isolate.
sealed class HttpServerEvent {} 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( Future<void> setupHttpServerIsolate(
Stream<SendToIsolateData<IsolateTask<BaseHttpServerTask>>> receiveFromMain, Stream<SendToIsolateData<IsolateTask<BaseHttpServerTask>>> receiveFromMain,
void Function(IsolateTaskStreamResult<HttpServerEvent>) sendToMain, void Function(IsolateTaskStreamResult<HttpServerEvent>) sendToMain,
@@ -157,6 +236,8 @@ Future<void> setupHttpServerIsolate(
deviceType: syncState.deviceInfo.deviceType.toRust(), deviceType: syncState.deviceInfo.deviceType.toRust(),
fingerprint: syncState.securityContext.certificateHash, fingerprint: syncState.securityContext.certificateHash,
pin: startTask.pin, pin: startTask.pin,
webSend: startTask.webSend,
showToken: startTask.showToken,
); );
try { try {
@@ -180,6 +261,17 @@ Future<void> setupHttpServerIsolate(
sessionId: sessionId, sessionId: sessionId,
reason: reason, 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; 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/child/upload_isolate.dart';
import 'package:localsend_app/isolate/src/isolate/dto/send_to_isolate_data.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/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:refena_flutter/refena_flutter.dart';
import 'package:typed_isolates/id.dart'; import 'package:typed_isolates/id.dart';
import 'package:typed_isolates/typed_isolates.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>> { class IsolateHttpServerStartAction extends ReduxActionWithResult<IsolateController, ParentIsolateState, Stream<HttpServerEvent>> {
final String? pin; 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({ IsolateHttpServerStartAction({
required this.pin, required this.pin,
required this.webSend,
required this.showToken,
}); });
@override @override
@@ -209,6 +220,8 @@ class IsolateHttpServerStartAction extends ReduxActionWithResult<IsolateControll
connection.sendWrappedTaskAndListenStream( connection.sendWrappedTaskAndListenStream(
task: HttpServerStartTask( task: HttpServerStartTask(
pin: pin, 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. /// Saving a file received by the HTTP server failed.
class HttpServerFileUploadException implements Exception { class HttpServerFileUploadException implements Exception {
final String message; final String message;
@@ -22,6 +22,8 @@ class HttpServerService {
required DeviceType? deviceType, required DeviceType? deviceType,
required String fingerprint, required String fingerprint,
required String? pin, required String? pin,
required WebSendParams? webSend,
required String? showToken,
}) async { }) async {
if (_server != null) { if (_server != null) {
throw StateError('Server already running'); throw StateError('Server already running');
@@ -36,6 +38,8 @@ class HttpServerService {
deviceType: deviceType, deviceType: deviceType,
fingerprint: fingerprint, fingerprint: fingerprint,
pin: pin, pin: pin,
webSend: webSend,
showToken: showToken,
); );
_server = server; _server = server;
return server.listen(); 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. /// Stops the server. The event stream returned by [start] will end.
Future<void> stop() async { Future<void> stop() async {
final server = _server; final server = _server;
+128 -1
View File
@@ -10,11 +10,18 @@ import 'package:localsend_app/rust/frb_generated.dart';
part 'server.freezed.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). /// Starts the HTTP server on the given port (IPv4 and IPv6).
/// The server runs until [RsHttpServer::stop] is called. /// 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]. /// Events are received by listening to [RsHttpServer::listen].
Future<RsHttpServer> startServer({ Future<RsHttpServer> startServer({
required int port, required int port,
@@ -25,6 +32,8 @@ Future<RsHttpServer> startServer({
DeviceType? deviceType, DeviceType? deviceType,
required String fingerprint, required String fingerprint,
String? pin, String? pin,
WebSendParams? webSend,
String? showToken,
}) => RustLib.instance.api.crateApiServerStartServer( }) => RustLib.instance.api.crateApiServerStartServer(
port: port, port: port,
tls: tls, tls: tls,
@@ -34,19 +43,35 @@ Future<RsHttpServer> startServer({
deviceType: deviceType, deviceType: deviceType,
fingerprint: fingerprint, fingerprint: fingerprint,
pin: pin, pin: pin,
webSend: webSend,
showToken: showToken,
); );
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>> // Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>>
abstract class RsHttpServer implements RustOpaqueInterface { abstract class RsHttpServer implements RustOpaqueInterface {
/// Emits server events until the server is stopped. /// Emits server events until the server is stopped.
/// Can only be listened to once. /// 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(); 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 /// Answers the pending [RsServerEvent::FileUpload] event with the target
/// the file should be saved to (either a path or a file descriptor) /// the file should be saved to (either a path or a file descriptor)
/// and waits until the file has been received completely. /// and waits until the file has been received completely.
Future<void> respondFileUpload({required String sessionId, required String fileId, String? path, int? fileDescriptor}); 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. /// Answers the pending [RsServerEvent::PrepareUpload] event.
/// ///
/// Passing the accepted file IDs (a subset of the offered files) accepts the request. /// 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 String sessionId,
required SessionEndReasonV2 reason, required SessionEndReasonV2 reason,
}) = RsServerEvent_SessionEnd; }) = 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 { enum SessionEndReasonV2 {
@@ -161,3 +211,80 @@ class TlsConfig {
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || other is TlsConfig && runtimeType == other.runtimeType && cert == other.cert && privateKey == other.privateKey; 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;
}
+244 -12
View File
@@ -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; final _that = this;
switch (_that) { switch (_that) {
case RsServerEvent_Register() when register != null: case RsServerEvent_Register() when register != null:
return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null: return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null:
return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null: return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null:
return fileUpload(_that);case RsServerEvent_SessionEnd() when sessionEnd != 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(); 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; final _that = this;
switch (_that) { switch (_that) {
case RsServerEvent_Register(): case RsServerEvent_Register():
return register(_that);case RsServerEvent_PrepareUpload(): return register(_that);case RsServerEvent_PrepareUpload():
return prepareUpload(_that);case RsServerEvent_FileUpload(): return prepareUpload(_that);case RsServerEvent_FileUpload():
return fileUpload(_that);case RsServerEvent_SessionEnd(): 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`. /// 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; final _that = this;
switch (_that) { switch (_that) {
case RsServerEvent_Register() when register != null: case RsServerEvent_Register() when register != null:
return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null: return register(_that);case RsServerEvent_PrepareUpload() when prepareUpload != null:
return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null: return prepareUpload(_that);case RsServerEvent_FileUpload() when fileUpload != null:
return fileUpload(_that);case RsServerEvent_SessionEnd() when sessionEnd != 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; 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) { switch (_that) {
case RsServerEvent_Register() when register != null: case RsServerEvent_Register() when register != null:
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload() when prepareUpload != 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 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 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(); 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) { switch (_that) {
case RsServerEvent_Register(): case RsServerEvent_Register():
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload(): return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload():
return prepareUpload(_that.ip,_that.info,_that.files);case RsServerEvent_FileUpload(): return prepareUpload(_that.ip,_that.info,_that.files);case RsServerEvent_FileUpload():
return fileUpload(_that.sessionId,_that.fileId,_that.file);case RsServerEvent_SessionEnd(): 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` /// 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) { switch (_that) {
case RsServerEvent_Register() when register != null: case RsServerEvent_Register() when register != null:
return register(_that.ip,_that.info);case RsServerEvent_PrepareUpload() when prepareUpload != 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 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 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; 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 // dart format on
+293 -30
View File
@@ -72,7 +72,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.12.0'; String get codegenVersion => '2.12.0';
@override @override
int get rustContentHash => -1220219761; int get rustContentHash => -1029282510;
static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig(
stem: 'rust_lib_localsend_app', stem: 'rust_lib_localsend_app',
@@ -154,6 +154,14 @@ abstract class RustLibApi extends BaseApi {
Stream<RsServerEvent> crateApiServerRsHttpServerListen({required RsHttpServer that}); 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({ Future<void> crateApiServerRsHttpServerRespondFileUpload({
required RsHttpServer that, required RsHttpServer that,
required String sessionId, required String sessionId,
@@ -162,6 +170,8 @@ abstract class RustLibApi extends BaseApi {
int? fileDescriptor, 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> crateApiServerRsHttpServerRespondPrepareUpload({required RsHttpServer that, List<String>? acceptedFileIds});
Future<void> crateApiServerRsHttpServerStop({required RsHttpServer that}); Future<void> crateApiServerRsHttpServerStop({required RsHttpServer that});
@@ -224,6 +234,8 @@ abstract class RustLibApi extends BaseApi {
DeviceType? deviceType, DeviceType? deviceType,
required String fingerprint, required String fingerprint,
String? pin, String? pin,
WebSendParams? webSend,
String? showToken,
}); });
Future<void> crateApiCryptoVerifyCert({required String cert, required String publicKey}); Future<void> crateApiCryptoVerifyCert({required String cert, required String publicKey});
@@ -689,7 +701,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
); );
@override @override
Future<void> crateApiServerRsHttpServerRespondFileUpload({ Future<void> crateApiServerRsHttpServerRespondFileDownload({
required RsHttpServer that, required RsHttpServer that,
required String sessionId, required String sessionId,
required String fileId, required String fileId,
@@ -711,6 +723,41 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
decodeErrorData: sse_decode_AnyhowException, 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, constMeta: kCrateApiServerRsHttpServerRespondFileUploadConstMeta,
argValues: [that, sessionId, fileId, path, fileDescriptor], argValues: [that, sessionId, fileId, path, fileDescriptor],
apiImpl: this, apiImpl: this,
@@ -723,6 +770,33 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ['that', 'sessionId', 'fileId', 'path', 'fileDescriptor'], 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 @override
Future<void> crateApiServerRsHttpServerRespondPrepareUpload({required RsHttpServer that, List<String>? acceptedFileIds}) { Future<void> crateApiServerRsHttpServerRespondPrepareUpload({required RsHttpServer that, List<String>? acceptedFileIds}) {
return handler.executeNormal( return handler.executeNormal(
@@ -731,7 +805,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer);
sse_encode_opt_list_String(acceptedFileIds, serializer); sse_encode_opt_list_String(acceptedFileIds, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 13, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 15, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -756,7 +830,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer(that, serializer); 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -781,7 +855,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(that, serializer); 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( codec: SseCodec(
decodeSuccessData: sse_decode_String, decodeSuccessData: sse_decode_String,
@@ -809,7 +883,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver(that, serializer);
sse_encode_StreamSink_list_prim_u_8_strict_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -837,7 +911,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender(that, serializer);
sse_encode_list_prim_u_8_loose(data, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -862,7 +936,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -890,7 +964,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_StreamSink_rtc_file_error_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -917,7 +991,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); 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( codec: SseCodec(
decodeSuccessData: sse_decode_list_file_dto, decodeSuccessData: sse_decode_list_file_dto,
@@ -945,7 +1019,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_StreamSink_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileReceiver_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -975,7 +1049,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_StreamSink_rtc_status_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1003,7 +1077,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_box_autoadd_rtc_send_file_response(status, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1029,7 +1103,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_String(pin, serializer); sse_encode_String(pin, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 24, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 26, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1055,7 +1129,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCReceiveController(that, serializer);
sse_encode_Set_String_None(selection, serializer); sse_encode_Set_String_None(selection, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 25, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 27, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1083,7 +1157,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer); sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
sse_encode_StreamSink_rtc_file_error_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1110,7 +1184,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer); 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( codec: SseCodec(
decodeSuccessData: sse_decode_Set_String_None, decodeSuccessData: sse_decode_Set_String_None,
@@ -1138,7 +1212,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer); sse_encode_Auto_RefMut_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
sse_encode_StreamSink_rtc_status_Sse(sink, 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( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1166,7 +1240,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
sse_encode_String(fileId, serializer); sse_encode_String(fileId, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 29, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 31, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender, decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCFileSender,
@@ -1192,7 +1266,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer); sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRTCSendController(that, serializer);
sse_encode_String(pin, serializer); sse_encode_String(pin, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 30, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 32, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1231,7 +1305,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
onConnection, onConnection,
serializer, serializer,
); );
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 31, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 33, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1257,7 +1331,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
SyncTask( SyncTask(
callFfi: () { callFfi: () {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 32)!; return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 34)!;
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsCancellationToken, 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_String(cert, serializer);
sse_encode_ls_http_client_version(version, serializer); sse_encode_ls_http_client_version(version, serializer);
sse_encode_opt_box_autoadd_u_32(timeoutMs, serializer); sse_encode_opt_box_autoadd_u_32(timeoutMs, serializer);
return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 33)!; return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 35)!;
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpClient, decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpClient,
@@ -1309,7 +1383,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
NormalTask( NormalTask(
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 34, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 36, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: decodeSuccessData:
@@ -1334,7 +1408,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
NormalTask( NormalTask(
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 35, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 37, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1358,7 +1432,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
NormalTask( NormalTask(
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 36, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 38, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_key_pair, decodeSuccessData: sse_decode_key_pair,
@@ -1386,6 +1460,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
DeviceType? deviceType, DeviceType? deviceType,
required String fingerprint, required String fingerprint,
String? pin, String? pin,
WebSendParams? webSend,
String? showToken,
}) { }) {
return handler.executeNormal( return handler.executeNormal(
NormalTask( NormalTask(
@@ -1399,14 +1475,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_opt_box_autoadd_device_type(deviceType, serializer); sse_encode_opt_box_autoadd_device_type(deviceType, serializer);
sse_encode_String(fingerprint, serializer); sse_encode_String(fingerprint, serializer);
sse_encode_opt_String(pin, 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( codec: SseCodec(
decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer, decodeSuccessData: sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerRsHttpServer,
decodeErrorData: sse_decode_AnyhowException, decodeErrorData: sse_decode_AnyhowException,
), ),
constMeta: kCrateApiServerStartServerConstMeta, constMeta: kCrateApiServerStartServerConstMeta,
argValues: [port, tls, alias, version, deviceModel, deviceType, fingerprint, pin], argValues: [port, tls, alias, version, deviceModel, deviceType, fingerprint, pin, webSend, showToken],
apiImpl: this, apiImpl: this,
), ),
); );
@@ -1414,7 +1492,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiServerStartServerConstMeta => const TaskConstMeta( TaskConstMeta get kCrateApiServerStartServerConstMeta => const TaskConstMeta(
debugName: 'start_server', debugName: 'start_server',
argNames: ['port', 'tls', 'alias', 'version', 'deviceModel', 'deviceType', 'fingerprint', 'pin'], argNames: ['port', 'tls', 'alias', 'version', 'deviceModel', 'deviceType', 'fingerprint', 'pin', 'webSend', 'showToken'],
); );
@override @override
@@ -1425,7 +1503,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_String(cert, serializer); sse_encode_String(cert, serializer);
sse_encode_String(publicKey, serializer); sse_encode_String(publicKey, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 38, port: port_); pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 40, port: port_);
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
@@ -1918,6 +1996,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as int; 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 @protected
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw) { WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // 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); 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 @protected
List<String>? dco_decode_opt_list_String(dynamic raw) { List<String>? dco_decode_opt_list_String(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // 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]), sessionId: dco_decode_String(raw[1]),
reason: dco_decode_session_end_reason_v_2(raw[2]), 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: default:
throw Exception('unreachable'); throw Exception('unreachable');
} }
@@ -2478,6 +2584,35 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return dcoDecodeU64(raw); 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 @protected
WsServerMessage dco_decode_ws_server_message(dynamic raw) { WsServerMessage dco_decode_ws_server_message(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // 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)); 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 @protected
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer) { WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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 @protected
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer) { List<String>? sse_decode_opt_list_String(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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_sessionId = sse_decode_String(deserializer);
var var_reason = sse_decode_session_end_reason_v_2(deserializer); var var_reason = sse_decode_session_end_reason_v_2(deserializer);
return RsServerEvent_SessionEnd(sessionId: var_sessionId, reason: var_reason); 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: default:
throw UnimplementedError(''); throw UnimplementedError('');
} }
@@ -3548,6 +3713,38 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getBigUint64(); 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 @protected
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer) { WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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); 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 @protected
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer) { void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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 @protected
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer) { void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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_i_32(3, serializer);
sse_encode_String(sessionId, serializer); sse_encode_String(sessionId, serializer);
sse_encode_session_end_reason_v_2(reason, 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); 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 @protected
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer) { void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // 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. /// Emits server events until the server is stopped.
/// Can only be listened to once. /// 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( Stream<RsServerEvent> listen() => RustLib.instance.api.crateApiServerRsHttpServerListen(
that: this, 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 /// Answers the pending [RsServerEvent::FileUpload] event with the target
/// the file should be saved to (either a path or a file descriptor) /// the file should be saved to (either a path or a file descriptor)
/// and waits until the file has been received completely. /// 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 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); .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. /// Answers the pending [RsServerEvent::PrepareUpload] event.
/// ///
/// Passing the accepted file IDs (a subset of the offered files) accepts the request. /// Passing the accepted file IDs (a subset of the offered files) accepts the request.
+36
View File
@@ -252,6 +252,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int dco_decode_box_autoadd_u_32(dynamic raw); int dco_decode_box_autoadd_u_32(dynamic raw);
@protected
WebSendParams dco_decode_box_autoadd_web_send_params(dynamic raw);
@protected @protected
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw); WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
@@ -340,6 +343,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int? dco_decode_opt_box_autoadd_u_32(dynamic raw); int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
@protected
WebSendParams? dco_decode_opt_box_autoadd_web_send_params(dynamic raw);
@protected @protected
List<String>? dco_decode_opt_list_String(dynamic raw); List<String>? dco_decode_opt_list_String(dynamic raw);
@@ -427,6 +433,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
BigInt dco_decode_usize(dynamic raw); 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 @protected
WsServerMessage dco_decode_ws_server_message(dynamic raw); WsServerMessage dco_decode_ws_server_message(dynamic raw);
@@ -647,6 +659,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer); int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
@protected
WebSendParams sse_decode_box_autoadd_web_send_params(SseDeserializer deserializer);
@protected @protected
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer); WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer);
@@ -737,6 +752,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer); int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
@protected
WebSendParams? sse_decode_opt_box_autoadd_web_send_params(SseDeserializer deserializer);
@protected @protected
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer); List<String>? sse_decode_opt_list_String(SseDeserializer deserializer);
@@ -824,6 +842,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
BigInt sse_decode_usize(SseDeserializer deserializer); 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 @protected
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer); WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
@@ -1089,6 +1113,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer); 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 @protected
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer); void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer);
@@ -1179,6 +1206,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer); 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 @protected
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer); void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer);
@@ -1267,6 +1297,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_usize(BigInt self, SseSerializer serializer); 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 @protected
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer); void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer);
+36
View File
@@ -254,6 +254,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int dco_decode_box_autoadd_u_32(dynamic raw); int dco_decode_box_autoadd_u_32(dynamic raw);
@protected
WebSendParams dco_decode_box_autoadd_web_send_params(dynamic raw);
@protected @protected
WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw); WsServerSdpMessage dco_decode_box_autoadd_ws_server_sdp_message(dynamic raw);
@@ -342,6 +345,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int? dco_decode_opt_box_autoadd_u_32(dynamic raw); int? dco_decode_opt_box_autoadd_u_32(dynamic raw);
@protected
WebSendParams? dco_decode_opt_box_autoadd_web_send_params(dynamic raw);
@protected @protected
List<String>? dco_decode_opt_list_String(dynamic raw); List<String>? dco_decode_opt_list_String(dynamic raw);
@@ -429,6 +435,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
BigInt dco_decode_usize(dynamic raw); 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 @protected
WsServerMessage dco_decode_ws_server_message(dynamic raw); WsServerMessage dco_decode_ws_server_message(dynamic raw);
@@ -649,6 +661,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int sse_decode_box_autoadd_u_32(SseDeserializer deserializer); int sse_decode_box_autoadd_u_32(SseDeserializer deserializer);
@protected
WebSendParams sse_decode_box_autoadd_web_send_params(SseDeserializer deserializer);
@protected @protected
WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer); WsServerSdpMessage sse_decode_box_autoadd_ws_server_sdp_message(SseDeserializer deserializer);
@@ -739,6 +754,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer); int? sse_decode_opt_box_autoadd_u_32(SseDeserializer deserializer);
@protected
WebSendParams? sse_decode_opt_box_autoadd_web_send_params(SseDeserializer deserializer);
@protected @protected
List<String>? sse_decode_opt_list_String(SseDeserializer deserializer); List<String>? sse_decode_opt_list_String(SseDeserializer deserializer);
@@ -826,6 +844,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
BigInt sse_decode_usize(SseDeserializer deserializer); 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 @protected
WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer); WsServerMessage sse_decode_ws_server_message(SseDeserializer deserializer);
@@ -1091,6 +1115,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_box_autoadd_u_32(int self, SseSerializer serializer); 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 @protected
void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer); void sse_encode_box_autoadd_ws_server_sdp_message(WsServerSdpMessage self, SseSerializer serializer);
@@ -1181,6 +1208,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_opt_box_autoadd_u_32(int? self, SseSerializer serializer); 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 @protected
void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer); void sse_encode_opt_list_String(List<String>? self, SseSerializer serializer);
@@ -1269,6 +1299,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_usize(BigInt self, SseSerializer serializer); 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 @protected
void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer); void sse_encode_ws_server_message(WsServerMessage self, SseSerializer serializer);
+262 -4
View File
@@ -4,11 +4,14 @@ pub use localsend::http::dto_v2::{ProtocolTypeV2, RegisterDtoV2};
use localsend::http::server::ServerConfigV2; use localsend::http::server::ServerConfigV2;
pub use localsend::http::server::TlsConfig; pub use localsend::http::server::TlsConfig;
use localsend::http::server::common::save::FileUploadTarget; use localsend::http::server::common::save::FileUploadTarget;
use localsend::http::server::internal::{InternalConfig, InternalEvent};
pub use localsend::http::server::v2::SessionEndReasonV2; pub use localsend::http::server::v2::SessionEndReasonV2;
use localsend::http::server::v2::{PrepareUploadDecisionV2, ServerEventV2}; 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::http::state::ClientInfo;
use localsend::model::discovery::DeviceType; use localsend::model::discovery::DeviceType;
use localsend::model::transfer::FileDto; use localsend::model::transfer::{FileContent, FileDto};
use std::collections::HashMap; use std::collections::HashMap;
use tokio::sync::{Mutex, mpsc, oneshot}; use tokio::sync::{Mutex, mpsc, oneshot};
@@ -39,6 +42,31 @@ pub enum RsServerEvent {
session_id: String, session_id: String,
reason: SessionEndReasonV2, 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 { pub struct RsHttpServer {
@@ -46,11 +74,38 @@ pub struct RsHttpServer {
stop_tx: Mutex<Option<oneshot::Sender<()>>>, stop_tx: Mutex<Option<oneshot::Sender<()>>>,
pending_decision: Mutex<Option<oneshot::Sender<PrepareUploadDecisionV2>>>, pending_decision: Mutex<Option<oneshot::Sender<PrepareUploadDecisionV2>>>,
pending_uploads: Mutex<HashMap<(String, String), oneshot::Sender<FileUploadTarget>>>, 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). /// Starts the HTTP server on the given port (IPv4 and IPv6).
/// The server runs until [RsHttpServer::stop] is called. /// 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]. /// Events are received by listening to [RsHttpServer::listen].
pub async fn start_server( pub async fn start_server(
port: u16, port: u16,
@@ -61,10 +116,38 @@ pub async fn start_server(
device_type: Option<DeviceType>, device_type: Option<DeviceType>,
fingerprint: String, fingerprint: String,
pin: Option<String>, pin: Option<String>,
web_send: Option<WebSendParams>,
show_token: Option<String>,
) -> anyhow::Result<RsHttpServer> { ) -> anyhow::Result<RsHttpServer> {
let (event_tx, event_rx) = mpsc::channel::<ServerEventV2>(16); let (event_tx, event_rx) = mpsc::channel::<ServerEventV2>(16);
let (stop_tx, stop_rx) = oneshot::channel::<()>(); 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( localsend::http::server::start_with_port(
port, port,
tls, tls,
@@ -75,9 +158,9 @@ pub async fn start_server(
device_type, device_type,
token: fingerprint, token: fingerprint,
}, },
None, internal_config,
Some(ServerConfigV2 { pin, event_tx }), Some(ServerConfigV2 { pin, event_tx }),
None, web_send_config,
stop_rx, stop_rx,
) )
.await?; .await?;
@@ -87,19 +170,59 @@ pub async fn start_server(
stop_tx: Mutex::new(Some(stop_tx)), stop_tx: Mutex::new(Some(stop_tx)),
pending_decision: Mutex::new(None), pending_decision: Mutex::new(None),
pending_uploads: Mutex::new(HashMap::new()), 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 { impl RsHttpServer {
/// Emits server events until the server is stopped. /// Emits server events until the server is stopped.
/// Can only be listened to once. /// 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>) { pub async fn listen(&self, sink: StreamSink<RsServerEvent>) {
let Some(mut event_rx) = self.event_rx.lock().await.take() else { let Some(mut event_rx) = self.event_rx.lock().await.take() else {
let _ = sink.add_error(anyhow::anyhow!("Server events already listened to")); let _ = sink.add_error(anyhow::anyhow!("Server events already listened to"));
return; 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 { 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,
}
}
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 { match event {
ServerEventV2::Register { ip, info } => { ServerEventV2::Register { ip, info } => {
let _ = sink.add(RsServerEvent::Register { let _ = sink.add(RsServerEvent::Register {
@@ -146,6 +269,42 @@ impl RsHttpServer {
} }
} }
} }
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,
});
}
}
} }
/// Answers the pending [RsServerEvent::PrepareUpload] event. /// Answers the pending [RsServerEvent::PrepareUpload] event.
@@ -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. /// Stops the server.
pub async fn stop(&self) { pub async fn stop(&self) {
if let Some(stop_tx) = self.stop_tx.lock().await.take() { 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( fn resolve_upload_target(
path: Option<String>, path: Option<String>,
file_descriptor: Option<i32>, 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))] #[frb(mirror(TlsConfig))]
pub struct _TlsConfig { pub struct _TlsConfig {
pub cert: String, pub cert: String,
+395 -28
View File
@@ -42,7 +42,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
default_rust_auto_opaque = RustAutoOpaqueMoi, default_rust_auto_opaque = RustAutoOpaqueMoi,
); );
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; 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 // 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( fn wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
port_: flutter_rust_bridge::for_generated::MessagePort, port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, 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( fn wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl(
port_: flutter_rust_bridge::for_generated::MessagePort, port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, 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); <Option<crate::api::model::DeviceType>>::sse_decode(&mut deserializer);
let api_fingerprint = <String>::sse_decode(&mut deserializer); let api_fingerprint = <String>::sse_decode(&mut deserializer);
let api_pin = <Option<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(); deserializer.end();
move |context| async move { move |context| async move {
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( 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_device_type,
api_fingerprint, api_fingerprint,
api_pin, api_pin,
api_web_send,
api_show_token,
) )
.await?; .await?;
Ok(output_ok) Ok(output_ok)
@@ -2322,6 +2455,17 @@ const _: fn() = || {
let _: String = TlsConfig.cert; let _: String = TlsConfig.cert;
let _: String = TlsConfig.private_key; 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() { match None::<crate::api::webrtc::WsServerMessage>.unwrap() {
crate::api::webrtc::WsServerMessage::Hello { client, peers } => { crate::api::webrtc::WsServerMessage::Hello { client, peers } => {
let _: crate::api::webrtc::ClientInfo = client; 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>> { impl SseDecode for Option<Vec<String>> {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { 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, 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!(""); 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 { impl SseDecode for crate::api::webrtc::WsServerMessage {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { 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), 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), 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), 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, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
13 => wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl( 13 => wire__crate__api__server__RsHttpServer_respond_file_upload_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
14 => wire__crate__api__server__RsHttpServer_stop_impl(port, ptr, rust_vec_len, data_len), 14 => wire__crate__api__server__RsHttpServer_respond_prepare_download_impl(
15 => wire__crate__api__webrtc__RtcFileReceiver_get_file_id_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
16 => wire__crate__api__webrtc__RtcFileReceiver_receive_impl( 15 => wire__crate__api__server__RsHttpServer_respond_prepare_upload_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
17 => wire__crate__api__webrtc__RtcFileSender_send_impl(port, ptr, rust_vec_len, data_len), 16 => wire__crate__api__server__RsHttpServer_stop_impl(port, ptr, rust_vec_len, data_len),
18 => wire__crate__api__webrtc__RtcReceiveController_decline_impl( 17 => wire__crate__api__webrtc__RtcFileReceiver_get_file_id_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
19 => wire__crate__api__webrtc__RtcReceiveController_listen_error_impl( 18 => wire__crate__api__webrtc__RtcFileReceiver_receive_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_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, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
21 => wire__crate__api__webrtc__RtcReceiveController_listen_receiving_impl( 21 => wire__crate__api__webrtc__RtcReceiveController_listen_error_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
22 => wire__crate__api__webrtc__RtcReceiveController_listen_status_impl( 22 => wire__crate__api__webrtc__RtcReceiveController_listen_files_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
23 => wire__crate__api__webrtc__RtcReceiveController_send_file_status_impl( 23 => wire__crate__api__webrtc__RtcReceiveController_listen_receiving_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
24 => wire__crate__api__webrtc__RtcReceiveController_send_pin_impl( 24 => wire__crate__api__webrtc__RtcReceiveController_listen_status_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
25 => wire__crate__api__webrtc__RtcReceiveController_send_selection_impl( 25 => wire__crate__api__webrtc__RtcReceiveController_send_file_status_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
26 => wire__crate__api__webrtc__RtcSendController_listen_error_impl( 26 => wire__crate__api__webrtc__RtcReceiveController_send_pin_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
27 => wire__crate__api__webrtc__RtcSendController_listen_selected_files_impl( 27 => wire__crate__api__webrtc__RtcReceiveController_send_selection_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
28 => wire__crate__api__webrtc__RtcSendController_listen_status_impl( 28 => wire__crate__api__webrtc__RtcSendController_listen_error_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
29 => wire__crate__api__webrtc__RtcSendController_send_file_impl( 29 => wire__crate__api__webrtc__RtcSendController_listen_selected_files_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
30 => wire__crate__api__webrtc__RtcSendController_send_pin_impl( 30 => wire__crate__api__webrtc__RtcSendController_listen_status_impl(
port, port,
ptr, ptr,
rust_vec_len, rust_vec_len,
data_len, data_len,
), ),
31 => wire__crate__api__webrtc__connect_impl(port, ptr, rust_vec_len, data_len), 31 => wire__crate__api__webrtc__RtcSendController_send_file_impl(
34 => wire__crate__api__stream__create_stream_impl(port, ptr, rust_vec_len, data_len), port,
35 => { 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) 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), 38 => 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), 39 => 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), 40 => wire__crate__api__crypto__verify_cert_impl(port, ptr, rust_vec_len, data_len),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -3743,8 +3977,8 @@ fn pde_ffi_dispatcher_sync_impl(
match func_id { match func_id {
2 => wire__crate__api__stream__Dart2RustStreamSink_close_impl(ptr, rust_vec_len, data_len), 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), 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), 34 => 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), 35 => wire__crate__api__http__create_client_impl(ptr, rust_vec_len, data_len),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -4422,6 +4656,31 @@ impl flutter_rust_bridge::IntoDart for crate::api::server::RsServerEvent {
reason.into_into_dart().into_dart(), reason.into_into_dart().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!(""); 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 // 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> { impl flutter_rust_bridge::IntoDart for FrbWrapper<crate::api::webrtc::WsServerMessage> {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
match self.0 { 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>> { impl SseEncode for Option<Vec<String>> {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { 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); <String>::sse_encode(session_id, serializer);
<crate::api::server::SessionEndReasonV2>::sse_encode(reason, 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!(""); 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 { impl SseEncode for crate::api::webrtc::WsServerMessage {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+4 -5
View File
@@ -1,6 +1,7 @@
#![cfg(feature = "http")] #![cfg(feature = "http")]
use bytes::Bytes; use bytes::Bytes;
use futures_util::StreamExt;
use localsend::http::client::{ClientError, LsHttpClientV2}; use localsend::http::client::{ClientError, LsHttpClientV2};
use localsend::http::dto::ProtocolType; use localsend::http::dto::ProtocolType;
use localsend::http::dto_v2::{PrepareUploadRequestDtoV2, ProtocolTypeV2, RegisterDtoV2}; 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::atomic::{AtomicU16, AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use futures_util::StreamExt;
use tokio::sync::{mpsc, oneshot, Mutex}; use tokio::sync::{mpsc, oneshot, Mutex};
use tokio_stream::wrappers::ReceiverStream; use tokio_stream::wrappers::ReceiverStream;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
@@ -223,12 +223,11 @@ async fn upload_bytes(
// The caller now owns building the request body; track cumulative bytes // The caller now owns building the request body; track cumulative bytes
// sent so the progress assertion below still holds. // sent so the progress assertion below still holds.
let progress = sent.clone(); let progress = sent.clone();
let body = localsend::reqwest::Body::wrap_stream(ReceiverStream::new(rx).map( let body =
move |chunk: Bytes| { localsend::reqwest::Body::wrap_stream(ReceiverStream::new(rx).map(move |chunk: Bytes| {
progress.fetch_add(chunk.len() as u64, Ordering::Relaxed); progress.fetch_add(chunk.len() as u64, Ordering::Relaxed);
Ok::<Bytes, std::io::Error>(chunk) Ok::<Bytes, std::io::Error>(chunk)
}, }));
));
let result = client let result = client
.upload( .upload(
ProtocolType::Http, ProtocolType::Http,