mirror of
https://mirror.ghproxy.com/https://github.com/StarCitizenToolBox/app.git
synced 2024-12-23 22:53:43 +08:00
213 lines
6.5 KiB
Dart
213 lines
6.5 KiB
Dart
import 'dart:convert';
|
||
import 'dart:io';
|
||
|
||
import 'package:flutter/rendering.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||
import 'package:shelf/shelf.dart';
|
||
import 'package:shelf/shelf_io.dart' as shelf_io;
|
||
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
|
||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||
import 'package:starcitizen_doctor/ui/home/localization/localization_ui_model.dart';
|
||
|
||
import 'input_method_dialog_ui_model.dart';
|
||
|
||
part 'server.g.dart';
|
||
|
||
part 'server.freezed.dart';
|
||
|
||
@freezed
|
||
class InputMethodServerState with _$InputMethodServerState {
|
||
const factory InputMethodServerState({
|
||
@Default(false) bool isServerStartup,
|
||
String? serverAddressText,
|
||
}) = _InputMethodServerState;
|
||
}
|
||
|
||
@riverpod
|
||
class InputMethodServer extends _$InputMethodServer {
|
||
@override
|
||
InputMethodServerState build() {
|
||
state = InputMethodServerState(isServerStartup: false);
|
||
ref.onDispose(() {
|
||
stopServer();
|
||
});
|
||
return state;
|
||
}
|
||
|
||
LocalizationUIState get _localizationUIState =>
|
||
ref.read(localizationUIModelProvider);
|
||
|
||
InputMethodDialogUIModel get _inputMethodDialogUIModel =>
|
||
ref.read(inputMethodDialogUIModelProvider.notifier);
|
||
|
||
HttpServer? _httpServer;
|
||
|
||
Future<void> stopServer() async {
|
||
if (_httpServer != null) {
|
||
await _httpServer!.close(force: true);
|
||
_httpServer = null;
|
||
state = state.copyWith(
|
||
isServerStartup: false,
|
||
);
|
||
dPrint("[InputMethodServer] stopServer");
|
||
}
|
||
}
|
||
|
||
Future<void> startServer() async {
|
||
dPrint("[InputMethodServer] startServer");
|
||
|
||
var handler =
|
||
const Pipeline().addMiddleware(logRequests()).addHandler(_onHandler);
|
||
|
||
var server = await shelf_io.serve(
|
||
handler, "0.0.0.0", ConstConf.inputMethodServerPort);
|
||
|
||
// Enable content compression
|
||
server.autoCompress = true;
|
||
|
||
dPrint('Serving at http://${server.address.host}:${server.port}');
|
||
|
||
server.autoCompress = true;
|
||
_httpServer = server;
|
||
final address = await _findAddress();
|
||
state = state.copyWith(
|
||
isServerStartup: true,
|
||
serverAddressText: address,
|
||
);
|
||
}
|
||
|
||
Future<String> _findAddress() async {
|
||
final list = <String>[];
|
||
final List<NetworkInterface> address = await NetworkInterface.list();
|
||
bool has192168 = false;
|
||
for (var value in address) {
|
||
for (var addr in value.addresses) {
|
||
if (addr.type == InternetAddressType.IPv4) {
|
||
list.add("http://${addr.address}:${ConstConf.inputMethodServerPort}");
|
||
if (addr.address.startsWith('192.168.')) {
|
||
has192168 = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (has192168) {
|
||
list.removeWhere((element) => !element.contains('192.168.'));
|
||
}
|
||
if (list.isEmpty) {
|
||
list.add("获取地址失败,请手动查看电脑IP");
|
||
}
|
||
return list.join(", ");
|
||
}
|
||
|
||
Future<Response> _onHandler(Request request) async {
|
||
final path = request.url.path;
|
||
dPrint("[InputMethodServer] path: $path");
|
||
Uint8List? contentByte;
|
||
String mimeType;
|
||
try {
|
||
if (path.startsWith('api')) {
|
||
return _onHandlerApi(request);
|
||
}
|
||
if (path == '/' || path == '') {
|
||
contentByte =
|
||
(await rootBundle.load('assets/web/input_method/index.html'))
|
||
.buffer
|
||
.asUint8List();
|
||
mimeType = 'text/html; charset=utf-8';
|
||
} else {
|
||
var dotOffset = path.lastIndexOf('.');
|
||
if (path.substring(dotOffset) == '.png' ||
|
||
path.substring(dotOffset) == '.ttf' ||
|
||
path.substring(dotOffset) == '.otf') {
|
||
contentByte = (await rootBundle.load('assets/web/input_method/$path'))
|
||
.buffer
|
||
.asUint8List();
|
||
} else {
|
||
contentByte = (await rootBundle.load('assets/web/input_method/$path'))
|
||
.buffer
|
||
.asUint8List();
|
||
}
|
||
|
||
mimeType = dotOffset == -1
|
||
? 'text/plain; charset=utf-8'
|
||
: {
|
||
'.html': 'text/html; charset=utf-8',
|
||
'.css': 'text/css; charset=utf-8',
|
||
'.js': 'text/javascript; charset=utf-8',
|
||
'.csv': 'text/csv; charset=utf-8',
|
||
'.txt': 'text/plain; charset=utf-8',
|
||
'.ico': 'image/x-icon',
|
||
'.jpg': 'image/jpg',
|
||
'.jpeg': 'image/jpeg',
|
||
'.png': 'image/png',
|
||
'.gif': 'image/gif',
|
||
'.svg': 'image/svg+xml',
|
||
'.json': 'application/json',
|
||
'.xml': 'application/xml',
|
||
'.ttf': 'font/ttf',
|
||
'.otf': 'font/otf'
|
||
}[path.substring(dotOffset)] ??
|
||
"application/octet-stream";
|
||
}
|
||
return Response.ok(
|
||
contentByte,
|
||
headers: {
|
||
'Content-Type': mimeType,
|
||
},
|
||
);
|
||
} catch (e) {
|
||
debugPrint(e.toString());
|
||
return Response.internalServerError();
|
||
}
|
||
}
|
||
|
||
Future<Response> _onHandlerApi(Request request) async {
|
||
final path = request.url.path;
|
||
if (path == "api") {
|
||
return Response.ok(json.encode({
|
||
"status": "ok",
|
||
"appVersion": ConstConf.appVersion,
|
||
"appVersionCode": ConstConf.appVersionCode,
|
||
"appVersionDate": ConstConf.appVersionDate,
|
||
"isMSE": ConstConf.isMSE,
|
||
"installedCommunityInputMethodSupportVersion":
|
||
_localizationUIState.installedCommunityInputMethodSupportVersion,
|
||
}));
|
||
} else if (path.startsWith("api/send") && request.method == "POST") {
|
||
final body = await request.readAsString();
|
||
final data = json.decode(body);
|
||
final text = data["text"] ?? "";
|
||
if (text.isEmpty) {
|
||
return Response.badRequest(
|
||
body: json.encode({
|
||
"result": "error",
|
||
"message": "文本不能为空!",
|
||
}));
|
||
}
|
||
final autoCopy = data["autoCopy"] ?? false;
|
||
final autoInput = data["autoInput"] ?? false;
|
||
try {
|
||
await _inputMethodDialogUIModel.onSendText(
|
||
text,
|
||
autoCopy: autoCopy,
|
||
autoInput: autoInput,
|
||
);
|
||
return Response.ok(json.encode({
|
||
"result": "ok",
|
||
"message": "发送成功!",
|
||
}));
|
||
} catch (e) {
|
||
return Response.internalServerError(
|
||
body: json.encode({
|
||
"result": "error",
|
||
"message": e.toString(),
|
||
}));
|
||
}
|
||
} else {
|
||
return Response.notFound("Not Found");
|
||
}
|
||
}
|
||
}
|