mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
347 lines
12 KiB
Dart
347 lines
12 KiB
Dart
// This file is automatically generated, so please do not edit it.
|
|
// @generated by `flutter_rust_bridge`@ 2.12.0.
|
|
|
|
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
|
|
|
|
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
|
|
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
|
|
import 'package:localsend_isolates/rust/api/model.dart';
|
|
import 'package:localsend_isolates/rust/frb_generated.dart';
|
|
|
|
part 'server.freezed.dart';
|
|
|
|
// These functions are ignored because they are not marked as `pub`: `handle_server_event`, `handle_web_event`, `recv_opt`, `resolve_file_content`, `resolve_upload_target`
|
|
|
|
/// Starts the HTTP server on the given port (IPv4 and IPv6).
|
|
/// The server runs until [RsHttpServer::stop] is called.
|
|
///
|
|
/// Passing [web_send] additionally enables the web send (download API) so that
|
|
/// web browsers can download the offered files.
|
|
///
|
|
/// Passing [show_token] enables the internal `show` endpoint that lets another
|
|
/// application instance request this one to show itself (emitted as
|
|
/// [RsServerEvent::Show]). The token guards the endpoint against other clients.
|
|
///
|
|
/// Events are received by listening to [RsHttpServer::listen].
|
|
Future<RsHttpServer> startServer({
|
|
required int port,
|
|
TlsConfig? tls,
|
|
required String alias,
|
|
required String version,
|
|
String? deviceModel,
|
|
DeviceType? deviceType,
|
|
required String fingerprint,
|
|
String? pin,
|
|
WebSendParams? webSend,
|
|
String? showToken,
|
|
}) => RustLib.instance.api.crateApiServerStartServer(
|
|
port: port,
|
|
tls: tls,
|
|
alias: alias,
|
|
version: version,
|
|
deviceModel: deviceModel,
|
|
deviceType: deviceType,
|
|
fingerprint: fingerprint,
|
|
pin: pin,
|
|
webSend: webSend,
|
|
showToken: showToken,
|
|
);
|
|
|
|
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>>
|
|
abstract class RsHttpServer implements RustOpaqueInterface {
|
|
/// Cancels the active upload session, e.g. because the user aborted the
|
|
/// transfer on the receiving side.
|
|
///
|
|
/// Uploads that are already in progress still run to completion, but new
|
|
/// upload requests fail and a new session can be created.
|
|
/// No [RsServerEvent::SessionEnd] is emitted: the application initiated
|
|
/// the cancellation itself.
|
|
Future<void> cancelSession({required String sessionId});
|
|
|
|
/// Fails the pending [RsServerEvent::WebFileDownload] event, e.g. because
|
|
/// the application failed to resolve a source for the file content.
|
|
///
|
|
/// The download request fails with an error response.
|
|
/// Does nothing if the download was already answered.
|
|
Future<void> failFileDownload({required String sessionId, required String fileId});
|
|
|
|
/// Fails the pending [RsServerEvent::FileUpload] event, e.g. because
|
|
/// the application failed to prepare a save target for the file.
|
|
///
|
|
/// The upload request fails with an error response and the file is marked
|
|
/// as failed. Does nothing if the upload was already answered.
|
|
Future<void> failFileUpload({required String sessionId, required String fileId});
|
|
|
|
/// Emits server events until the server is stopped.
|
|
/// Can only be listened to once.
|
|
///
|
|
/// The v2 protocol, the web send (download API), and the internal endpoint
|
|
/// events are all emitted on the same stream.
|
|
Stream<RsServerEvent> listen();
|
|
|
|
/// Answers the pending [RsServerEvent::WebFileDownload] event with the source
|
|
/// the file content should be read from (either a path or a file descriptor).
|
|
///
|
|
/// The server reads the content and streams it to the web client.
|
|
Future<void> respondFileDownload({required String sessionId, required String fileId, String? path, int? fileDescriptor});
|
|
|
|
/// Answers the pending [RsServerEvent::FileUpload] event with the target
|
|
/// the file should be saved to (either a path or a file descriptor)
|
|
/// and waits until the file has been received completely.
|
|
///
|
|
/// The progress (fraction of [file_size]) is emitted on [sink]
|
|
/// while the file is being received.
|
|
Stream<double> respondFileUpload({required String sessionId, required String fileId, String? path, int? fileDescriptor, required BigInt fileSize});
|
|
|
|
/// Answers the pending [RsServerEvent::WebPrepareDownload] event.
|
|
///
|
|
/// Passing `true` accepts the download request, `false` declines it.
|
|
Future<void> respondPrepareDownload({required String sessionId, required bool accept});
|
|
|
|
/// Answers the pending [RsServerEvent::PrepareUpload] event.
|
|
///
|
|
/// Passing the accepted file IDs (a subset of the offered files) accepts the request.
|
|
/// Passing `None` declines the request.
|
|
Future<void> respondPrepareUpload({List<String>? acceptedFileIds});
|
|
|
|
/// Stops the server.
|
|
/// Returns after the listeners are closed, so the port can be bound again.
|
|
Future<void> stop();
|
|
}
|
|
|
|
enum ProtocolTypeV2 {
|
|
http,
|
|
https,
|
|
}
|
|
|
|
class RegisterDtoV2 {
|
|
final String alias;
|
|
final String version;
|
|
final String? deviceModel;
|
|
final DeviceType? deviceType;
|
|
final String fingerprint;
|
|
final int port;
|
|
final ProtocolTypeV2 protocol;
|
|
final bool download;
|
|
|
|
const RegisterDtoV2({
|
|
required this.alias,
|
|
required this.version,
|
|
this.deviceModel,
|
|
this.deviceType,
|
|
required this.fingerprint,
|
|
required this.port,
|
|
required this.protocol,
|
|
required this.download,
|
|
});
|
|
|
|
@override
|
|
int get hashCode =>
|
|
alias.hashCode ^
|
|
version.hashCode ^
|
|
deviceModel.hashCode ^
|
|
deviceType.hashCode ^
|
|
fingerprint.hashCode ^
|
|
port.hashCode ^
|
|
protocol.hashCode ^
|
|
download.hashCode;
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) ||
|
|
other is RegisterDtoV2 &&
|
|
runtimeType == other.runtimeType &&
|
|
alias == other.alias &&
|
|
version == other.version &&
|
|
deviceModel == other.deviceModel &&
|
|
deviceType == other.deviceType &&
|
|
fingerprint == other.fingerprint &&
|
|
port == other.port &&
|
|
protocol == other.protocol &&
|
|
download == other.download;
|
|
}
|
|
|
|
@freezed
|
|
sealed class RsServerEvent with _$RsServerEvent {
|
|
const RsServerEvent._();
|
|
|
|
/// A device registered itself via `POST /api/localsend/v2/register`.
|
|
///
|
|
/// On TLS, this event is only emitted when `info.fingerprint` matches the
|
|
/// fingerprint of the client certificate verified during the mTLS
|
|
/// handshake, so the fingerprint cannot be spoofed.
|
|
const factory RsServerEvent.register({
|
|
required String ip,
|
|
required RegisterDtoV2 info,
|
|
}) = RsServerEvent_Register;
|
|
|
|
/// A sender requests to upload files via `POST /api/localsend/v2/prepare-upload`.
|
|
const factory RsServerEvent.prepareUpload({
|
|
/// The session ID the upload session will have when the request is accepted.
|
|
required String sessionId,
|
|
required String ip,
|
|
required RegisterDtoV2 info,
|
|
|
|
/// The SHA-256 fingerprint (uppercase hex) of the sender's client
|
|
/// certificate verified during the mTLS handshake. Unlike
|
|
/// `info.fingerprint`, this value cannot be spoofed.
|
|
/// `None` when the server runs without TLS.
|
|
String? certFingerprint,
|
|
required Map<String, FileDto> files,
|
|
}) = RsServerEvent_PrepareUpload;
|
|
|
|
/// An accepted file is being uploaded via `POST /api/localsend/v2/upload`.
|
|
const factory RsServerEvent.fileUpload({
|
|
required String sessionId,
|
|
required String fileId,
|
|
required FileDto file,
|
|
}) = RsServerEvent_FileUpload;
|
|
|
|
/// An upload session ended.
|
|
const factory RsServerEvent.sessionEnd({
|
|
required String sessionId,
|
|
required SessionEndReasonV2 reason,
|
|
}) = RsServerEvent_SessionEnd;
|
|
|
|
/// A prepare-upload request was aborted before a session was created,
|
|
/// e.g. the sender disconnected while the application was still deciding.
|
|
/// The [RsServerEvent::PrepareUpload] with the same session ID
|
|
/// no longer needs to be answered.
|
|
const factory RsServerEvent.prepareUploadAborted({
|
|
required String sessionId,
|
|
}) = RsServerEvent_PrepareUploadAborted;
|
|
|
|
/// `POST /api/localsend/v2/cancel` was received for a session this server
|
|
/// does not manage: the remote device cancels a transfer this application
|
|
/// is currently *sending* to it. The application must verify that [ip]
|
|
/// matches the target of the send session before cancelling it.
|
|
const factory RsServerEvent.cancelReceived({
|
|
required String ip,
|
|
required String sessionId,
|
|
}) = RsServerEvent_CancelReceived;
|
|
|
|
/// 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 {
|
|
finished,
|
|
cancelled,
|
|
}
|
|
|
|
class TlsConfig {
|
|
final String cert;
|
|
final String privateKey;
|
|
|
|
const TlsConfig({
|
|
required this.cert,
|
|
required this.privateKey,
|
|
});
|
|
|
|
@override
|
|
int get hashCode => cert.hashCode ^ privateKey.hashCode;
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) || other is TlsConfig && runtimeType == other.runtimeType && cert == other.cert && privateKey == other.privateKey;
|
|
}
|
|
|
|
class WebSendI18n {
|
|
final String waiting;
|
|
final String enterPin;
|
|
final String invalidPin;
|
|
final String tooManyAttempts;
|
|
final String rejected;
|
|
final String files;
|
|
final String fileName;
|
|
final String size;
|
|
|
|
const WebSendI18n({
|
|
required this.waiting,
|
|
required this.enterPin,
|
|
required this.invalidPin,
|
|
required this.tooManyAttempts,
|
|
required this.rejected,
|
|
required this.files,
|
|
required this.fileName,
|
|
required this.size,
|
|
});
|
|
|
|
@override
|
|
int get hashCode =>
|
|
waiting.hashCode ^
|
|
enterPin.hashCode ^
|
|
invalidPin.hashCode ^
|
|
tooManyAttempts.hashCode ^
|
|
rejected.hashCode ^
|
|
files.hashCode ^
|
|
fileName.hashCode ^
|
|
size.hashCode;
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) ||
|
|
other is WebSendI18n &&
|
|
runtimeType == other.runtimeType &&
|
|
waiting == other.waiting &&
|
|
enterPin == other.enterPin &&
|
|
invalidPin == other.invalidPin &&
|
|
tooManyAttempts == other.tooManyAttempts &&
|
|
rejected == other.rejected &&
|
|
files == other.files &&
|
|
fileName == other.fileName &&
|
|
size == other.size;
|
|
}
|
|
|
|
/// Configuration for web send: files offered for download by web browsers.
|
|
///
|
|
/// Web send can be enabled independently of the v2 protocol endpoints. When
|
|
/// omitted, the download API responds with 403 and only the v2 endpoints run.
|
|
class WebSendParams {
|
|
/// The metadata of the files offered for download, mapped by file ID.
|
|
/// The content is requested per download via [RsServerEvent::WebFileDownload].
|
|
final Map<String, FileDto> files;
|
|
|
|
/// Optional PIN that web clients must provide via the `pin` query parameter.
|
|
final String? pin;
|
|
|
|
/// Translations for the web page, served via `/i18n.json`.
|
|
final WebSendI18n i18N;
|
|
|
|
const WebSendParams({
|
|
required this.files,
|
|
this.pin,
|
|
required this.i18N,
|
|
});
|
|
|
|
@override
|
|
int get hashCode => files.hashCode ^ pin.hashCode ^ i18N.hashCode;
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
identical(this, other) ||
|
|
other is WebSendParams && runtimeType == other.runtimeType && files == other.files && pin == other.pin && i18N == other.i18N;
|
|
}
|