From f53debfd14bd23a04a8a12147c102ce0a09a2936 Mon Sep 17 00:00:00 2001 From: Linloir <3145078758@qq.com> Date: Tue, 11 Oct 2022 16:02:41 +0800 Subject: [PATCH] More codes - TCP response model --- .../common_models/json_encodable.dart | 12 + lib/repositories/common_models/message.dart | 90 +++++++ .../common_models/message_type.dart | 19 -- .../common_models/useridentity.dart | 44 ++++ lib/repositories/common_models/userinfo.dart | 41 +++ .../models/tcp_response.dart | 6 - .../models/tcp_request.dart | 134 +++------- .../tcp_repository/models/tcp_response.dart | 246 ++++++++++++++++++ .../tcp_repository.dart} | 0 9 files changed, 465 insertions(+), 127 deletions(-) create mode 100644 lib/repositories/common_models/json_encodable.dart create mode 100644 lib/repositories/common_models/message.dart delete mode 100644 lib/repositories/common_models/message_type.dart create mode 100644 lib/repositories/common_models/useridentity.dart create mode 100644 lib/repositories/common_models/userinfo.dart delete mode 100644 lib/repositories/online_service_repository/models/tcp_response.dart rename lib/repositories/{online_service_repository => tcp_repository}/models/tcp_request.dart (60%) create mode 100644 lib/repositories/tcp_repository/models/tcp_response.dart rename lib/repositories/{online_service_repository/online_service_repository.dart => tcp_repository/tcp_repository.dart} (100%) diff --git a/lib/repositories/common_models/json_encodable.dart b/lib/repositories/common_models/json_encodable.dart new file mode 100644 index 0000000..9f8530f --- /dev/null +++ b/lib/repositories/common_models/json_encodable.dart @@ -0,0 +1,12 @@ +/* + * @Author : Linloir + * @Date : 2022-10-11 15:18:49 + * @LastEditTime : 2022-10-11 15:22:13 + * @Description : + */ + +abstract class JSONEncodable { + const JSONEncodable(); + + Map get jsonObject; +} \ No newline at end of file diff --git a/lib/repositories/common_models/message.dart b/lib/repositories/common_models/message.dart new file mode 100644 index 0000000..723df26 --- /dev/null +++ b/lib/repositories/common_models/message.dart @@ -0,0 +1,90 @@ +/* + * @Author : Linloir + * @Date : 2022-10-11 10:30:05 + * @LastEditTime : 2022-10-11 15:36:23 + * @Description : + */ + +import 'dart:convert'; + +import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart'; +import 'package:tcp_client/repositories/common_models/json_encodable.dart'; +import 'package:tcp_client/repositories/file_repository/models/local_file.dart'; + +enum MessageType { + plaintext('plaintext'), + file('file'), + image('image'); + + factory MessageType.fromStringLiteral(String value) { + return MessageType.values.firstWhere((element) => element._value == value); + } + const MessageType(String value): _value = value; + final String _value; + String get literal => _value; +} + +class Message extends JSONEncodable { + final int _userid; + final int _targetid; + final MessageType _contenttype; + final String _content; + final int _timestamp; + late final String _contentmd5; + final LocalFile? _payload; + + Message({ + required int userid, + required int targetid, + required MessageType contenttype, + required String content, + LocalFile? payload, + required int token + }): + _userid = userid, + _targetid = targetid, + _contenttype = contenttype, + _content = base64.encode(utf8.encode(content)), + _timestamp = DateTime.now().millisecondsSinceEpoch, + _payload = payload { + _contentmd5 = md5.convert( + utf8.encode(content) + ..addAll(Uint8List(4)..buffer.asInt32List()[0] = userid) + ..addAll(Uint8List(4)..buffer.asInt32List()[0] = targetid) + ..addAll(Uint8List(4)..buffer.asInt32List()[0] = _timestamp) + ).toString(); + } + + Message.fromJSONObject({ + required Map jsonObject, + LocalFile? payload + }): + _userid = jsonObject['userid'] as int, + _targetid = jsonObject['targetid'] as int, + _contenttype = MessageType.fromStringLiteral(jsonObject['contenttype'] as String), + _content = jsonObject['content'] as String, + _timestamp = jsonObject['timestamp'] as int, + _contentmd5 = jsonObject['md5encoded'] as String, + _payload = payload; + + int get senderID => _userid; + int get recieverID => _targetid; + MessageType get type => _contenttype; + String get contentDecoded => utf8.decode(base64.decode(_content)); + String get contentEncoded => _content; + String get contentmd5 => _contentmd5; + int get timeStamp => _timestamp; + LocalFile? get payload => _payload; + + @override + Map get jsonObject => { + 'userid': _userid, + 'targetid': _targetid, + 'contenttype': _contenttype.literal, + 'content': _content, + 'timestamp': _timestamp, + 'md5Encoded': _contentmd5, + 'filemd5': payload?.filemd5 + }; +} diff --git a/lib/repositories/common_models/message_type.dart b/lib/repositories/common_models/message_type.dart deleted file mode 100644 index b022c9b..0000000 --- a/lib/repositories/common_models/message_type.dart +++ /dev/null @@ -1,19 +0,0 @@ -/* - * @Author : Linloir - * @Date : 2022-10-11 10:30:05 - * @LastEditTime : 2022-10-11 10:30:12 - * @Description : - */ - -enum MessageType { - plaintext('plaintext'), - file('file'), - image('image'); - - factory MessageType.fromStringLiteral(String value) { - return MessageType.values.firstWhere((element) => element._value == value); - } - const MessageType(String value): _value = value; - final String _value; - String get literal => _value; -} diff --git a/lib/repositories/common_models/useridentity.dart b/lib/repositories/common_models/useridentity.dart new file mode 100644 index 0000000..545fdd7 --- /dev/null +++ b/lib/repositories/common_models/useridentity.dart @@ -0,0 +1,44 @@ +/* + * @Author : Linloir + * @Date : 2022-10-11 15:06:42 + * @LastEditTime : 2022-10-11 15:39:38 + * @Description : + */ +import 'dart:convert'; + +import 'package:crypto/crypto.dart'; +import 'package:tcp_client/repositories/common_models/json_encodable.dart'; + +class UserIdentity extends JSONEncodable { + final String _username; + final String _oldPasswd; + final String? _newPasswd; + + UserIdentity({ + required String username, + required String password, + String? newPassword + }): + _username = base64.encode(utf8.encode(username)), + _oldPasswd = md5.convert(password.codeUnits).toString(), + _newPasswd = newPassword != null ? + md5.convert(newPassword.codeUnits).toString() : null; + + UserIdentity.fromJSONObject({ + required Map jsonObject + }): + _username = jsonObject['username'] as String, + _oldPasswd = jsonObject['passwd'] as String, + _newPasswd = jsonObject['newPasswd'] as String?; + + String get userName => utf8.decode(base64.decode(_username)); + String get password => _oldPasswd; + String? get newPassword => _newPasswd; + + @override + Map get jsonObject => { + 'username': _username, + 'passwd': _oldPasswd, + 'newPasswd': _newPasswd + }; +} \ No newline at end of file diff --git a/lib/repositories/common_models/userinfo.dart b/lib/repositories/common_models/userinfo.dart new file mode 100644 index 0000000..f02d775 --- /dev/null +++ b/lib/repositories/common_models/userinfo.dart @@ -0,0 +1,41 @@ +/* + * @Author : Linloir + * @Date : 2022-10-11 14:30:10 + * @LastEditTime : 2022-10-11 15:39:13 + * @Description : + */ + +import 'package:tcp_client/repositories/common_models/json_encodable.dart'; + +class UserInfo extends JSONEncodable { + final int _userid; + final String _username; + final String? _avatar; + + const UserInfo({ + required int userid, + required String username, + String? avatar + }): + _userid = userid, + _username = username, + _avatar = avatar; + + UserInfo.fromJSONObject({ + required Map jsonObject + }): + _userid = jsonObject['userid'] as int, + _username = jsonObject['username'] as String, + _avatar = jsonObject['avatar'] as String?; + + int get userID => _userid; + String get userName => _username; + String? get avatarEncoded => _avatar; + + @override + Map get jsonObject => { + 'userid': _userid, + 'username': _username, + 'avatar': _avatar + }; +} diff --git a/lib/repositories/online_service_repository/models/tcp_response.dart b/lib/repositories/online_service_repository/models/tcp_response.dart deleted file mode 100644 index 92779fe..0000000 --- a/lib/repositories/online_service_repository/models/tcp_response.dart +++ /dev/null @@ -1,6 +0,0 @@ -/* - * @Author : Linloir - * @Date : 2022-10-11 11:02:19 - * @LastEditTime : 2022-10-11 11:02:19 - * @Description : - */ diff --git a/lib/repositories/online_service_repository/models/tcp_request.dart b/lib/repositories/tcp_repository/models/tcp_request.dart similarity index 60% rename from lib/repositories/online_service_repository/models/tcp_request.dart rename to lib/repositories/tcp_repository/models/tcp_request.dart index ba1d1ca..567c258 100644 --- a/lib/repositories/online_service_repository/models/tcp_request.dart +++ b/lib/repositories/tcp_repository/models/tcp_request.dart @@ -1,16 +1,16 @@ /* * @Author : Linloir * @Date : 2022-10-11 09:44:03 - * @LastEditTime : 2022-10-11 11:37:13 + * @LastEditTime : 2022-10-11 16:01:54 * @Description : Abstract TCP request class */ -export 'package:tcp_client/repositories/online_service_repository/models/tcp_request.dart'; +export 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart'; import 'dart:convert'; -import 'package:crypto/crypto.dart'; -import 'package:flutter/foundation.dart'; -import 'package:tcp_client/repositories/common_models/message_type.dart'; +import 'package:tcp_client/repositories/common_models/message.dart'; +import 'package:tcp_client/repositories/common_models/useridentity.dart'; +import 'package:tcp_client/repositories/common_models/userinfo.dart'; import 'package:tcp_client/repositories/file_repository/models/local_file.dart'; enum TCPRequestType { @@ -68,43 +68,27 @@ class CheckStateRequest extends TCPRequest { } class RegisterRequest extends TCPRequest { - final String _username; - final String _password; + final UserIdentity _identity; RegisterRequest({ - required username, - required password, + required UserIdentity identity, required token - }): - _username = username, - _password = md5.convert(password.codeUnits).toString(), - super(type: TCPRequestType.register, token: token); + }): _identity = identity, super(type: TCPRequestType.register, token: token); @override - Map get body => { - 'username': _username, - 'passwd': _password - }; + Map get body => _identity.jsonObject; } class LoginRequest extends TCPRequest { - final String _username; - final String _password; - - LoginRequest({ - required String username, - required String password, - required int token - }): - _username = username, - _password = md5.convert(password.codeUnits).toString(), - super(type: TCPRequestType.login, token: token); + final UserIdentity _identity; + LoginRequest({ + required UserIdentity identity, + required token + }): _identity = identity, super(type: TCPRequestType.login, token: token); + @override - Map get body => { - 'username': _username, - 'passwd': _password - }; + Map get body => _identity.jsonObject; } class LogoutRequest extends TCPRequest { @@ -122,97 +106,43 @@ class GetProfileRequest extends TCPRequest { } class ModifyPasswordRequest extends TCPRequest { - final String _username; - final String _oldPassword; - final String _newPassword; - + final UserIdentity _identity; + ModifyPasswordRequest({ - required String username, - required String oldPassword, - required String newPassowrd, - required int token - }): - _username = username, - _oldPassword = md5.convert(oldPassword.codeUnits).toString(), - _newPassword = md5.convert(newPassowrd.codeUnits).toString(), - super(type: TCPRequestType.modifyPassword, token: token); + required UserIdentity identity, + required token + }): _identity = identity, super(type: TCPRequestType.modifyPassword, token: token); @override - Map get body => { - 'username': _username, - 'passwd': _oldPassword, - 'newPasswd': _newPassword - }; + Map get body => _identity.jsonObject; } class ModifyProfileRequest extends TCPRequest { - final int _userid; - final String _username; - final String _avatar; + final UserInfo _userinfo; const ModifyProfileRequest ({ - required int userid, //Note: This can be fetched from local_service_repository - required String username, - required String avatar, + required UserInfo userInfo, required int token - }): - _userid = userid, - _username = username, - _avatar = avatar, - super(type: TCPRequestType.modifyProfile, token: token); + }): _userinfo = userInfo, super(type: TCPRequestType.modifyProfile, token: token); @override - Map get body => { - 'userid': _userid, - 'username': _username, - 'avatar': _avatar - }; + Map get body => _userinfo.jsonObject; } class SendMessageRequest extends TCPRequest { - final int _userid; - final int _targetid; - final MessageType _contenttype; - final String _content; - final int _timestamp; - late final String _contentmd5; - final LocalFile? _payload; + final Message _message; SendMessageRequest({ - required int userid, - required int targetid, - required MessageType contenttype, - required String content, - LocalFile? payload, + required Message message, required int token }): - _userid = userid, - _targetid = targetid, - _contenttype = contenttype, - _content = base64.encode(utf8.encode(content)), - _timestamp = DateTime.now().millisecondsSinceEpoch, - _payload = payload, - super(type: TCPRequestType.sendMessage, token: token) { - _contentmd5 = md5.convert( - utf8.encode(content) - ..addAll(Uint8List(4)..buffer.asInt32List()[0] = userid) - ..addAll(Uint8List(4)..buffer.asInt32List()[0] = targetid) - ..addAll(Uint8List(4)..buffer.asInt32List()[0] = _timestamp) - ).toString(); - } + _message = message, + super(type: TCPRequestType.sendMessage, token: token); @override - Map get body => { - 'userid': _userid, - 'targetid': _targetid, - 'contenttype': _contenttype.literal, - 'content': _content, - 'timestamp': _timestamp, - 'md5Encoded': _contentmd5, - 'filemd5': _payload?.filemd5 - }; + Map get body => _message.jsonObject; - LocalFile? get payload => _payload; + Message get message => _message; } class FetchMessageRequest extends TCPRequest { diff --git a/lib/repositories/tcp_repository/models/tcp_response.dart b/lib/repositories/tcp_repository/models/tcp_response.dart new file mode 100644 index 0000000..bfe8c0a --- /dev/null +++ b/lib/repositories/tcp_repository/models/tcp_response.dart @@ -0,0 +1,246 @@ +/* + * @Author : Linloir + * @Date : 2022-10-11 11:02:19 + * @LastEditTime : 2022-10-11 16:00:53 + * @Description : + */ + +import 'package:tcp_client/repositories/common_models/message.dart'; +import 'package:tcp_client/repositories/common_models/userinfo.dart'; +import 'package:tcp_client/repositories/file_repository/models/local_file.dart'; + +enum TCPResponseType { + token ('TOKEN'), //Only exists when server is sending message + checkState ('STATE'), //Check login state for device token + register ('REGISTER'), //Register new user + login ('LOGIN'), //Login via username and password + logout ('LOGOUT'), //Logout for current device token + profile ('PROFILE'), //Fetch current logged in user profile + modifyPassword('MODIFYPASSWD'), //Modify user password + modifyProfile ('MODIFYPROFILE'), //Modify user profile + sendMessage ('SENDMSG'), //Send message + forwardMessage('FORWARDMSG'), //Forward message + fetchMessage ('FETCHMSG'), //Fetch message + findFile ('FINDFILE'), //Find file by md5 before transmitting the file + fetchFile ('FETCHFILE'), //Fetch file and file md5 by message md5 + searchUser ('SEARCHUSR'), //Search username and userid by username + addContact ('ADDCONTACT'), //Add one-way relation to a user + fetchContact ('FETCHCONTACT'), //Fetch all contacts, including requesting and pending + unknown ('UNKNOWN'); //Wrong command + + const TCPResponseType(String value): _value = value; + final String _value; + String get value => _value; + + //Construct the enum type by value + factory TCPResponseType.fromValue(String value) { + return TCPResponseType.values.firstWhere((element) => element._value == value, orElse: () => TCPResponseType.unknown); + } +} + +enum TCPResponseStatus { + ok ('OK'), + err ('ERR'), + unknown ('UNKNOWN'); + + const TCPResponseStatus(String value): _value = value; + final String _value; + String get value => _value; + + //Construct the enum type by value + factory TCPResponseStatus.fromValue(String value) { + return TCPResponseStatus.values.firstWhere((element) => element._value == value, orElse: () => TCPResponseStatus.unknown); + } +} + +abstract class TCPResponse { + late final TCPResponseType _type; + late final TCPResponseStatus _status; + late final String? _info; + + TCPResponse({ + required Map jsonObject + }) { + _type = TCPResponseType.fromValue(jsonObject['response'] as String); + _status = TCPResponseStatus.fromValue(jsonObject['status'] as String); + _info = jsonObject['info'] as String?; + } + + TCPResponseType get type => _type; + TCPResponseStatus get status => _status; + String? get info => _info; +} + +class SetTokenReponse extends TCPResponse { + final int _token; + + SetTokenReponse({ + required Map jsonObject + }): + _token = (jsonObject['body'] as Map)['tokenid'] as int, + super(jsonObject: jsonObject); + + int get token => _token; +} + +class CheckStateResponse extends TCPResponse { + late final UserInfo _userInfo; + + CheckStateResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class RegisterResponse extends TCPResponse { + late final UserInfo _userInfo; + + RegisterResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class LoginResponse extends TCPResponse { + late final UserInfo _userInfo; + + LoginResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class LogoutResponse extends TCPResponse { + LogoutResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject); +} + +class GetProfileResponse extends TCPResponse { + late final UserInfo _userInfo; + + GetProfileResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class ModifyPasswordResponse extends TCPResponse { + ModifyPasswordResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject); +} + +class ModifyProfileResponse extends TCPResponse { + late final UserInfo _userInfo; + + ModifyProfileResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class SendMessageResponse extends TCPResponse { + SendMessageResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject); +} + +class ForwardMessageResponse extends TCPResponse { + late final Message _message; + + ForwardMessageResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _message = Message.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + Message get message => _message; +} + +class FetchMessageResponse extends TCPResponse { + late final List _messages; + + FetchMessageResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _messages = ((jsonObject['body'] as Map)['messages'] as List) + .map((e) => Message.fromJSONObject(jsonObject: e)).toList(); + } + + List get messages => _messages; +} + +class FindFileResponse extends TCPResponse { + FindFileResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject); + + bool get foundIdentical => status == TCPResponseStatus.ok; +} + +class FetchFileResponse extends TCPResponse { + final LocalFile _payload; + + FetchFileResponse({ + required Map jsonObject, + required LocalFile payload + }): _payload = payload, super(jsonObject: jsonObject); + + LocalFile get payload => _payload; +} + +class SearchUserResponse extends TCPResponse { + late final UserInfo _userInfo; + + SearchUserResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + _userInfo = UserInfo.fromJSONObject(jsonObject: jsonObject['body'] as Map); + } + + UserInfo get userInfo => _userInfo; +} + +class AddContactResponse extends TCPResponse { + AddContactResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject); +} + +class FetchContactResponse extends TCPResponse { + late final List _added; + late final List _pending; + late final List _requesting; + + FetchContactResponse({ + required Map jsonObject + }): super(jsonObject: jsonObject) { + var body = jsonObject['body'] as Map; + var rawAddedContacts = body['contacts'] as List; + var rawPendingContacts = body['pending'] as List; + var rawRequestingContacts = body['requesting'] as List; + _added = rawAddedContacts.map((e) => UserInfo.fromJSONObject(jsonObject: e)).toList(); + _pending = rawPendingContacts.map((e) => UserInfo.fromJSONObject(jsonObject: e)).toList(); + _requesting = rawRequestingContacts.map((e) => UserInfo.fromJSONObject(jsonObject: e)).toList(); + } + + List get addedContacts => _added; + List get pendingContacts => _pending; + List get requestingContacts => _requesting; +} \ No newline at end of file diff --git a/lib/repositories/online_service_repository/online_service_repository.dart b/lib/repositories/tcp_repository/tcp_repository.dart similarity index 100% rename from lib/repositories/online_service_repository/online_service_repository.dart rename to lib/repositories/tcp_repository/tcp_repository.dart