From 68f06e5f05210d7cbd7a5f24b0d032b12f676f2a Mon Sep 17 00:00:00 2001 From: Zachary Atkins Date: Sat, 10 Apr 2021 17:06:05 -0500 Subject: [PATCH] p2p transaction logic --- loc_chain_app/lib/util/bluetooth.dart | 93 ++++++++++++++++--- .../lib/util/transaction_manager.dart | 11 ++- 2 files changed, 85 insertions(+), 19 deletions(-) diff --git a/loc_chain_app/lib/util/bluetooth.dart b/loc_chain_app/lib/util/bluetooth.dart index 9a3df52..f204128 100644 --- a/loc_chain_app/lib/util/bluetooth.dart +++ b/loc_chain_app/lib/util/bluetooth.dart @@ -7,18 +7,32 @@ import 'package:nearby_connections/nearby_connections.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:loc_chain_app/util/keyfile_manager.dart'; +import 'package:loc_chain_app/util/transaction_manager.dart'; + class Connect { final serviceId = "com.yourdomain.appname"; final Strategy strategy = Strategy.P2P_STAR; late final _userName; + final BuildContext? context; Map endpointMap = Map(); + Map transactionMap = Map(); - Connect() { + Connect({this.context}) { SharedPreferences.getInstance() .then((s) => _userName = s.getString('userName') ?? '0'); } + void showSnackbar(dynamic a) { + if (context == null) { + return; + } + ScaffoldMessenger.of(context!).showSnackBar(SnackBar( + content: Text(a.toString()), + )); + } + void startConnect() async { // final prefs = await SharedPreferences.getInstance(); // final userName = prefs.getString('userName') ?? " "; @@ -27,19 +41,21 @@ class Connect { bool advertise = await Nearby().startAdvertising( _userName, strategy, - onConnectionInitiated: (String id, ConnectionInfo info) { - // Called whenever a discoverer requests connection - // - // onConnectionInit - }, + onConnectionInitiated: onConnectionInit, onConnectionResult: (String id, Status status) { // Called when connection is accepted/rejected // if connection is accepted send the transaction - // - // + endpointMap.forEach((key, value) async { + String str = await Transaction.generateHash(key); + Nearby().sendBytesPayload(key, Uint8List.fromList(str.codeUnits)); + }); }, onDisconnected: (String id) { // Callled whenever a discoverer disconnects from advertiser + // delete connection info + endpointMap.remove(id); + // delete transaction info + transactionMap.remove(id); }, serviceId: serviceId, // uniquely identifies your app ); @@ -49,6 +65,19 @@ class Connect { strategy, onEndpointFound: (String id, String userName, String serviceId) { // called when an advertiser is found + Nearby().requestConnection( + userName, + id, + onConnectionInitiated: onConnectionInit, + onConnectionResult: (id, status) { + showSnackbar(status); + }, + onDisconnected: (id) { + endpointMap.remove(id); + showSnackbar( + "Disconnected from: ${endpointMap[id]!.endpointName}, id $id"); + }, + ); }, onEndpointLost: (String? id) { //called when an advertiser is lost (only if we weren't connected to it ) @@ -59,9 +88,49 @@ class Connect { // platform exceptions like unable to start bluetooth or insufficient permissions } } -} - + void onConnectionInit(String otherId, ConnectionInfo info) { + // Called whenever a discoverer requests connection + // + // onConnectionInit + if (endpointMap.containsKey(otherId)) { + Nearby().rejectConnection(otherId); + } + endpointMap[otherId] = info; + Nearby().acceptConnection( + otherId, + onPayLoadRecieved: (_otherId, payload) async { + if (payload.type != PayloadType.BYTES) return; + // completed payload from other connection + String str = String.fromCharCodes(payload.bytes!); + var parts = str.split(':'); + if (parts.length != 2) { + showSnackbar("$_otherId invalid payload: $str"); + return; + } + // Store transaction + var combinedHash = parts[0]; + var publicKey = parts[1]; + transactionMap[_otherId] = + Transaction(hash: combinedHash, pubKey: publicKey); + // sign combined hash with our private key + // upload hash+otherKey to firebase + transactionMap.remove(_otherId); + }, + onPayloadTransferUpdate: (endid, payloadTransferUpdate) { + if (payloadTransferUpdate.status == PayloadStatus.IN_PROGRESS) { + print(payloadTransferUpdate.bytesTransferred); + } else if (payloadTransferUpdate.status == PayloadStatus.FAILURE) { + print("failed"); + showSnackbar(endid + ": FAILED to transfer file"); + } else if (payloadTransferUpdate.status == PayloadStatus.SUCCESS) { + showSnackbar( + "$endid success, total bytes = ${payloadTransferUpdate.totalBytes}"); + } + }, + ); + } +} // ElevatedButton( @@ -77,10 +146,6 @@ class Connect { // }, // ), - - - - // void onConnectionInit(String id, ConnectionInfo info) { // showModalBottomSheet( // context: context, diff --git a/loc_chain_app/lib/util/transaction_manager.dart b/loc_chain_app/lib/util/transaction_manager.dart index c7e27a5..db8d623 100644 --- a/loc_chain_app/lib/util/transaction_manager.dart +++ b/loc_chain_app/lib/util/transaction_manager.dart @@ -9,12 +9,10 @@ import 'package:loc_chain_app/util/keyfile_manager.dart'; import 'dart:io'; class Transaction { - Transaction({required this.hash}) { - SharedPreferences.getInstance() - .then((s) => _id = s.getString('userName') ?? '0'); - } - late final String _id; + Transaction({required this.hash, required this.pubKey}); final String hash; + final String pubKey; + static Future generateHash(String otherUserId) async { String id = await SharedPreferences.getInstance() .then((s) => s.getString('userName') ?? ''); @@ -24,6 +22,9 @@ class Transaction { return DBCrypt() .hashpw("$lesser-$greater", KeyFileManager.keyPair.privateKey); } + + Future generateP2PPayload(String otherUserId) async => + "${await generateHash(otherUserId)}:${KeyFileManager.keyPair.publicKey}"; } class TransactionsDBManager {