Skip to content
This repository has been archived by the owner on Dec 28, 2024. It is now read-only.

Commit

Permalink
34 when spamming refresh local discovery crashed (#37)
Browse files Browse the repository at this point in the history
* increase timer to be sure data is received (if platform existed)

* Works even if the network is very slow

---------

Co-authored-by: Damien Albisson <[email protected]>
  • Loading branch information
Darcraytore1 and Damien Albisson authored May 27, 2024
1 parent d6d3046 commit 5f8b81e
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 79 deletions.
136 changes: 115 additions & 21 deletions lib/after_setup_pages/discovery_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:auto_size_text/auto_size_text.dart';
Expand All @@ -10,8 +11,10 @@ import 'package:panduza_sandbox_flutter/utils_widgets/appBar.dart';
import 'manual_connection_page.dart';


// Page who will discover the differents platforms on
// the network
/*
This class will go looking for different platform on the network sending
broadcast with UTF-8 format and getting an answer for each platform
*/

class DiscoveryPage extends StatefulWidget {
const DiscoveryPage({super.key});
Expand All @@ -22,9 +25,84 @@ class DiscoveryPage extends StatefulWidget {

class _DiscoveryPageState extends State<DiscoveryPage> {

// List ip/port broker of the platforms already discovered
List<(String, int, String)> platformsIpsPorts = [];
bool isLoading = false;

Timer? timer;

// List socket who has been closed when changing page or refreshing
List<RawDatagramSocket> sockets = [];

// List of subscription to realize listen
List<StreamSubscription<RawSocketEvent>> subscriptions = [];

// Create socket for each network interface and listen message on them while
// page is not refresh

Future<void> platformDiscoveryStart() async {

// Could have some problem with some android phone ?
List<NetworkInterface> listInterface = await NetworkInterface.list();

for (NetworkInterface interface in listInterface) {
for (InternetAddress address in interface.addresses) {
RawDatagramSocket socket = await RawDatagramSocket.bind(address.address, 63500);
socket.broadcastEnabled = true;
// Add to the list of socket to close when changing of page or refreshing
sockets.add(socket);
subscriptions.add(
socket.listen((event) {
Datagram? datagram = socket.receive();
if (datagram != null) {
String answer = utf8.decode(datagram.data);

Map<String, dynamic> answerMap = jsonDecode(answer);

Map<String, dynamic>? brokerInfo = answerMap["broker"];
Map<String, dynamic>? platformInfo = answerMap["platform"];

if (brokerInfo != null && platformInfo != null) {
String? brokerAddr = brokerInfo["addr"];
int? brokerPort = brokerInfo["port"];
String? platformName = platformInfo["name"];

// if platform name is not given in the answer payload do not add this platform
if (platformName != null && brokerAddr != null && brokerPort != null) {

// Get addr, port and platform name
if (!platformsIpsPorts.contains((datagram.address.address, brokerPort, platformName))) {
setState(() {
// add the new platform discovered to the list seen by the user, sort them by name
platformsIpsPorts.add((datagram.address.address, brokerPort, platformName));
platformsIpsPorts.sort(((a, b) => a.$3.compareTo(b.$3)));
});
}
}
}
}
}, onError: (error) {
print("error: $error");
}, onDone: () {
print("done!");
}, cancelOnError: true)
);
}
}
}

// Send request to discover platforms
void sendDiscoverRequest() {
for (RawDatagramSocket socket in sockets) {
try {
socket.send(utf8.encode(jsonEncode({"search" : true})), InternetAddress("255.255.255.255"), portLocalDiscovery);
} on SocketException catch(e) {
print("Local discovery on ${e.address}:${e.port} failed, error code = ${e.osError?.errorCode}, ${e.osError?.message}");
}
}
}


// List of button of local platform detected
Widget localDiscoveryConnections(List<(String, int, String)> platformsIpsPorts, bool isLoading) {

Expand Down Expand Up @@ -69,13 +147,19 @@ class _DiscoveryPageState extends State<DiscoveryPage> {
),
),
onTap: () {
// close socket, stop the timer before changing of page
String platformName = platformsIpsPorts[index].$3;
String ip = platformsIpsPorts[index].$1;
String port = platformsIpsPorts[index].$2.toString();
clearInstance();

Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => ManualConnectionPage(
name: platformsIpsPorts[index].$3,
ip: platformsIpsPorts[index].$1,
port: platformsIpsPorts[index].$2.toString()
name: platformName,
ip: ip,
port: port
),
),
);
Expand All @@ -87,17 +171,32 @@ class _DiscoveryPageState extends State<DiscoveryPage> {
);
}

// Stop listens on socket, close sockets, stop sendings message to platforms
// and clear lists
void clearInstance() {
for (StreamSubscription<RawSocketEvent> subscription in subscriptions) {
subscription.cancel();
}
for (RawDatagramSocket socket in sockets) {
socket.close();
}
sockets.clear();
timer?.cancel();
platformsIpsPorts.clear();
}

@override
void initState() {
super.initState();
platformDiscovery().then(
(value) {
platformsIpsPorts = value;
platformsIpsPorts.sort((a, b) => a.$3.compareTo(b.$3));
setState(() {});
}
);
platformDiscoveryStart();
timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
sendDiscoverRequest();
});
}

@override dispose() {
clearInstance();
super.dispose();
}

@override
Expand All @@ -116,15 +215,10 @@ class _DiscoveryPageState extends State<DiscoveryPage> {
backgroundColor: MaterialStateProperty.all<Color>(black)
),
onPressed: () {
// Resend a broadcast to detect every local plaform (get
// id and for each of them)
platformDiscovery().then(
(value) {
platformsIpsPorts = value;
platformsIpsPorts.sort((a, b) => a.$3.compareTo(b.$3));
setState(() {});
}
);
// Close sockets then create new ones if potential bugs
sockets.map((socket) => socket.close());
sockets.clear();
platformDiscoveryStart();
},
child: Text(
'REFRESH',
Expand Down
58 changes: 0 additions & 58 deletions lib/data/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -276,62 +276,4 @@ Future<bool> checkIfConnectionValid(BuildContext context, String name, String ho
}

return true;
}


/*
This class will go looking for different platform on the network sending
broadcast with UTF-8 format and getting an answer for each platform
*/

Future<List<(String, int, String)>> platformDiscovery() async {

List<(String, int, String)> ipPort = [];

// Could have some problem with some android phone ?
List<NetworkInterface> listInterface = await NetworkInterface.list();

for (NetworkInterface interface in listInterface) {
for (InternetAddress address in interface.addresses) {
RawDatagramSocket socket = await RawDatagramSocket.bind(address.address, 63500);
socket.broadcastEnabled = true;
socket.listen((e) {
Datagram? datagram = socket.receive();
if (datagram != null) {
String answer = utf8.decode(datagram.data);

Map<String, dynamic> answerMap = jsonDecode(answer);

Map<String, dynamic>? brokerInfo = answerMap["broker"];
Map<String, dynamic>? platformInfo = answerMap["platform"];

if (brokerInfo != null && platformInfo != null) {
String? brokerAddr = brokerInfo["addr"];
int? brokerPort = brokerInfo["port"];
String? platformName = platformInfo["name"];

// if platform name is not given in the answer payload do not add this platform
if (platformName != null && brokerAddr != null && brokerPort != null) {
// Get addr, port and platform name
// if (!ipPort.contains((datagram.address, datagram.port, platformName))) ipPort.add((datagram.address, datagram.port, platformName));
if (!ipPort.contains((datagram.address.address, brokerPort, platformName))) ipPort.add((datagram.address.address, brokerPort, platformName));
}
}


}
});

try {
socket.send(utf8.encode(jsonEncode({"search" : true})), InternetAddress("255.255.255.255"), portLocalDiscovery);
} on SocketException catch(e) {
print("Local discovery on ${e.address}:${e.port} failed, error code = ${e.osError?.errorCode}, ${e.osError?.message}");
}

await Future.delayed(const Duration(milliseconds: 400));
socket.close();
}
}

return ipPort;
}

0 comments on commit 5f8b81e

Please sign in to comment.