diff --git a/lib/domain/connections_service.dart b/lib/domain/connections_service.dart index d1f507125..05e55b684 100644 --- a/lib/domain/connections_service.dart +++ b/lib/domain/connections_service.dart @@ -22,6 +22,7 @@ part 'package:cybearjinni/infrastructure/connection_service/app_connection_servi part 'package:cybearjinni/infrastructure/connection_service/hub_connection_service.dart'; part 'package:cybearjinni/infrastructure/connection_service/demo_connection_service.dart'; part 'package:cybearjinni/infrastructure/connection_service/none_connection_service.dart'; +part 'package:cybearjinni/infrastructure/connection_service/remote_pipes_connection_service.dart'; enum ConnectionType { appAsHub, @@ -41,33 +42,31 @@ abstract interface class ConnectionsService { static ConnectionType _currentConnectionType = ConnectionType.appAsHub; - static void setCurrentConnectionType(ConnectionType? connectionType) { + static void setCurrentConnectionType(ConnectionType connectionType) { if (connectionType == _currentConnectionType) { return; } _instance?.dispose(); + _currentConnectionType = connectionType; + switch (connectionType) { case ConnectionType.appAsHub: _instance = _AppConnectionService(); - _currentConnectionType = ConnectionType.appAsHub; case ConnectionType.hub: - _currentConnectionType = ConnectionType.hub; _instance = _HubConnectionService(); - case ConnectionType.demo: case ConnectionType.remotePipes: + _instance = _RemotePipesConnectionService(); + case ConnectionType.demo: _instance = _DemoConnectionService(); - _currentConnectionType = ConnectionType.demo; case ConnectionType.none: - case null: _instance = _NoneConnectionService(); - _currentConnectionType = ConnectionType.none; } } static ConnectionType getCurrentConnectionType() => _currentConnectionType; - Future connect(); + Future connect({String? address}); Future searchDevices(); diff --git a/lib/infrastructure/connection_service/app_connection_service.dart b/lib/infrastructure/connection_service/app_connection_service.dart index af0dca372..dc042a966 100644 --- a/lib/infrastructure/connection_service/app_connection_service.dart +++ b/lib/infrastructure/connection_service/app_connection_service.dart @@ -63,5 +63,5 @@ class _AppConnectionService implements ConnectionsService { IcSynchronizer().getVendors(); @override - Future connect() async => true; + Future connect({String? address}) async => true; } diff --git a/lib/infrastructure/connection_service/demo_connection_service.dart b/lib/infrastructure/connection_service/demo_connection_service.dart index 1dd066164..b0f17ddac 100644 --- a/lib/infrastructure/connection_service/demo_connection_service.dart +++ b/lib/infrastructure/connection_service/demo_connection_service.dart @@ -61,5 +61,5 @@ class _DemoConnectionService implements ConnectionsService { IcSynchronizer().getVendors(); @override - Future connect() async => true; + Future connect({String? address}) async => true; } diff --git a/lib/infrastructure/connection_service/hub_connection_service.dart b/lib/infrastructure/connection_service/hub_connection_service.dart index 6fde90320..70bb08beb 100644 --- a/lib/infrastructure/connection_service/hub_connection_service.dart +++ b/lib/infrastructure/connection_service/hub_connection_service.dart @@ -270,7 +270,7 @@ class _HubConnectionService implements ConnectionsService { IcSynchronizer().getVendors(); @override - Future connect() async { + Future connect({String? address}) async { searchDevices(); if (hubIp == null) { return false; diff --git a/lib/infrastructure/connection_service/none_connection_service.dart b/lib/infrastructure/connection_service/none_connection_service.dart index fb1049d22..7908507ee 100644 --- a/lib/infrastructure/connection_service/none_connection_service.dart +++ b/lib/infrastructure/connection_service/none_connection_service.dart @@ -59,5 +59,5 @@ class _NoneConnectionService implements ConnectionsService { Future> getVendors() async => []; @override - Future connect() async => true; + Future connect({String? address}) async => true; } diff --git a/lib/infrastructure/connection_service/remote_pipes_connection_service.dart b/lib/infrastructure/connection_service/remote_pipes_connection_service.dart new file mode 100644 index 000000000..3b0920734 --- /dev/null +++ b/lib/infrastructure/connection_service/remote_pipes_connection_service.dart @@ -0,0 +1,239 @@ +part of 'package:cybearjinni/domain/connections_service.dart'; + +class _RemotePipesConnectionService implements ConnectionsService { + /// Port to connect to the cbj hub, will change according to the current + /// running environment + int hubPort = 50051; + + String? address; + String? networkBssid; + String? networkName; + + ClientChannel? channel; + CbjHubClient? stub; + + StreamController>? entitiesStream; + StreamController>? areasStream; + + BehaviorSubject hubMessagesToApp = + BehaviorSubject(); + + // StreamController appMessagesToHub = + // StreamController(); + + BehaviorSubject appMessagesToHub = BehaviorSubject(); + + @override + Future dispose() async { + entitiesStream?.close(); + } + + @override + Future> get getEntities async { + appMessagesToHub.sink.add( + ClientStatusRequests(sendingType: SendingType.allEntities.name), + ); + final HashMap entities = HashMap(); + + await for (final RequestsAndStatusFromHub message + in hubMessagesToApp.stream) { + final SendingType sendingType = + SendingTypeExtension.fromString(message.sendingType); + if (sendingType != SendingType.allEntities) { + continue; + } + + try { + final Map entitiesMap = Map.from( + jsonDecode(message.allRemoteCommands) as Map, + ); + entities.addEntries( + entitiesMap.entries.map( + (e) => MapEntry( + e.key, + DeviceHelper.convertJsonStringToDomain(e.value), + ), + ), + ); + } catch (e) { + logger.e('Error converting entities\n$e'); + } + break; + } + + return entities; + } + + @override + Future> get getAreas async { + appMessagesToHub.sink.add( + ClientStatusRequests(sendingType: SendingType.allAreas.name), + ); + + final HashMap areas = HashMap(); + + await for (final RequestsAndStatusFromHub message + in hubMessagesToApp.stream) { + final SendingType sendingType = + SendingTypeExtension.fromString(message.sendingType); + if (sendingType != SendingType.allAreas) { + continue; + } + + try { + final Map entitiesMap = Map.from( + jsonDecode(message.allRemoteCommands) as Map, + ); + areas.addEntries( + entitiesMap.entries.map( + (e) => MapEntry( + e.key, + AreaEntityDtos.fromJson( + jsonDecode(e.value) as Map, + ).toDomain(), + ), + ), + ); + } catch (e) { + logger.e('Error converting areas\n$e'); + } + break; + } + + return areas; + } + + @override + Future> get getScenes async { + appMessagesToHub.sink.add( + ClientStatusRequests(sendingType: SendingType.allScenes.name), + ); + + final HashMap scenesMap = HashMap(); + + await for (final RequestsAndStatusFromHub message + in hubMessagesToApp.stream) { + final SendingType sendingType = + SendingTypeExtension.fromString(message.sendingType); + if (sendingType != SendingType.allScenes) { + continue; + } + + try { + final Map entities = Map.from( + jsonDecode(message.allRemoteCommands) as Map, + ); + scenesMap.addEntries( + entities.entries.map( + (e) => MapEntry( + e.key, + SceneCbjDtos.fromJson(jsonDecode(e.value) as Map) + .toDomain(), + ), + ), + ); + } catch (e) { + logger.e('Error converting scenes\n$e'); + } + break; + } + + return scenesMap; + } + + @override + Future searchDevices() async {} + + @override + void setEntityState(RequestActionObject action) { + appMessagesToHub.sink.add( + ClientStatusRequests( + sendingType: SendingType.setEntitiesAction.name, + allRemoteCommands: action.toInfrastructure().toJsonString(), + ), + ); + } + + @override + Stream> watchEntities() { + entitiesStream?.close(); + + entitiesStream = StreamController.broadcast(); + return entitiesStream!.stream; + } + + @override + Stream> watchAreas() { + areasStream?.close(); + + areasStream = StreamController.broadcast(); + return areasStream!.stream; + } + + @override + Future setNewArea(AreaEntity area) async {} + + @override + Future setEtitiesToArea(String areaId, HashSet entities) async {} + + @override + Future addScene(SceneCbjEntity scene) async {} + + @override + Future activateScene(String id) async {} + + @override + Future loginVendor(VendorLoginEntity value) async {} + + @override + Future> getVendors() async => + IcSynchronizer().getVendors(); + + @override + Future connect({String? address}) async { + this.address = address; + if (this.address == null) { + return false; + } + + connectHelper(); + + return true; + } + + /// Connect directly to the Hub if possible + Future connectHelper() async { + if (address == null) { + return; + } + + try { + channel = ClientChannel( + address!, + port: hubPort, + options: + const ChannelOptions(credentials: ChannelCredentials.insecure()), + ); + + channel!.onConnectionStateChanged.listen((event) { + logger.i('gRPC connection state $event'); + }); + + stub = CbjHubClient(channel!); + + final ResponseStream response = + stub!.clientTransferEntities( + appMessagesToHub.stream, + ); + + // appMessagesToHub.sink + // .add(ClientStatusRequests(sendingType: SendingType.firstConnection)); + + hubMessagesToApp.addStream(response); + await Future.delayed(const Duration(seconds: 3)); + } catch (e) { + logger.e('Caught error while stream with hub\n$e'); + await channel?.shutdown(); + } + } +} diff --git a/lib/infrastructure/core/injection.dart b/lib/infrastructure/core/injection.dart index 512fd02b2..45e0fe6e9 100644 --- a/lib/infrastructure/core/injection.dart +++ b/lib/infrastructure/core/injection.dart @@ -1,4 +1,4 @@ -import 'package:cbj_integrations_controller/integrations_controller.dart'; +import 'package:cybearjinni/infrastructure/core/injection.config.dart'; import 'package:cybearjinni/infrastructure/core/logger.dart'; import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; diff --git a/lib/main.dart b/lib/main.dart index c28244d98..a370484f6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:cbj_integrations_controller/integrations_controller.dart'; import 'package:cybearjinni/infrastructure/core/injection.dart'; import 'package:cybearjinni/presentation/core/app_widget.dart'; import 'package:cybearjinni/presentation/core/routes/app_router.dart'; @@ -8,7 +7,6 @@ import 'package:flutter/material.dart'; Future main() async { configureDependencies(EnvApp.dev); - configureInjection(Env.devPc); WidgetsFlutterBinding.ensureInitialized(); diff --git a/lib/presentation/pages/plus_button.dart b/lib/presentation/pages/plus_button.dart index 7d2a9c26a..e325fcfc1 100644 --- a/lib/presentation/pages/plus_button.dart +++ b/lib/presentation/pages/plus_button.dart @@ -12,7 +12,7 @@ import 'package:iconify_flutter/icons/simple_icons.dart'; class PlusButtonPage extends StatelessWidget { Future _logout(BuildContext context) async { context.router.replace(const ConnectToHubRoute()); - ConnectionsService.setCurrentConnectionType(null); + ConnectionsService.setCurrentConnectionType(ConnectionType.none); } @override diff --git a/lib/presentation/pages/remote_pipes_page.dart b/lib/presentation/pages/remote_pipes_page.dart index f4bdc2361..00c781134 100644 --- a/lib/presentation/pages/remote_pipes_page.dart +++ b/lib/presentation/pages/remote_pipes_page.dart @@ -1,6 +1,6 @@ import 'package:adaptive_action_sheet/adaptive_action_sheet.dart'; import 'package:auto_route/auto_route.dart'; -import 'package:cbj_integrations_controller/integrations_controller.dart'; +import 'package:cybearjinni/domain/connections_service.dart'; import 'package:cybearjinni/presentation/atoms/atoms.dart'; import 'package:cybearjinni/presentation/core/snack_bar_service.dart'; import 'package:cybearjinni/presentation/molecules/molecules.dart'; @@ -71,15 +71,9 @@ class _RemotePipesWidgetState extends State { if (remotePipesDomainName == null || remotePipesDomainName!.isEmpty) { return; } - - final RemotePipesEntity remotePipesEntity = - RemotePipesEntity.empty().copyWith( - domainName: RemotePipesDomain(remotePipesDomainName!), - ); - + ConnectionsService.setCurrentConnectionType(ConnectionType.remotePipes); + ConnectionsService.instance.connect(address: remotePipesDomainName); context.router.pop(); - await IRemotePipesRepository.instance - .setRemotePipesDomainName(remotePipesEntity); } @override @@ -91,7 +85,6 @@ class _RemotePipesWidgetState extends State { children: [ const TextAtom( 'Please insert the Remote Pipes domain', - style: TextStyle(color: Colors.black, fontSize: 25), ), const SizedBox( height: 60, diff --git a/lib/presentation/pages/splash_page.dart b/lib/presentation/pages/splash_page.dart index ea0cda862..6c528ec64 100644 --- a/lib/presentation/pages/splash_page.dart +++ b/lib/presentation/pages/splash_page.dart @@ -28,16 +28,21 @@ class _SplashPageState extends State { } Future initilizeApp() async { + // TODO: can we remove await Hive.initFlutter(); AppCommands(); + // TODO: can we remove await Future.value([ IDbRepository.instance.initializeDb(isFlutter: true), ILocalDbRepository.instance.asyncConstructor(), // ISavedDevicesRepo.instance.setUpAllFromDb(), ]); + // TODO: can we remove MqttServerRepository(); + // TODO: Same as App Command? PhoneCommandsD(); SystemCommandsManager(); + // TODO: can we remove NodeRedRepository(); ConnectionsService.instance; _navigate();