owntracks-viewer/lib/web_socket_cubit.dart

101 lines
2.8 KiB
Dart

// web_socket_cubit.dart
import 'dart:async';
import 'dart:convert';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ot_viewer_app/owntracks_api.dart';
import 'package:ot_viewer_app/settings_page.dart';
import 'package:ws/ws.dart';
import 'package:rust_core/option.dart';
// Define the state. For simplicity, we're just using Map<String, dynamic> directly.
// You might want to define a more specific state class based on your application's needs.
abstract class LocationUpdateState {}
class LocationUpdateUnconnected extends LocationUpdateState {}
class LocationUpdateConnected extends LocationUpdateState {}
class LocationUpdateReceived extends LocationUpdateState {
Point position;
(String, String) deviceId;
LocationUpdateReceived(this.position, this.deviceId);
}
class LocationSubscribeCubit extends Cubit<LocationUpdateState> {
Option<WebSocketClient> _wsClient = None;
LocationSubscribeCubit() : super(LocationUpdateUnconnected());
subscribe(SettingsState settings) async {
if(_wsClient.isSome()) {
await _wsClient.unwrap().close();
_wsClient = None;
}
var ws = await OwntracksApi(
baseUrl: settings.url,
username: settings.username,
pass: settings.password)
.createWebSocketConnection(
wsPath: 'last',
onMessage: (msg) {
if (msg is String) {
if (msg == 'LAST') {
return;
}
try {
final Map<String, dynamic> map = jsonDecode(msg);
if (map['_type'] == 'location') {
// filter points (only the ones for this device pls!)
final topic = (map['topic'] as String?)?.split('/');
if (topic == null || topic.length < 3) {
// couldn't reconstruct ID, bail
return;
}
// build device_id
final deviceId = (topic[1], topic[2]);
// build point
final p = Point(
lat: map['lat'] as double,
lon: map['lon'] as double,
timestamp:
DateTime.fromMillisecondsSinceEpoch(map['tst'] as int));
emit(LocationUpdateReceived(p, deviceId));
}
} catch (e) {
print('BUG: Couldn\'t parse WS message: $msg ($e)');
}
}
},
onStateChange: (sc) {
if (sc case WebSocketClientState$Open(:final url)) {
_wsClient.map((wsc) => wsc.add('LAST'));
}
print(sc);
},
);
_wsClient = Some(ws);
emit(LocationUpdateConnected());
}
@override
void onChange(Change<LocationUpdateState> change) {
print('loc_sub_cubit change: $change');
}
@override
Future<void> close() async {
await _wsClient.toFutureOption().map((conn) => conn.close());
return super.close();
}
}