You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
3.5 KiB
Dart

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:isekai_wiki/api/base_api.dart';
import 'package:isekai_wiki/global.dart';
import 'package:json_annotation/json_annotation.dart';
part 'mw_api.g.dart';
@JsonSerializable()
class MWApiErrorException implements Exception {
String code;
String? info;
@JsonKey(name: "*")
String? detail;
MWApiErrorException({required this.code, this.info, this.detail});
factory MWApiErrorException.fromJson(Map<String, dynamic> json) =>
_$MWApiErrorExceptionFromJson(json);
Map<String, dynamic> toJson() => _$MWApiErrorExceptionToJson(this);
@override
String toString() {
return "MediaWiki Api Error: ${info ?? code}";
}
}
class MWApiEmptyBodyException implements Exception {
dynamic resData;
MWApiEmptyBodyException(this.resData);
@override
String toString() {
return "MediaWiki Api Response body is empty";
}
}
class MWResponse<T> {
List<dynamic>? warnList;
T data;
Map<String, String>? continueInfo;
MWResponse(this.data, {this.warnList, this.continueInfo});
MWResponse<N> replaceData<N>(N data) {
return MWResponse<N>(
data,
warnList: warnList,
continueInfo: continueInfo,
);
}
}
class MWApi {
static Uri apiBaseUri = Uri.parse(Global.wikiApiUrl);
static Future<MWResponse<Map<String, dynamic>>> get(String action,
{Map<String, dynamic>? query}) async {
Map<String, String> queryStr =
query?.map((key, value) => MapEntry(key, value.toString())) ?? {};
queryStr.addAll({
"action": action,
"format": "json",
"formatversion": "2",
"uselang": Global.wikiLang,
});
if (Global.webOrigin != null) {
queryStr["origin"] = Global.webOrigin!;
}
var resText = "";
try {
resText = await BaseApi.get(apiBaseUri, search: queryStr);
} on DioError catch (err) {
if (err.type == DioErrorType.response) {
if (err.response != null) {
var response = err.response!;
var contentType = response.headers[Headers.contentTypeHeader];
if (contentType != null &&
contentType.contains("application/json") &&
response.data is String) {
resText = response.data as String;
}
}
}
if (resText.isEmpty) {
// 没有捕获到服务器返回的错误,则抛给上一层
rethrow;
}
}
return parseMWResponse(action, resText);
}
static MWResponse<Map<String, dynamic>> parseMWResponse(
String action, String resJson) {
var resData = jsonDecode(resJson);
if (resData is! Map<String, dynamic>) {
throw MWApiEmptyBodyException(resData);
}
// 处理请求错误
if (resData.containsKey("error")) {
throw MWApiErrorException.fromJson(resData["error"]!);
}
// 请求结果
if (!resData.containsKey(action) ||
resData[action] is! Map<String, dynamic>) {
throw MWApiEmptyBodyException(resData);
}
MWResponse<Map<String, dynamic>> mwRes =
MWResponse(resData[action] as Map<String, dynamic>);
// continue参数
var batchcomplete = resData["batchcomplete"];
if (batchcomplete is bool && batchcomplete) {
var continueInfo = resData["continue"];
if (continueInfo is Map<String, dynamic>) {
mwRes.continueInfo = {};
continueInfo.forEach((key, value) {
var keyStr = key;
mwRes.continueInfo![keyStr] = value.toString();
});
}
}
return mwRes;
}
}