feat(*): add sender to files pack result

This commit is contained in:
ksenia312
2024-02-04 22:25:57 +01:00
parent a1ac4488ca
commit d6840a4313
25 changed files with 199 additions and 152 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
export 'nearby_device_base.dart';
export 'nearby_message_base.dart';
export 'nearby_message_content_base.dart';
export 'nearby_message_content_base.dart';
+1 -1
View File
@@ -1,3 +1,3 @@
export 'nearby_device_mapper.dart';
export 'nearby_received_interface.dart';
export 'nearby_outgoing_interface.dart';
export 'nearby_outgoing_interface.dart';
@@ -32,5 +32,3 @@ abstract interface class NearbyDeviceMapper {
///
NearbyDeviceBase? mapToDevice(dynamic value);
}
+2 -1
View File
@@ -3,5 +3,6 @@ export 'nearby_device_status.dart';
export 'nearby_message.dart';
export 'nearby_message_content.dart';
export 'communication_channel_state.dart';
export 'nearby_file.dart';
export 'nearby_file_info.dart';
export 'nearby_message_content_type.dart';
export 'nearby_files_pack.dart';
@@ -1,4 +1,3 @@
import 'dart:io';
import 'package:nearby_service/nearby_service.dart';
///
@@ -8,46 +7,7 @@ import 'package:nearby_service/nearby_service.dart';
/// From the communication channel, you usually get
/// the [NearbyMessageFilesRequest] request first.
/// After that, you can send positive [NearbyMessageFilesResponse] and
/// get the list of [NearbyFile].
///
final class NearbyFile {
///
/// Pass [info] assigned to file to be sent.
///
const NearbyFile({
required this.info,
required this.file,
});
///
/// Quick info about the file
///
final NearbyFileInfo info;
///
/// A file that you can save in your phone if needed
///
final File file;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is NearbyFile &&
runtimeType == other.runtimeType &&
info == other.info &&
file == other.file;
@override
int get hashCode => info.hashCode ^ file.hashCode;
@override
String toString() {
return 'NearbyFile{info: $info, file: $file}';
}
}
///
/// Quick info about the file
/// get the list of [NearbyFileInfo].
///
class NearbyFileInfo {
///
+54
View File
@@ -0,0 +1,54 @@
import 'package:nearby_service/nearby_service.dart';
///
/// Used to provide result [files] that was got from [sender].
///
/// Can be received from [NearbyServiceFilesListener] only.
///
class ReceivedNearbyFilesPack implements NearbyReceivedInterface {
const ReceivedNearbyFilesPack({
required this.sender,
required this.files,
});
factory ReceivedNearbyFilesPack.fromJson(Map<String, dynamic>? json) {
return ReceivedNearbyFilesPack(
sender: NearbyDeviceInfo.fromJson(json?['sender']),
files: [
...?(json?['files'] as List?)?.map(
(e) => NearbyFileInfo.fromJson(e as Map<String, dynamic>),
),
],
);
}
@override
final NearbyDeviceInfo sender;
final List<NearbyFileInfo> files;
Map<String, dynamic> toJson() {
return {
'sender': sender.toJson(),
'files': [
...files.map((e) => e.toJson()),
],
};
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ReceivedNearbyFilesPack &&
runtimeType == other.runtimeType &&
sender == other.sender &&
files == other.files;
@override
int get hashCode => sender.hashCode ^ files.hashCode;
@override
String toString() {
return 'NearbyFilesPack{sender: $sender, files: $files}';
}
}
@@ -42,7 +42,7 @@ class NearbyConnectionAndroidInfo {
final bool isGroupOwner;
///
/// Indicates if the current device is the group owner.
/// Indicates if a p2p group has been successfully formed.
/// Source [WifiP2pInfo documentation](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pInfo)
///
final bool groupFormed;
@@ -18,15 +18,15 @@ final class NearbyAndroidDevice extends NearbyDeviceBase {
///
NearbyAndroidDevice({
required String deviceName,
required super.status,
required this.deviceAddress,
required this.isGroupOwner,
required this.isServiceDiscoveryCapable,
required this.primaryDeviceType,
required this.wpsKeypadSupported,
required this.wpsPbcSupported,
required this.wpsDisplaySupported,
this.isGroupOwner = false,
this.isServiceDiscoveryCapable = false,
this.primaryDeviceType = kNearbyUnknown,
this.wpsKeypadSupported = false,
this.wpsPbcSupported = false,
this.wpsDisplaySupported = false,
this.secondaryDeviceType,
super.status = NearbyDeviceStatus.unavailable,
}) : super(
info: NearbyDeviceInfo(
displayName: deviceName,
@@ -65,9 +65,8 @@ class NearbyAndroidService extends NearbyService {
/// Note! Requires [NearbyAndroidDevice] to be passed.
///
@override
Future<bool> disconnect(NearbyDeviceBase device) {
_requireAndroidDevice(device);
return NearbyServiceAndroidPlatform.instance.disconnect(device.info.id);
Future<bool> disconnect([NearbyDeviceBase? device]) {
return NearbyServiceAndroidPlatform.instance.disconnect();
}
///
@@ -51,7 +51,7 @@ abstract class NearbyServiceAndroidPlatform extends PlatformInterface {
throw UnimplementedError('connect() has not been implemented.');
}
Future<bool> disconnect(String deviceAddress) {
Future<bool> disconnect() {
throw UnimplementedError('disconnect() has not been implemented.');
}
@@ -57,12 +57,8 @@ class MethodChannelAndroidNearbyService extends NearbyServiceAndroidPlatform {
}
@override
Future<bool> disconnect(String deviceAddress) async {
return (await methodChannel.invokeMethod<bool?>(
"disconnect",
{"deviceAddress": deviceAddress},
)) ??
false;
Future<bool> disconnect() async {
return (await methodChannel.invokeMethod<bool?>("disconnect")) ?? false;
}
@override
@@ -11,6 +11,7 @@ class FileSocketsManager {
final _serverWaitingRequests = <String, HttpRequest>{};
NearbyServiceFilesListener? _filesListener;
NearbyDeviceInfo? _sender;
void setListener(NearbyServiceFilesListener? listener) {
_filesListener = listener;
@@ -26,22 +27,30 @@ class FileSocketsManager {
Future<void> handleFileMessageContent(
NearbyMessageFilesContent content, {
required NearbyDeviceInfo? sender,
required NearbyAndroidCommunicationChannelData androidData,
required bool isReceived,
}) async {
if (sender != null) {
_sender = sender;
Logger.debug('Sender was set to $_sender');
}
final shouldStartSocket = content.byType(
onFilesResponse: (response) => response.response,
onFilesRequest: (_) => true,
) ??
false;
if (shouldStartSocket) {
final alreadyExists = _filesSockets[content.id] != null;
if (shouldStartSocket && !alreadyExists) {
final info = await _service.getConnectionInfo();
if (info != null && info.groupFormed) {
if (info.isGroupOwner) {
await _startFilesServer(content);
if (content is NearbyMessageFilesResponse && isReceived) {
await _tryTransferData(content);
if (isReceived && content is NearbyMessageFilesResponse) {
await _startDataTransfer(content);
}
} else {
await _connectToFilesSocket(
@@ -49,13 +58,11 @@ class FileSocketsManager {
connectionData: androidData,
ownerIpAddress: info.ownerIpAddress,
);
if (content is NearbyMessageFilesRequest && !isReceived) {
await _tryTransferData(content);
if (!isReceived && content is NearbyMessageFilesRequest) {
await _startDataTransfer(content);
}
}
}
} else {
_filesSockets.remove(content.id);
}
}
@@ -107,9 +114,7 @@ class FileSocketsManager {
}
}
Future<void> _startFilesServer(
NearbyMessageFilesContent content,
) async {
Future<void> _startFilesServer(NearbyMessageFilesContent content) async {
final request = _serverWaitingRequests[content.id];
if (request != null) {
@@ -130,8 +135,9 @@ class FileSocketsManager {
required Future<WebSocket?> Function() onCreateSocket,
}) async {
final socket = await onCreateSocket();
if (socket != null) {
if (socket != null && _sender != null) {
_filesSockets[content.id] = FilesSocket.startListening(
sender: _sender!,
content: content,
socket: socket,
listener: _filesListener,
@@ -143,7 +149,7 @@ class FileSocketsManager {
return false;
}
Future<void> _tryTransferData(NearbyMessageFilesContent content) async {
Future<void> _startDataTransfer(NearbyMessageFilesContent content) async {
final filesSocket = _filesSockets[content.id];
if (filesSocket != null) {
Logger.debug('Start transferring the files pack ${content.id}');
@@ -96,13 +96,7 @@ class NearbySocketService {
},
),
);
if (message.content is NearbyMessageFilesContent) {
_fileSocketsManager.handleFileMessageContent(
message.content as NearbyMessageFilesContent,
androidData: _androidData,
isReceived: false,
);
}
_handleMessage(message);
}
return true;
}
@@ -211,13 +205,7 @@ class NearbySocketService {
.listen(
(message) async {
try {
if (message.content is NearbyMessageFilesContent) {
_fileSocketsManager.handleFileMessageContent(
message.content as NearbyMessageFilesContent,
androidData: _androidData,
isReceived: true,
);
}
_handleMessage(message);
socketListener.onData(message);
} catch (e) {
Logger.error(e);
@@ -244,4 +232,15 @@ class NearbySocketService {
state.value = CommunicationChannelState.notConnected;
}
}
void _handleMessage(NearbyMessageBase message) {
if (message.content is NearbyMessageFilesContent) {
_fileSocketsManager.handleFileMessageContent(
message.content as NearbyMessageFilesContent,
isReceived: message is ReceivedNearbyMessage,
sender: message is ReceivedNearbyMessage ? message.sender : null,
androidData: _androidData,
);
}
}
}
@@ -140,7 +140,8 @@ class NearbyIOSService extends NearbyService {
/// Note! Requires [NearbyIOSDevice] to be passed.
///
@override
Future<bool> disconnect(NearbyDeviceBase device) async {
Future<bool> disconnect([NearbyDeviceBase? device]) async {
if (device == null) return false;
_requireIOSDevice(device);
final result = await NearbyServiceIOSPlatform.instance.disconnect(
device.info.id,
@@ -185,9 +186,9 @@ class NearbyIOSService extends NearbyService {
cancelOnError: eventListener.cancelOnError,
);
_resourcesSubscription = NearbyServiceIOSPlatform.instance.resourcesStream
.map(ResourcesStreamMapper.toFiles)
.map(ResourcesStreamMapper.toFilesPack)
.where((event) => event != null)
.cast<List<NearbyFile>>()
.cast<ReceivedNearbyFilesPack>()
.listen(
(e) => filesListener?.onData.call(e),
onDone: filesListener?.onDone,
@@ -46,7 +46,7 @@ class NearbyServiceMessagesListener
/// Stream Subscription Listener.
///
class NearbyServiceFilesListener
extends NearbyServiceSocketListener<List<NearbyFile>> {
extends NearbyServiceSocketListener<ReceivedNearbyFilesPack> {
///
/// It is required to pass the [onData] parameter to process the
/// data that came through the stream.
+2 -1
View File
@@ -31,7 +31,8 @@ class NearbyServiceException implements Exception {
);
}
factory NearbyServiceException.invalidMessage(NearbyMessageContentBase content) {
factory NearbyServiceException.invalidMessage(
NearbyMessageContentBase content) {
return NearbyServiceException(
'The message="$content" is not valid',
);
+13 -6
View File
@@ -8,6 +8,7 @@ import 'package:path_provider/path_provider.dart';
class FilesSocket {
FilesSocket.startListening({
required this.sender,
required this.content,
required this.listener,
required this.onDestroy,
@@ -31,9 +32,10 @@ class FilesSocket {
final NearbyMessageFilesContent content;
final void Function(String) onDestroy;
final NearbyServiceFilesListener? listener;
final NearbyDeviceInfo sender;
final WebSocket _socket;
final _files = <NearbyFile>[];
final _files = <NearbyFileInfo>[];
final _bytesTable = <String, List<int>>{'0': []};
final _futures = <Future>[];
@@ -65,7 +67,13 @@ class FilesSocket {
} else if (event == finishCommand) {
await Future.wait(_futures);
Logger.info('Files pack ${content.id} was created');
listener?.onData.call(_files);
listener?.onData.call(
ReceivedNearbyFilesPack(
sender: sender,
files: _files,
),
);
onDestroy(content.id);
}
}
@@ -76,13 +84,12 @@ class FilesSocket {
final fileInfo = content.files[index];
final directory = await getTemporaryDirectory();
final file = File('${directory.path}/${fileInfo.name}');
await file.writeAsBytes(bytes);
final updatedFileInfo = NearbyFileInfo(path: file.path);
final nearbyFile = NearbyFile(file: file, info: fileInfo);
_files.add(nearbyFile);
_files.add(updatedFileInfo);
Logger.info('File ${nearbyFile.info.name} was created');
Logger.info('File ${updatedFileInfo.name} was created');
} catch (e) {
Logger.error(e);
}
+7 -12
View File
@@ -1,5 +1,3 @@
import 'dart:io';
import 'package:nearby_service/nearby_service.dart';
import 'package:nearby_service/src/utils/json_decoder.dart';
@@ -20,6 +18,8 @@ abstract class MessagesStreamMapper {
static ReceivedNearbyMessage? toMessage(dynamic event) {
try {
final decoded = JSONDecoder.decodeMap(event);
if (decoded == null) return null;
return ReceivedNearbyMessage.fromJson(decoded);
} catch (e) {
throw NearbyServiceException(
@@ -30,17 +30,12 @@ abstract class MessagesStreamMapper {
}
abstract class ResourcesStreamMapper {
static List<NearbyFile>? toFiles(dynamic event) {
static ReceivedNearbyFilesPack? toFilesPack(dynamic event) {
try {
final decoded = JSONDecoder.decodeList(event);
final infoList = [
...?decoded?.map(
(e) => NearbyFileInfo.fromJson(e as Map<String, dynamic>),
)
];
return [
...infoList.map((e) => NearbyFile(info: e, file: File(e.path))),
];
final decoded = JSONDecoder.decodeMap(event);
if (decoded == null) return null;
return ReceivedNearbyFilesPack.fromJson(decoded);
} catch (e) {
throw NearbyServiceException(
'Can\'t convert $event to ReceivedNearbyMessage',