Skip to content

Commit

Permalink
feat: better debugging tools (#183)
Browse files Browse the repository at this point in the history
* Update debug page and related components

* Add flutter_json_view dependency and update code to handle methods in SettingsController

* Fix JSON formatting and update dependencies

* Add ExtensionNetworkLog class and update ExtensionUtils

* Refactor child widget in debug_page.dart

* Refactor network request handling

* Fix scroll to bottom issue in debug page
  • Loading branch information
MiaoMint authored Jan 17, 2024
1 parent 89785c4 commit 0c07809
Show file tree
Hide file tree
Showing 9 changed files with 911 additions and 116 deletions.
77 changes: 75 additions & 2 deletions lib/controllers/settings_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import 'dart:convert';

import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:dio/dio.dart';
import 'package:flutter_js/flutter_js.dart';
import 'package:get/get.dart';
import 'package:miru_app/utils/extension.dart';

class SettingsController extends GetxController {
final contributors = [].obs;
Expand All @@ -25,12 +27,12 @@ class SettingsController extends GetxController {
void toggleExtensionLogWindow(bool open) async {
if (open && extensionLogWindowId.value == -1) {
final window = await DesktopMultiWindow.createWindow(jsonEncode({
"name": 'log',
"name": 'debug',
}));
extensionLogWindowId.value = window.windowId;
window
..center()
..setTitle("miru extension log")
..setTitle("miru extension debug")
..show();

// 用于检测窗口是否关闭
Expand All @@ -45,12 +47,83 @@ class SettingsController extends GetxController {
timer.cancel();
}
});
// 轮询带执行的方法并执行方法
Timer.periodic(const Duration(milliseconds: 500), (timer) async {
if (extensionLogWindowId.value == -1) {
timer.cancel();
return;
}
await _handleMethods();
});

return;
}
WindowController.fromWindowId(extensionLogWindowId.value).close();
extensionLogWindowId.value = -1;
}

// 返回执行结果
_invokeMethodResult(String methodKey, dynamic result) async {
await DesktopMultiWindow.invokeMethod(
extensionLogWindowId.value,
"result",
{
"key": methodKey,
"result": result,
},
);
}

// 获取方法列表
Future<List<Map<String, dynamic>>> _getMethods() async {
final methods = await DesktopMultiWindow.invokeMethod(
extensionLogWindowId.value,
"getMethods",
);

return List<dynamic>.from(methods)
.map((e) => Map<String, dynamic>.from(e))
.toList();
}

// 处理待执行的方法
Future<void> _handleMethods() async {
final methods = await _getMethods();
for (final call in methods) {
if (call["method"] == "getInstalledExtensions") {
_invokeMethodResult(
call["key"],
ExtensionUtils.runtimes.values
.toList()
.map((e) => e.extension.toJson())
.toList(),
);
}

if (call["method"] == "debugExecute") {
final arguments = call["arguments"];
final extension = ExtensionUtils.runtimes[arguments["package"]];
final method = arguments["method"];
final runtime = extension!.runtime;
try {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync('stringify(()=>{return $method})'),
);
final result = jsResult.stringResult;
_invokeMethodResult(
call["key"],
result,
);
} catch (e) {
_invokeMethodResult(
call["key"],
e.toString(),
);
}
}
}
}

_getContributors() async {
final res = await Dio()
.get("https://api.github.com/repos/miru-project/miru-app/contributors");
Expand Down
111 changes: 78 additions & 33 deletions lib/data/services/extension_service.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart';
Expand Down Expand Up @@ -53,26 +54,70 @@ class ExtensionService {
});
// 请求
runtime.onMessage('request', (dynamic args) async {
ExtensionUtils.addLog(
extension,
ExtensionLogLevel.info,
"Request: ${args[0]} , ${args[1]}",
);
_cuurentRequestUrl = args[0];
final headers = args[1]['headers'] ?? {};
if (headers['User-Agent'] == null) {
headers['User-Agent'] = MiruStorage.getUASetting();
}
return (await _dio.request<String>(
args[0],
data: args[1]['data'],
queryParameters: args[1]['queryParameters'] ?? {},
options: Options(
headers: headers,
method: args[1]['method'] ?? 'get',
),
))
.data;

final url = args[0];
final method = args[1]['method'] ?? 'get';
final requestBody = args[1]['data'];

final log = ExtensionNetworkLog(
extension: extension,
url: args[0],
method: method,
requestHeaders: headers,
);
final key = UniqueKey().toString();
ExtensionUtils.addNetworkLog(
key,
log,
);

try {
final res = await _dio.request<String>(
url,
data: requestBody,
queryParameters: args[1]['queryParameters'] ?? {},
options: Options(
headers: headers,
method: method,
),
);
log.requestHeaders = res.requestOptions.headers;
log.responseBody = res.data;
log.responseHeaders = res.headers.map.map(
(key, value) => MapEntry(
key,
value.join(';'),
),
);
log.statusCode = res.statusCode;

ExtensionUtils.addNetworkLog(
key,
log,
);
return res.data;
} on DioException catch (e) {
log.url = e.requestOptions.uri.toString();
log.requestHeaders = e.requestOptions.headers;
log.responseBody = e.response?.data;
log.responseHeaders = e.response?.headers.map.map(
(key, value) => MapEntry(
key,
value.join(';'),
),
);
log.statusCode = e.response?.statusCode;
ExtensionUtils.addNetworkLog(
key,
log,
);
rethrow;
}
});

// 设置
Expand Down Expand Up @@ -355,7 +400,7 @@ class ExtensionService {
async function stringify(callback) {
const data = await callback();
return typeof data === "object" ? JSON.stringify(data) : data;
return typeof data === "object" ? JSON.stringify(data,0,2) : data;
}
''');
Expand All @@ -365,9 +410,9 @@ class ExtensionService {

JsEvalResult jsResult = await runtime.evaluateAsync('''
$ext
var extenstion = new Ext();
extenstion.load().then(()=>{
sendMessage("cleanSettings", JSON.stringify([extenstion.settingKeys]));
var extension = new Ext();
extension.load().then(()=>{
sendMessage("cleanSettings", JSON.stringify([extension.settingKeys]));
});
''');
await runtime.handlePromise(jsResult);
Expand Down Expand Up @@ -397,7 +442,7 @@ class ExtensionService {
return cookies.map((e) => e.toString()).join(';');
}

Future<T> _runExtension<T>(Future<T> Function() fun) async {
Future<T> runExtension<T>(Future<T> Function() fun) async {
try {
return await fun();
} catch (e) {
Expand All @@ -419,9 +464,9 @@ class ExtensionService {
}

Future<List<ExtensionListItem>> latest(int page) async {
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync('stringify(()=>extenstion.latest($page))'),
await runtime.evaluateAsync('stringify(()=>extension.latest($page))'),
);
List<ExtensionListItem> result =
jsonDecode(jsResult.stringResult).map<ExtensionListItem>((e) {
Expand All @@ -439,10 +484,10 @@ class ExtensionService {
int page, {
Map<String, List<String>>? filter,
}) async {
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync(
'stringify(()=>extenstion.search("$kw",$page,${filter == null ? null : jsonEncode(filter)}))'),
'stringify(()=>extension.search("$kw",$page,${filter == null ? null : jsonEncode(filter)}))'),
);
List<ExtensionListItem> result =
jsonDecode(jsResult.stringResult).map<ExtensionListItem>((e) {
Expand All @@ -460,12 +505,12 @@ class ExtensionService {
}) async {
late String eval;
if (filter == null) {
eval = 'stringify(()=>extenstion.createFilter())';
eval = 'stringify(()=>extension.createFilter())';
} else {
eval =
'stringify(()=>extenstion.createFilter(JSON.parse(\'${jsonEncode(filter)}\')))';
'stringify(()=>extension.createFilter(JSON.parse(\'${jsonEncode(filter)}\')))';
}
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync(eval),
);
Expand All @@ -480,9 +525,9 @@ class ExtensionService {
}

Future<ExtensionDetail> detail(String url) async {
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync('stringify(()=>extenstion.detail("$url"))'),
await runtime.evaluateAsync('stringify(()=>extension.detail("$url"))'),
);
final result =
ExtensionDetail.fromJson(jsonDecode(jsResult.stringResult));
Expand All @@ -492,9 +537,9 @@ class ExtensionService {
}

Future<Object?> watch(String url) async {
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime.evaluateAsync('stringify(()=>extenstion.watch("$url"))'),
await runtime.evaluateAsync('stringify(()=>extension.watch("$url"))'),
);
final data = jsonDecode(jsResult.stringResult);

Expand All @@ -514,10 +559,10 @@ class ExtensionService {
}

Future<String> checkUpdate(url) async {
return _runExtension(() async {
return runExtension(() async {
final jsResult = await runtime.handlePromise(
await runtime
.evaluateAsync('stringify(()=>extenstion.checkUpdate("$url"))'),
.evaluateAsync('stringify(()=>extension.checkUpdate("$url"))'),
);
return jsResult.stringResult;
});
Expand Down
4 changes: 2 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart';
import 'package:miru_app/controllers/application_controller.dart';
import 'package:miru_app/views/pages/log_page.dart';
import 'package:miru_app/views/pages/debug_page.dart';
import 'package:miru_app/views/pages/main_page.dart';
import 'package:miru_app/router/router.dart';
import 'package:miru_app/utils/extension.dart';
Expand All @@ -28,7 +28,7 @@ void main(List<String> args) async {
: jsonDecode(args[2]) as Map<String, dynamic>;

Map windows = {
"log": ExtensionLogWindow(
"debug": ExtensionDebugWindow(
windowController: WindowController.fromWindowId(windowId),
),
};
Expand Down
28 changes: 28 additions & 0 deletions lib/models/extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,31 @@ class ExtensionLog {

Map<String, dynamic> toJson() => _$ExtensionLogToJson(this);
}

@JsonSerializable()
class ExtensionNetworkLog {
final Extension extension;
String? responseBody;
String? requestBody;
Map<String, dynamic>? requestHeaders;
Map<String, dynamic>? responseHeaders;
String url;
String method;
int? statusCode;

ExtensionNetworkLog({
required this.extension,
required this.url,
required this.method,
this.statusCode,
this.responseBody,
this.requestBody,
this.requestHeaders,
this.responseHeaders,
});

factory ExtensionNetworkLog.fromJson(Map<String, dynamic> json) =>
_$ExtensionNetworkLogFromJson(json);

Map<String, dynamic> toJson() => _$ExtensionNetworkLogToJson(this);
}
25 changes: 25 additions & 0 deletions lib/models/extension.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0c07809

Please sign in to comment.