import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import '../../model/endpoint_data.dart'; import '../api_params.dart'; import '../api_request.dart'; import '../api_response.dart'; import '../errors/network_exception.dart'; import '../errors/parse_exception.dart'; import 'queries/authenticate/authenticate.dart'; import 'webuntis_error.dart'; abstract class WebuntisApi extends ApiRequest { Uri endpoint = Uri.parse('https://${EndpointData().webuntis().full()}/WebUntis/jsonrpc.do?school=marianum-fulda'); String method; ApiParams? genericParam; http.Response? response; bool authenticatedResponse; WebuntisApi(this.method, this.genericParam, {this.authenticatedResponse = true}); Future query(WebuntisApi untis, {bool retry = false}) async { final body = '{"id":"ID","method":"$method","params":${untis._body()},"jsonrpc":"2.0"}'; var sessionId = '0'; if (authenticatedResponse) { sessionId = (await Authenticate.getSession()).sessionId; } final data = await post(body, {'Cookie': 'JSESSIONID=$sessionId'}); response = data; final Map jsonData; try { jsonData = jsonDecode(data.body) as Map; } on FormatException catch (e) { throw ParseException(technicalDetails: 'WebUntis JSON decode: ${e.message}'); } final error = jsonData['error'] as Map?; if (error != null) { final code = error['code'] as int; if (code == -8520) { if (retry) throw WebuntisError('Authentication was tried (probably session timeout), but was not successful!', -8520); await Authenticate.createSession(); return query(untis, retry: true); } else { throw WebuntisError(error['message'] as String, code); } } return data.body; } T finalize(T response) { response.rawResponse = this.response!; return response; } Future run(); String _body() => genericParam == null ? '{}' : jsonEncode(genericParam); Future post(String data, Map? headers) async { try { return await http.post(endpoint, body: data, headers: headers).timeout( const Duration(seconds: 10), onTimeout: () => throw NetworkException.timeout(technicalDetails: 'WebUntis $method timed out after 10s'), ); } on SocketException catch (e) { throw NetworkException(technicalDetails: 'WebUntis $method: ${e.message}'); } on http.ClientException catch (e) { throw NetworkException(technicalDetails: 'WebUntis $method: ${e.message}'); } } }