LCOV - code coverage report
Current view: top level - lib/matrix_api_lite - matrix_api.dart (source / functions) Coverage Total Hit
Test: merged.info Lines: 69.2 % 65 45
Test Date: 2025-01-14 13:39:53 Functions: - 0 0

            Line data    Source code
       1              : /* MIT License
       2              : *
       3              : * Copyright (C) 2019, 2020, 2021 Famedly GmbH
       4              : *
       5              : * Permission is hereby granted, free of charge, to any person obtaining a copy
       6              : * of this software and associated documentation files (the "Software"), to deal
       7              : * in the Software without restriction, including without limitation the rights
       8              : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9              : * copies of the Software, and to permit persons to whom the Software is
      10              : * furnished to do so, subject to the following conditions:
      11              : *
      12              : * The above copyright notice and this permission notice shall be included in all
      13              : * copies or substantial portions of the Software.
      14              : *
      15              : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16              : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17              : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18              : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19              : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20              : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      21              : * SOFTWARE.
      22              : */
      23              : 
      24              : import 'dart:async';
      25              : import 'dart:convert';
      26              : import 'dart:typed_data';
      27              : 
      28              : import 'package:http/http.dart' as http;
      29              : 
      30              : import 'package:matrix/matrix_api_lite.dart';
      31              : import 'package:matrix/matrix_api_lite/generated/api.dart';
      32              : 
      33              : // ignore: constant_identifier_names
      34              : enum RequestType { GET, POST, PUT, DELETE }
      35              : 
      36              : class MatrixApi extends Api {
      37              :   /// The homeserver this client is communicating with.
      38           70 :   Uri? get homeserver => baseUri;
      39              : 
      40           70 :   set homeserver(Uri? uri) => baseUri = uri;
      41              : 
      42              :   /// This is the access token for the matrix client. When it is undefined, then
      43              :   /// the user needs to sign in first.
      44           66 :   String? get accessToken => bearerToken;
      45              : 
      46           66 :   set accessToken(String? token) => bearerToken = token;
      47              : 
      48            5 :   @override
      49              :   Never unexpectedResponse(http.BaseResponse response, Uint8List body) {
      50           20 :     if (response.statusCode >= 400 && response.statusCode < 500) {
      51           10 :       final resp = json.decode(utf8.decode(body));
      52            5 :       if (resp is Map<String, Object?>) {
      53            5 :         throw MatrixException.fromJson(resp);
      54              :       }
      55              :     }
      56            1 :     super.unexpectedResponse(response, body);
      57              :   }
      58              : 
      59            2 :   @override
      60              :   Never bodySizeExceeded(int expected, int actual) {
      61            2 :     throw EventTooLarge(expected, actual);
      62              :   }
      63              : 
      64           39 :   MatrixApi({
      65              :     Uri? homeserver,
      66              :     String? accessToken,
      67              :     super.httpClient,
      68           39 :   }) : super(baseUri: homeserver, bearerToken: accessToken);
      69              : 
      70              :   /// Used for all Matrix json requests using the [c2s API](https://matrix.org/docs/spec/client_server/r0.6.0.html).
      71              :   ///
      72              :   /// Throws: FormatException, MatrixException
      73              :   ///
      74              :   /// You must first set [this.homeserver] and for some endpoints also
      75              :   /// [this.accessToken] before you can use this! For example to send a
      76              :   /// message to a Matrix room with the id '!fjd823j:example.com' you call:
      77              :   /// ```
      78              :   /// final resp = await request(
      79              :   ///   RequestType.PUT,
      80              :   ///   '/r0/rooms/!fjd823j:example.com/send/m.room.message/$txnId',
      81              :   ///   data: {
      82              :   ///     'msgtype': 'm.text',
      83              :   ///     'body': 'hello'
      84              :   ///   }
      85              :   ///  );
      86              :   /// ```
      87              :   ///
      88            4 :   Future<Map<String, Object?>> request(
      89              :     RequestType type,
      90              :     String action, {
      91              :     dynamic data = '',
      92              :     String contentType = 'application/json',
      93              :     Map<String, Object?>? query,
      94              :   }) async {
      95            4 :     if (homeserver == null) {
      96              :       throw ('No homeserver specified.');
      97              :     }
      98              :     dynamic json;
      99            6 :     (data is! String) ? json = jsonEncode(data) : json = data;
     100            8 :     if (data is List<int> || action.startsWith('/media/v3/upload')) json = data;
     101              : 
     102            4 :     final url = homeserver!
     103           12 :         .resolveUri(Uri(path: '_matrix$action', queryParameters: query));
     104              : 
     105            4 :     final headers = <String, String>{};
     106            8 :     if (type == RequestType.PUT || type == RequestType.POST) {
     107            2 :       headers['Content-Type'] = contentType;
     108              :     }
     109            4 :     if (accessToken != null) {
     110           12 :       headers['Authorization'] = 'Bearer $accessToken';
     111              :     }
     112              : 
     113              :     late http.Response resp;
     114            4 :     Map<String, Object?>? jsonResp = <String, Object?>{};
     115              : 
     116              :     switch (type) {
     117            4 :       case RequestType.GET:
     118            8 :         resp = await httpClient.get(url, headers: headers);
     119              :         break;
     120            2 :       case RequestType.POST:
     121            4 :         resp = await httpClient.post(url, body: json, headers: headers);
     122              :         break;
     123            2 :       case RequestType.PUT:
     124            4 :         resp = await httpClient.put(url, body: json, headers: headers);
     125              :         break;
     126            0 :       case RequestType.DELETE:
     127            0 :         resp = await httpClient.delete(url, headers: headers);
     128              :         break;
     129              :     }
     130            4 :     var respBody = resp.body;
     131              :     try {
     132            8 :       respBody = utf8.decode(resp.bodyBytes);
     133              :     } catch (_) {
     134              :       // No-OP
     135              :     }
     136            8 :     if (resp.statusCode >= 500 && resp.statusCode < 600) {
     137            0 :       throw Exception(respBody);
     138              :     }
     139            8 :     var jsonString = String.fromCharCodes(respBody.runes);
     140            4 :     if (jsonString.startsWith('[') && jsonString.endsWith(']')) {
     141            0 :       jsonString = '{"chunk":$jsonString}';
     142              :     }
     143            4 :     jsonResp = jsonDecode(jsonString)
     144              :         as Map<String, Object?>?; // May throw FormatException
     145              : 
     146            8 :     if (resp.statusCode >= 400 && resp.statusCode < 500) {
     147            0 :       throw MatrixException(resp);
     148              :     }
     149              : 
     150              :     return jsonResp!;
     151              :   }
     152              : 
     153              :   /// This endpoint allows the creation, modification and deletion of pushers
     154              :   /// for this user ID. The behaviour of this endpoint varies depending on the
     155              :   /// values in the JSON body.
     156              :   ///
     157              :   /// See [deletePusher] to issue requests with `kind: null`.
     158              :   ///
     159              :   /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-pushers-set
     160            0 :   Future<void> postPusher(Pusher pusher, {bool? append}) async {
     161            0 :     final data = pusher.toJson();
     162              :     if (append != null) {
     163            0 :       data['append'] = append;
     164              :     }
     165            0 :     await request(
     166              :       RequestType.POST,
     167              :       '/client/v3/pushers/set',
     168              :       data: data,
     169              :     );
     170              :     return;
     171              :   }
     172              : 
     173              :   /// Variant of postPusher operation that deletes pushers by setting `kind: null`.
     174              :   ///
     175              :   /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-pushers-set
     176            0 :   Future<void> deletePusher(PusherId pusher) async {
     177            0 :     final data = PusherData.fromJson(pusher.toJson()).toJson();
     178            0 :     data['kind'] = null;
     179            0 :     await request(
     180              :       RequestType.POST,
     181              :       '/client/v3/pushers/set',
     182              :       data: data,
     183              :     );
     184              :     return;
     185              :   }
     186              : 
     187              :   /// This API provides credentials for the client to use when initiating
     188              :   /// calls.
     189            2 :   @override
     190              :   Future<TurnServerCredentials> getTurnServer() async {
     191            2 :     final json = await request(RequestType.GET, '/client/v3/voip/turnServer');
     192              : 
     193              :     // fix invalid responses from synapse
     194              :     // https://github.com/matrix-org/synapse/pull/10922
     195            2 :     final ttl = json['ttl'];
     196            2 :     if (ttl is double) {
     197            0 :       json['ttl'] = ttl.toInt();
     198              :     }
     199              : 
     200            2 :     return TurnServerCredentials.fromJson(json);
     201              :   }
     202              : 
     203            0 :   @Deprecated('Use [deleteRoomKeyBySessionId] instead')
     204              :   Future<RoomKeysUpdateResponse> deleteRoomKeysBySessionId(
     205              :     String roomId,
     206              :     String sessionId,
     207              :     String version,
     208              :   ) async {
     209            0 :     return deleteRoomKeyBySessionId(roomId, sessionId, version);
     210              :   }
     211              : 
     212            0 :   @Deprecated('Use [deleteRoomKeyBySessionId] instead')
     213              :   Future<RoomKeysUpdateResponse> putRoomKeysBySessionId(
     214              :     String roomId,
     215              :     String sessionId,
     216              :     String version,
     217              :     KeyBackupData data,
     218              :   ) async {
     219            0 :     return putRoomKeyBySessionId(roomId, sessionId, version, data);
     220              :   }
     221              : 
     222            0 :   @Deprecated('Use [getRoomKeyBySessionId] instead')
     223              :   Future<KeyBackupData> getRoomKeysBySessionId(
     224              :     String roomId,
     225              :     String sessionId,
     226              :     String version,
     227              :   ) async {
     228            0 :     return getRoomKeyBySessionId(roomId, sessionId, version);
     229              :   }
     230              : }
     231              : 
     232              : class EventTooLarge implements Exception {
     233              :   int maxSize, actualSize;
     234            2 :   EventTooLarge(this.maxSize, this.actualSize);
     235              : }
        

Generated by: LCOV version 2.0-1