feature: update owners by websocket
This commit is contained in:
parent
49e74feb4f
commit
116bacf428
6 changed files with 139 additions and 23 deletions
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "seshat",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "debug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seshat (profile mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seshat (release mode)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"flutterMode": "release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:seshat/data/services/api_client.dart';
|
import 'package:seshat/data/services/api_client.dart';
|
||||||
import 'package:seshat/data/services/websocket_client.dart';
|
import 'package:seshat/data/services/websocket_client.dart';
|
||||||
import 'package:seshat/domain/models/owner.dart';
|
import 'package:seshat/domain/models/owner.dart';
|
||||||
|
|
@ -14,6 +17,10 @@ class OwnerRepository {
|
||||||
|
|
||||||
final ApiClient _apiClient;
|
final ApiClient _apiClient;
|
||||||
final WebsocketClient _wsClient;
|
final WebsocketClient _wsClient;
|
||||||
|
final BehaviorSubject<Owner> _ownersController = BehaviorSubject<Owner>(
|
||||||
|
sync: true,
|
||||||
|
);
|
||||||
|
late final StreamSubscription sub;
|
||||||
List<Owner>? _cachedOwners;
|
List<Owner>? _cachedOwners;
|
||||||
|
|
||||||
Future<Result<Owner>> postOwner(
|
Future<Result<Owner>> postOwner(
|
||||||
|
|
@ -29,29 +36,27 @@ class OwnerRepository {
|
||||||
Future<Result<List<Owner>>> getOwners() async {
|
Future<Result<List<Owner>>> getOwners() async {
|
||||||
if (_cachedOwners == null) {
|
if (_cachedOwners == null) {
|
||||||
final result = await _apiClient.getOwners();
|
final result = await _apiClient.getOwners();
|
||||||
|
_wsClient.connect();
|
||||||
|
|
||||||
if (result is Ok<List<Owner>>) {
|
if (result is Ok<List<Owner>>) {
|
||||||
_cachedOwners = result.value;
|
_cachedOwners = result.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub = _wsClient.owners.listen((owner) {
|
||||||
|
debugPrint("\n\n\n\n[3] Added : $owner\n\n\n\n");
|
||||||
|
_cachedOwners!.add(owner);
|
||||||
|
_ownersController.add(owner);
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
return Result.ok(_cachedOwners!);
|
return Result.ok(_cachedOwners!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Owner> liveOwners() async* {
|
Stream<Owner> get liveOwners => _ownersController.stream;
|
||||||
await for (String data in await _wsClient.connect()) {
|
|
||||||
Map<String, dynamic> decodedData = jsonDecode(
|
dispose() {
|
||||||
data,
|
sub.cancel();
|
||||||
).cast<Map<String, dynamic>>();
|
|
||||||
Owner owner = Owner.fromJSON(decodedData);
|
|
||||||
if (_cachedOwners == null) {
|
|
||||||
await getOwners();
|
|
||||||
} else {
|
|
||||||
_cachedOwners!.add(owner);
|
|
||||||
yield* Stream.value(owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,82 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:seshat/config/constants.dart';
|
import 'package:seshat/config/constants.dart';
|
||||||
|
import 'package:seshat/domain/models/owner.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
|
|
||||||
class WebsocketClient {
|
class WebsocketClient {
|
||||||
Future<Stream<dynamic>> connect() async {
|
WebSocketChannel? _channel;
|
||||||
final channel = WebSocketChannel.connect(
|
FlutterSecureStorage? _secureStorage;
|
||||||
Uri.parse("wss://$apiBasePath/ws"),
|
final BehaviorSubject<dynamic> _baseController = BehaviorSubject();
|
||||||
|
final BehaviorSubject<Owner> _ownersController = BehaviorSubject<Owner>(
|
||||||
|
sync: true,
|
||||||
|
);
|
||||||
|
late final StreamSubscription sub;
|
||||||
|
|
||||||
|
Stream<Owner> get owners => _ownersController.stream;
|
||||||
|
|
||||||
|
Future<void> _initStore() async {
|
||||||
|
_secureStorage ??= const FlutterSecureStorage(
|
||||||
|
aOptions: AndroidOptions(encryptedSharedPreferences: true),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await channel.ready;
|
Future<void> connect() async {
|
||||||
|
await _initStore();
|
||||||
|
debugPrint("\n\n\n\nWEBSOCKET STORE IS READY\n\n\n\n");
|
||||||
|
if (_channel != null) return;
|
||||||
|
|
||||||
channel.sink.add("json-token: ");
|
debugPrint("\n\n\n\nWEBSOCKET WILL CONNECT\n\n\n\n");
|
||||||
|
_channel = WebSocketChannel.connect(Uri.parse("wss://$apiBasePath/ws"));
|
||||||
|
debugPrint("\n\n\n\nWEBSOCKET IS CONNECTING\n\n\n\n");
|
||||||
|
|
||||||
return channel.stream;
|
await _channel!.ready;
|
||||||
|
debugPrint("\n\n\n\nWEBSOCKET IS READY\n\n\n\n");
|
||||||
|
var token = await _secureStorage!.read(key: "token");
|
||||||
|
|
||||||
|
_channel!.sink.add(jsonEncode({"token": "$token"}));
|
||||||
|
_channel!.stream.listen((message) {
|
||||||
|
debugPrint("\n\n\n\n[1] Received : $message\n\n\n\n");
|
||||||
|
_baseController.add(message);
|
||||||
|
});
|
||||||
|
var data = await _baseController.stream.first;
|
||||||
|
debugPrint("\n\n\n\n$data\n\n\n\n");
|
||||||
|
var result = jsonDecode(data);
|
||||||
|
|
||||||
|
if (result["type"] == "auth_success") {
|
||||||
|
debugPrint("\n\n\n\nSUCCESS !\n\n\n\n");
|
||||||
|
sub = _baseController.stream.listen(
|
||||||
|
(message) {
|
||||||
|
final Map<String, dynamic> data = jsonDecode(message);
|
||||||
|
debugPrint("\n\n\n\n[2] Transfered : $message\n\n\n\n");
|
||||||
|
switch (data["type"]) {
|
||||||
|
case "new_owner":
|
||||||
|
final owner = Owner.fromJSON(data["data"]);
|
||||||
|
_ownersController.add(owner);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDone: _handleDisconnect,
|
||||||
|
onError: (error) {
|
||||||
|
_handleDisconnect();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleDisconnect() {
|
||||||
|
sub.cancel();
|
||||||
|
_channel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
sub.cancel();
|
||||||
|
_channel?.sink.close();
|
||||||
|
_ownersController.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||||
|
|
@ -14,6 +16,7 @@ class AddViewModel extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
final OwnerRepository _ownerRepository;
|
final OwnerRepository _ownerRepository;
|
||||||
|
late final StreamSubscription sub;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================
|
* ====================
|
||||||
|
|
@ -122,10 +125,17 @@ class AddViewModel extends ChangeNotifier {
|
||||||
debugPrint("Oupsie daysie, ${result.error}");
|
debugPrint("Oupsie daysie, ${result.error}");
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
// _ownerRepository.liveOwners().listen((Owner owner) {
|
sub = _ownerRepository.liveOwners.listen((Owner owner) {
|
||||||
// _owners.add(owner);
|
debugPrint("\n\n\n\n[5] Updated UI : $owner\n\n\n\n");
|
||||||
// notifyListeners();
|
_owners.add(owner);
|
||||||
// });
|
notifyListeners();
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
sub.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.5"
|
version: "6.1.5"
|
||||||
|
rxdart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: rxdart
|
||||||
|
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.28.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ dependencies:
|
||||||
web_socket_channel: ^3.0.3
|
web_socket_channel: ^3.0.3
|
||||||
nested: ^1.0.0
|
nested: ^1.0.0
|
||||||
flutter_secure_storage: ^9.2.4
|
flutter_secure_storage: ^9.2.4
|
||||||
|
rxdart: ^0.28.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Reference in a new issue