Line data Source code
1 : import 'dart:async'; 2 : import 'dart:convert'; 3 : 4 : import 'package:chatwoot_client_sdk/data/local/entity/chatwoot_contact.dart'; 5 : import 'package:chatwoot_client_sdk/data/local/entity/chatwoot_conversation.dart'; 6 : import 'package:chatwoot_client_sdk/data/local/entity/chatwoot_message.dart'; 7 : import 'package:chatwoot_client_sdk/data/remote/chatwoot_client_exception.dart'; 8 : import 'package:chatwoot_client_sdk/data/remote/requests/chatwoot_action.dart'; 9 : import 'package:chatwoot_client_sdk/data/remote/requests/chatwoot_action_data.dart'; 10 : import 'package:chatwoot_client_sdk/data/remote/service/chatwoot_client_api_interceptor.dart'; 11 : import 'package:chatwoot_client_sdk/data/remote/requests/chatwoot_new_message_request.dart'; 12 : import 'package:dio/dio.dart'; 13 : import 'package:web_socket_channel/web_socket_channel.dart'; 14 : 15 : /// Service for handling chatwoot api calls 16 : /// See [ChatwootClientServiceImpl] 17 : abstract class ChatwootClientService { 18 : final String _baseUrl; 19 : WebSocketChannel? connection; 20 : final Dio _dio; 21 : 22 1 : ChatwootClientService(this._baseUrl, this._dio); 23 : 24 : Future<ChatwootContact> updateContact(update); 25 : 26 : Future<ChatwootContact> getContact(); 27 : 28 : Future<List<ChatwootConversation>> getConversations(); 29 : 30 : Future<ChatwootMessage> createMessage(ChatwootNewMessageRequest request); 31 : 32 : Future<ChatwootMessage> updateMessage(String messageIdentifier, update); 33 : 34 : Future<List<ChatwootMessage>> getAllMessages(); 35 : 36 : void startWebSocketConnection(String contactPubsubToken, 37 : {WebSocketChannel Function(Uri)? onStartConnection}); 38 : 39 : void sendAction(String contactPubsubToken, ChatwootActionType action); 40 : } 41 : 42 : class ChatwootClientServiceImpl extends ChatwootClientService { 43 1 : ChatwootClientServiceImpl(String baseUrl, {required Dio dio}) 44 1 : : super(baseUrl, dio); 45 : 46 : ///Sends message to chatwoot inbox 47 : @override 48 1 : Future<ChatwootMessage> createMessage( 49 : ChatwootNewMessageRequest request) async { 50 : try { 51 3 : final createResponse = await _dio.post( 52 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages", 53 1 : data: request.toJson()); 54 2 : if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { 55 2 : return ChatwootMessage.fromJson(createResponse.data); 56 : } else { 57 1 : throw ChatwootClientException( 58 1 : createResponse.statusMessage ?? "unknown error", 59 : ChatwootClientExceptionType.SEND_MESSAGE_FAILED); 60 : } 61 1 : } on DioError catch (e) { 62 1 : throw ChatwootClientException( 63 1 : e.message, ChatwootClientExceptionType.SEND_MESSAGE_FAILED); 64 : } 65 : } 66 : 67 : ///Gets all messages of current chatwoot client instance's conversation 68 : @override 69 1 : Future<List<ChatwootMessage>> getAllMessages() async { 70 : try { 71 3 : final createResponse = await _dio.get( 72 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages"); 73 2 : if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { 74 1 : return (createResponse.data as List<dynamic>) 75 3 : .map(((json) => ChatwootMessage.fromJson(json))) 76 1 : .toList(); 77 : } else { 78 1 : throw ChatwootClientException( 79 1 : createResponse.statusMessage ?? "unknown error", 80 : ChatwootClientExceptionType.GET_MESSAGES_FAILED); 81 : } 82 1 : } on DioError catch (e) { 83 1 : throw ChatwootClientException( 84 1 : e.message, ChatwootClientExceptionType.GET_MESSAGES_FAILED); 85 : } 86 : } 87 : 88 : ///Gets contact of current chatwoot client instance 89 : @override 90 1 : Future<ChatwootContact> getContact() async { 91 : try { 92 3 : final createResponse = await _dio.get( 93 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}"); 94 2 : if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { 95 2 : return ChatwootContact.fromJson(createResponse.data); 96 : } else { 97 1 : throw ChatwootClientException( 98 1 : createResponse.statusMessage ?? "unknown error", 99 : ChatwootClientExceptionType.GET_CONTACT_FAILED); 100 : } 101 1 : } on DioError catch (e) { 102 1 : throw ChatwootClientException( 103 1 : e.message, ChatwootClientExceptionType.GET_CONTACT_FAILED); 104 : } 105 : } 106 : 107 : ///Gets all conversation of current chatwoot client instance 108 : @override 109 1 : Future<List<ChatwootConversation>> getConversations() async { 110 : try { 111 3 : final createResponse = await _dio.get( 112 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations"); 113 2 : if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { 114 1 : return (createResponse.data as List<dynamic>) 115 3 : .map(((json) => ChatwootConversation.fromJson(json))) 116 1 : .toList(); 117 : } else { 118 1 : throw ChatwootClientException( 119 1 : createResponse.statusMessage ?? "unknown error", 120 : ChatwootClientExceptionType.GET_CONVERSATION_FAILED); 121 : } 122 1 : } on DioError catch (e) { 123 1 : throw ChatwootClientException( 124 1 : e.message, ChatwootClientExceptionType.GET_CONVERSATION_FAILED); 125 : } 126 : } 127 : 128 : ///Update current client instance's contact 129 : @override 130 1 : Future<ChatwootContact> updateContact(update) async { 131 : try { 132 3 : final updateResponse = await _dio.patch( 133 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}", 134 : data: update); 135 2 : if ((updateResponse.statusCode ?? 0).isBetween(199, 300)) { 136 2 : return ChatwootContact.fromJson(updateResponse.data); 137 : } else { 138 1 : throw ChatwootClientException( 139 1 : updateResponse.statusMessage ?? "unknown error", 140 : ChatwootClientExceptionType.UPDATE_CONTACT_FAILED); 141 : } 142 1 : } on DioError catch (e) { 143 1 : throw ChatwootClientException( 144 1 : e.message, ChatwootClientExceptionType.UPDATE_CONTACT_FAILED); 145 : } 146 : } 147 : 148 : ///Update message with id [messageIdentifier] with contents of [update] 149 : @override 150 1 : Future<ChatwootMessage> updateMessage( 151 : String messageIdentifier, update) async { 152 : try { 153 3 : final updateResponse = await _dio.patch( 154 1 : "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages/$messageIdentifier", 155 : data: update); 156 2 : if ((updateResponse.statusCode ?? 0).isBetween(199, 300)) { 157 2 : return ChatwootMessage.fromJson(updateResponse.data); 158 : } else { 159 1 : throw ChatwootClientException( 160 1 : updateResponse.statusMessage ?? "unknown error", 161 : ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED); 162 : } 163 1 : } on DioError catch (e) { 164 1 : throw ChatwootClientException( 165 1 : e.message, ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED); 166 : } 167 : } 168 : 169 1 : @override 170 : void startWebSocketConnection(String contactPubsubToken, 171 : {WebSocketChannel Function(Uri)? onStartConnection}) { 172 4 : final socketUrl = Uri.parse(_baseUrl.replaceFirst("http", "ws") + "/cable"); 173 1 : this.connection = onStartConnection == null 174 0 : ? WebSocketChannel.connect(socketUrl) 175 1 : : onStartConnection(socketUrl); 176 5 : connection!.sink.add(jsonEncode({ 177 : "command": "subscribe", 178 1 : "identifier": jsonEncode( 179 1 : {"channel": "RoomChannel", "pubsub_token": contactPubsubToken}) 180 : })); 181 : } 182 : 183 1 : @override 184 : void sendAction(String contactPubsubToken, ChatwootActionType actionType) { 185 : final ChatwootAction action; 186 1 : final identifier = jsonEncode( 187 1 : {"channel": "RoomChannel", "pubsub_token": contactPubsubToken}); 188 : switch (actionType) { 189 1 : case ChatwootActionType.subscribe: 190 0 : action = ChatwootAction(identifier: identifier, command: "subscribe"); 191 : break; 192 : default: 193 1 : action = ChatwootAction( 194 : identifier: identifier, 195 1 : data: ChatwootActionData(action: actionType), 196 : command: "message"); 197 : break; 198 : } 199 5 : connection?.sink.add(jsonEncode(action.toJson())); 200 : } 201 : }