diff --git a/lib/matrix_api/matrix_api.dart b/lib/matrix_api/matrix_api.dart index ff9f793..6f87e88 100644 --- a/lib/matrix_api/matrix_api.dart +++ b/lib/matrix_api/matrix_api.dart @@ -68,6 +68,13 @@ enum Direction { b, f } enum Visibility { public, private } enum CreateRoomPreset { private_chat, public_chat, trusted_private_chat } +String describeEnum(Object enumEntry) { + final description = enumEntry.toString(); + final indexOfDot = description.indexOf('.'); + assert(indexOfDot != -1 && indexOfDot < description.length - 1); + return description.substring(indexOfDot + 1); +} + class MatrixApi { /// The homeserver this client is communicating with. Uri homeserver; @@ -120,10 +127,14 @@ class MatrixApi { /// ); /// ``` /// - Future> request(RequestType type, String action, - {dynamic data = '', - int timeout, - String contentType = 'application/json'}) async { + Future> request( + RequestType type, + String action, { + dynamic data = '', + int timeout, + String contentType = 'application/json', + Map query, + }) async { if (homeserver == null) { throw ('No homeserver specified.'); } @@ -133,7 +144,13 @@ class MatrixApi { (!(data is String)) ? json = jsonEncode(data) : json = data; if (data is List || action.startsWith('/media/r0/upload')) json = data; - final url = '${homeserver.toString()}/_matrix${action}'; + final queryPart = query?.entries + ?.where((x) => x.value != null) + ?.map((x) => [x.key, x.value].map(Uri.encodeQueryComponent).join('=')) + ?.join('&'); + final url = ['${homeserver.toString()}/_matrix${action}', queryPart] + .where((x) => x != null && x != '') + .join('?'); var headers = {}; if (type == RequestType.PUT || type == RequestType.POST) { @@ -145,13 +162,13 @@ class MatrixApi { if (debug) { print( - "[REQUEST ${type.toString().split('.').last}] $action, Data: ${jsonEncode(data)}"); + '[REQUEST ${describeEnum(type)}] $action, Data: ${jsonEncode(data)}'); } http.Response resp; var jsonResp = {}; try { - switch (type.toString().split('.').last) { + switch (describeEnum(type)) { case 'GET': resp = await httpClient.get(url, headers: headers).timeout( Duration(seconds: timeout), @@ -439,8 +456,7 @@ class MatrixApi { }); return IdServerUnbindResult.values.firstWhere( - (i) => - i.toString().split('.').last == response['id_server_unbind_result'], + (i) => describeEnum(i) == response['id_server_unbind_result'], ); } @@ -510,12 +526,11 @@ class MatrixApi { RequestType.POST, '/client/r0/account/3pid/delete', data: { 'address': address, - 'medium': medium.toString().split('.').last, + 'medium': describeEnum(medium), 'id_server': idServer, }); return IdServerUnbindResult.values.firstWhere( - (i) => - i.toString().split('.').last == response['id_server_unbind_result'], + (i) => describeEnum(i) == response['id_server_unbind_result'], ); } @@ -530,12 +545,11 @@ class MatrixApi { RequestType.POST, '/client/r0/account/3pid/unbind', data: { 'address': address, - 'medium': medium.toString().split('.').last, + 'medium': describeEnum(medium), 'id_server': idServer, }); return IdServerUnbindResult.values.firstWhere( - (i) => - i.toString().split('.').last == response['id_server_unbind_result'], + (i) => describeEnum(i) == response['id_server_unbind_result'], ); } @@ -643,37 +657,16 @@ class MatrixApi { PresenceType setPresence, int timeout, }) async { - var atLeastOneParameter = false; - var action = '/client/r0/sync'; - if (filter != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'filter=${Uri.encodeQueryComponent(filter)}'; - atLeastOneParameter = true; - } - if (since != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'since=${Uri.encodeQueryComponent(since)}'; - atLeastOneParameter = true; - } - if (fullState != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'full_state=${Uri.encodeQueryComponent(fullState.toString())}'; - atLeastOneParameter = true; - } - if (setPresence != null) { - action += atLeastOneParameter ? '&' : '?'; - action += - 'set_presence=${Uri.encodeQueryComponent(setPresence.toString().split('.').last)}'; - atLeastOneParameter = true; - } - if (timeout != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'timeout=${Uri.encodeQueryComponent(timeout.toString())}'; - atLeastOneParameter = true; - } final response = await request( RequestType.GET, - action, + '/client/r0/sync', + query: { + if (filter != null) 'filter': filter, + if (since != null) 'since': since, + if (fullState != null) 'full_state': fullState.toString(), + if (setPresence != null) 'set_presence': describeEnum(setPresence), + if (timeout != null) 'timeout': timeout.toString(), + }, ); return SyncUpdate.fromJson(response); } @@ -728,28 +721,15 @@ class MatrixApi { Membership membership, Membership notMembership, }) async { - var action = '/client/r0/rooms/${Uri.encodeComponent(roomId)}/members'; - var atLeastOneParameter = false; - if (at != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'at=${Uri.encodeQueryComponent(at)}'; - atLeastOneParameter = true; - } - if (membership != null) { - action += atLeastOneParameter ? '&' : '?'; - action += - 'membership=${Uri.encodeQueryComponent(membership.toString().split('.').last)}'; - atLeastOneParameter = true; - } - if (notMembership != null) { - action += atLeastOneParameter ? '&' : '?'; - action += - 'not_membership=${Uri.encodeQueryComponent(notMembership.toString().split('.').last)}'; - atLeastOneParameter = true; - } final response = await request( RequestType.GET, - action, + '/client/r0/rooms/${Uri.encodeComponent(roomId)}/members', + query: { + if (at != null) 'at': at, + if (membership != null) 'membership': describeEnum(membership), + if (notMembership != null) + 'not_membership': describeEnum(notMembership), + }, ); return (response['chunk'] as List) .map((i) => MatrixEvent.fromJson(i)) @@ -779,23 +759,15 @@ class MatrixApi { int limit, String filter, }) async { - var action = '/client/r0/rooms/${Uri.encodeComponent(roomId)}/messages'; - action += '?from=${Uri.encodeQueryComponent(from)}'; - action += - '&dir=${Uri.encodeQueryComponent(dir.toString().split('.').last)}'; - if (to != null) { - action += '&to=${Uri.encodeQueryComponent(to)}'; - } - if (limit != null) { - action += '&limit=${Uri.encodeQueryComponent(limit.toString())}'; - } - if (filter != null) { - action += '&filter=${Uri.encodeQueryComponent(filter)}'; - } - final response = await request( - RequestType.GET, - action, - ); + final response = await request(RequestType.GET, + '/client/r0/rooms/${Uri.encodeComponent(roomId)}/messages', + query: { + 'from': from, + 'dir': describeEnum(dir), + if (to != null) 'to': to, + if (limit != null) 'limit': limit.toString(), + if (filter != null) 'filter': filter, + }); return TimelineHistoryResponse.fromJson(response); } @@ -862,8 +834,7 @@ class MatrixApi { }) async { final response = await request(RequestType.POST, '/client/r0/createRoom', data: { - if (visibility != null) - 'visibility': visibility.toString().split('.').last, + if (visibility != null) 'visibility': describeEnum(visibility), if (roomAliasName != null) 'room_alias_name': roomAliasName, if (name != null) 'name': name, if (topic != null) 'topic': topic, @@ -872,7 +843,7 @@ class MatrixApi { if (roomVersion != null) 'room_version': roomVersion, if (creationContent != null) 'creation_content': creationContent, if (initialState != null) 'initial_state': initialState, - if (preset != null) 'preset': preset.toString().split('.').last, + if (preset != null) 'preset': describeEnum(preset), if (isDirect != null) 'is_direct': isDirect, if (powerLevelContentOverride != null) 'power_level_content_override': powerLevelContentOverride, @@ -981,15 +952,11 @@ class MatrixApi { Map thirdPidSignedSiganture, }) async { var action = '/client/r0/join/${Uri.encodeComponent(roomIdOrAlias)}'; - if (servers != null) { - for (var i = 0; i < servers.length; i++) { - if (i == 0) { - action += '?'; - } else { - action += '&'; - } - action += 'server_name=${Uri.encodeQueryComponent(servers[i])}'; - } + final queryPart = servers + ?.map((x) => 'server_name=${Uri.encodeQueryComponent(x)}') + ?.join('&'); + if (queryPart != null && queryPart != '') { + action += '?' + queryPart; } final response = await request( RequestType.POST, @@ -1073,8 +1040,8 @@ class MatrixApi { RequestType.GET, '/client/r0/directory/list/room/${Uri.encodeComponent(roomId)}', ); - return Visibility.values.firstWhere( - (v) => v.toString().split('.').last == response['visibility']); + return Visibility.values + .firstWhere((v) => describeEnum(v) == response['visibility']); } /// Sets the visibility of a given room in the server's public room directory. @@ -1084,7 +1051,7 @@ class MatrixApi { RequestType.PUT, '/client/r0/directory/list/room/${Uri.encodeComponent(roomId)}', data: { - 'visibility': visibility.toString().split('.').last, + 'visibility': describeEnum(visibility), }, ); return; @@ -1097,26 +1064,14 @@ class MatrixApi { String since, String server, }) async { - var action = '/client/r0/publicRooms'; - var atLeastOneParameter = false; - if (limit != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'limit=${Uri.encodeQueryComponent(limit.toString())}'; - atLeastOneParameter = true; - } - if (since != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'since=${Uri.encodeQueryComponent(since.toString())}'; - atLeastOneParameter = true; - } - if (server != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'server=${Uri.encodeQueryComponent(server.toString())}'; - atLeastOneParameter = true; - } final response = await request( RequestType.GET, - action, + '/client/r0/publicRooms', + query: { + if (limit != null) 'limit': limit.toString(), + if (since != null) 'since': since, + if (server != null) 'server': server, + }, ); return PublicRoomsResponse.fromJson(response); } @@ -1131,13 +1086,12 @@ class MatrixApi { bool includeAllNetworks, String thirdPartyInstanceId, }) async { - var action = '/client/r0/publicRooms'; - if (server != null) { - action += '?server=${Uri.encodeQueryComponent(server.toString())}'; - } final response = await request( RequestType.POST, - action, + '/client/r0/publicRooms', + query: { + if (server != null) 'server': server, + }, data: { if (limit != null) 'limit': limit, if (since != null) 'since': since, @@ -1304,7 +1258,7 @@ class MatrixApi { RequestType.PUT, '/client/r0/presence/${Uri.encodeComponent(userId)}/status', data: { - 'presence': presenceType.toString().split('.').last, + 'presence': describeEnum(presenceType), if (statusMsg != null) 'status_msg': statusMsg, }, ); @@ -1596,26 +1550,14 @@ class MatrixApi { int limit, String only, }) async { - var action = '/client/r0/notifications'; - var atLeastOneParameter = false; - if (from != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'from=${Uri.encodeQueryComponent(from.toString())}'; - atLeastOneParameter = true; - } - if (limit != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'limit=${Uri.encodeQueryComponent(limit.toString())}'; - atLeastOneParameter = true; - } - if (only != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'only=${Uri.encodeQueryComponent(only.toString())}'; - atLeastOneParameter = true; - } final response = await request( RequestType.GET, - action, + '/client/r0/notifications', + query: { + if (from != null) 'from': from, + if (limit != null) 'limit': limit.toString(), + if (only != null) 'only': only, + }, ); return NotificationsQueryResponse.fromJson(response); } @@ -1641,7 +1583,7 @@ class MatrixApi { ) async { final response = await request( RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}', + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', ); return PushRule.fromJson(response); } @@ -1655,7 +1597,7 @@ class MatrixApi { ) async { await request( RequestType.DELETE, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}', + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', ); return; } @@ -1673,26 +1615,18 @@ class MatrixApi { List conditions, String pattern, }) async { - var action = - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}'; - var atLeastOneParameter = false; - if (before != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'before=${Uri.encodeQueryComponent(before.toString())}'; - atLeastOneParameter = true; - } - if (after != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'after=${Uri.encodeQueryComponent(after.toString())}'; - atLeastOneParameter = true; - } - await request(RequestType.PUT, action, data: { - 'actions': actions.map((i) => i.toString().split('.').last).toList(), - if (conditions != null) - 'conditions': - conditions.map((i) => i.toString().split('.').last).toList(), - if (pattern != null) 'pattern': pattern, - }); + await request(RequestType.PUT, + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', + query: { + if (before != null) 'before': before, + if (after != null) 'after': after, + }, + data: { + 'actions': actions.map(describeEnum).toList(), + if (conditions != null) + 'conditions': conditions.map((c) => c.toJson()).toList(), + if (pattern != null) 'pattern': pattern, + }); return; } @@ -1705,7 +1639,7 @@ class MatrixApi { ) async { final response = await request( RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}/enabled', + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/enabled', ); return response['enabled']; } @@ -1720,7 +1654,7 @@ class MatrixApi { ) async { await request( RequestType.PUT, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}/enabled', + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/enabled', data: {'enabled': enabled}, ); return; @@ -1735,11 +1669,11 @@ class MatrixApi { ) async { final response = await request( RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}/actions', + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/actions', ); return (response['actions'] as List) - .map((i) => PushRuleAction.values - .firstWhere((a) => a.toString().split('.').last == i)) + .map((i) => + PushRuleAction.values.firstWhere((a) => describeEnum(a) == i)) .toList(); } @@ -1753,10 +1687,8 @@ class MatrixApi { ) async { await request( RequestType.PUT, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(kind.toString().split('.').last)}/${Uri.encodeComponent(ruleId)}/actions', - data: { - 'actions': actions.map((a) => a.toString().split('.').last).toList() - }, + '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/actions', + data: {'actions': actions.map((a) => describeEnum(a)).toList()}, ); return; } @@ -1781,24 +1713,12 @@ class MatrixApi { int timeout, String roomId, }) async { - var action = '/client/r0/events'; - var atLeastOneParameter = false; - if (from != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'from=${Uri.encodeQueryComponent(from)}'; - atLeastOneParameter = true; - } - if (timeout != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'timeout=${Uri.encodeQueryComponent(timeout.toString())}'; - atLeastOneParameter = true; - } - if (roomId != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'roomId=${Uri.encodeQueryComponent(roomId)}'; - atLeastOneParameter = true; - } - final response = await request(RequestType.GET, action); + final response = + await request(RequestType.GET, '/client/r0/events', query: { + if (from != null) 'from': from, + if (timeout != null) 'timeout': timeout.toString(), + if (roomId != null) 'roomId': roomId, + }); return EventsSyncUpdate.fromJson(response); } @@ -1917,20 +1837,12 @@ class MatrixApi { int limit, String filter, }) async { - var action = - '/client/r0/rooms/${Uri.encodeQueryComponent(roomId)}/context/${Uri.encodeQueryComponent(eventId)}'; - var atLeastOneParameter = false; - if (filter != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'filter=${Uri.encodeQueryComponent(filter)}'; - atLeastOneParameter = true; - } - if (limit != null) { - action += atLeastOneParameter ? '&' : '?'; - action += 'limit=${Uri.encodeQueryComponent(limit.toString())}'; - atLeastOneParameter = true; - } - final response = await request(RequestType.GET, action); + final response = await request(RequestType.GET, + '/client/r0/rooms/${Uri.encodeQueryComponent(roomId)}/context/${Uri.encodeQueryComponent(eventId)}', + query: { + if (filter != null) 'filter': filter, + if (limit != null) 'limit': limit.toString(), + }); return EventContext.fromJson(response); }