websocket.provider.dart 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import 'dart:convert';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:hive/hive.dart';
  4. import 'package:hooks_riverpod/hooks_riverpod.dart';
  5. import 'package:immich_mobile/constants/hive_box.dart';
  6. import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
  7. import 'package:immich_mobile/shared/models/asset.dart';
  8. import 'package:immich_mobile/shared/providers/asset.provider.dart';
  9. import 'package:logging/logging.dart';
  10. import 'package:openapi/api.dart';
  11. import 'package:socket_io_client/socket_io_client.dart';
  12. class WebsocketState {
  13. final Socket? socket;
  14. final bool isConnected;
  15. WebsocketState({
  16. this.socket,
  17. required this.isConnected,
  18. });
  19. WebsocketState copyWith({
  20. Socket? socket,
  21. bool? isConnected,
  22. }) {
  23. return WebsocketState(
  24. socket: socket ?? this.socket,
  25. isConnected: isConnected ?? this.isConnected,
  26. );
  27. }
  28. @override
  29. String toString() =>
  30. 'WebsocketState(socket: $socket, isConnected: $isConnected)';
  31. @override
  32. bool operator ==(Object other) {
  33. if (identical(this, other)) return true;
  34. return other is WebsocketState &&
  35. other.socket == socket &&
  36. other.isConnected == isConnected;
  37. }
  38. @override
  39. int get hashCode => socket.hashCode ^ isConnected.hashCode;
  40. }
  41. class WebsocketNotifier extends StateNotifier<WebsocketState> {
  42. WebsocketNotifier(this.ref)
  43. : super(WebsocketState(socket: null, isConnected: false));
  44. final log = Logger('WebsocketNotifier');
  45. final Ref ref;
  46. connect() {
  47. var authenticationState = ref.read(authenticationProvider);
  48. if (authenticationState.isAuthenticated) {
  49. var accessToken = Hive.box(userInfoBox).get(accessTokenKey);
  50. try {
  51. var endpoint = Uri.parse(Hive.box(userInfoBox).get(serverEndpointKey));
  52. debugPrint("Attempting to connect to websocket");
  53. // Configure socket transports must be specified
  54. Socket socket = io(
  55. endpoint.origin,
  56. OptionBuilder()
  57. .setPath("${endpoint.path}/socket.io")
  58. .setTransports(['websocket'])
  59. .enableReconnection()
  60. .enableForceNew()
  61. .enableForceNewConnection()
  62. .enableAutoConnect()
  63. .setExtraHeaders({"Authorization": "Bearer $accessToken"})
  64. .build(),
  65. );
  66. socket.onConnect((_) {
  67. debugPrint("Established Websocket Connection");
  68. state = WebsocketState(isConnected: true, socket: socket);
  69. });
  70. socket.onDisconnect((_) {
  71. debugPrint("Disconnect to Websocket Connection");
  72. state = WebsocketState(isConnected: false, socket: null);
  73. });
  74. socket.on('error', (errorMessage) {
  75. log.severe("Websocket Error - $errorMessage");
  76. state = WebsocketState(isConnected: false, socket: null);
  77. });
  78. socket.on('on_upload_success', _handleOnUploadSuccess);
  79. } catch (e) {
  80. debugPrint("[WEBSOCKET] Catch Websocket Error - ${e.toString()}");
  81. }
  82. }
  83. }
  84. disconnect() {
  85. debugPrint("Attempting to disconnect from websocket");
  86. var socket = state.socket?.disconnect();
  87. if (socket?.disconnected == true) {
  88. state = WebsocketState(isConnected: false, socket: null);
  89. }
  90. }
  91. stopListenToEvent(String eventName) {
  92. debugPrint("Stop listening to event $eventName");
  93. state.socket?.off(eventName);
  94. }
  95. listenUploadEvent() {
  96. debugPrint("Start listening to event on_upload_success");
  97. state.socket?.on('on_upload_success', _handleOnUploadSuccess);
  98. }
  99. _handleOnUploadSuccess(dynamic data) {
  100. final jsonString = jsonDecode(data.toString());
  101. final dto = AssetResponseDto.fromJson(jsonString);
  102. if (dto != null) {
  103. final newAsset = Asset.remote(dto);
  104. ref.watch(assetProvider.notifier).onNewAssetUploaded(newAsset);
  105. }
  106. }
  107. }
  108. final websocketProvider =
  109. StateNotifierProvider<WebsocketNotifier, WebsocketState>((ref) {
  110. return WebsocketNotifier(ref);
  111. });