| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- import 'dart:async';
- import 'dart:convert';
- import 'package:flutter_map/src/entity/map_location.dart';
- import 'package:injectable/injectable.dart';
- import 'package:location/data/repositories/friends_repository.dart';
- import 'package:location/di/get_it.dart';
- import 'package:location/socket/base_message.dart';
- import 'package:location/socket/socket_constants.dart';
- import 'package:location/utils/async_util.dart';
- import 'package:location/utils/atmob_log.dart';
- import 'package:location/utils/base_expand.dart';
- import 'package:web_socket_channel/web_socket_channel.dart';
- import '../data/bean/location_info.dart';
- import '../data/repositories/account_repository.dart';
- import '../data/repositories/contact_repository.dart';
- import '../data/repositories/message_repository.dart';
- import '../dialog/account_replace_dialog.dart';
- import 'location_message.dart';
- typedef OnLocationChangeListener = void Function(List<LocationInfo> data);
- @lazySingleton
- class AtmobLocationClient {
- static final String tag = 'AtmobLocationClient';
- static final List<OnLocationChangeListener> _locationListeners = [];
- WebSocketChannel? _webSocket;
- StreamSubscription? _subscription;
- bool _isConnecting = false;
- CancelableFuture? cancelableFuture;
- AtmobLocationClient() {
- startWebsocketInternal();
- }
- static AtmobLocationClient getAtmobLocationClient() {
- return getIt.get<AtmobLocationClient>();
- }
- static void connectWebSocket() {
- AtmobLog.d(tag, 'connectWebSocket');
- AtmobLocationClient client = getIt.get<AtmobLocationClient>();
- client.startWebsocketInternal();
- }
- static void disConnectWebSocket() {
- AtmobLog.d(tag, 'disConnectWebSocket');
- AtmobLocationClient client = getIt.get<AtmobLocationClient>();
- client.stopWebsocketInternal();
- }
- void startWebsocketInternal() {
- if (AccountRepository.token == null ||
- AccountRepository.token?.isEmpty == true ||
- _isConnecting) {
- return;
- }
- cancelableFuture?.cancel();
- cancelableFuture = AsyncUtil.retryWithExponentialBackoff(
- () => _startConnect(), 4,
- initialInterval: Duration(seconds: 2));
- cancelableFuture!.catchError((error) {
- AtmobLog.d(tag, '重试最大次数 异常 error:$error');
- startWebsocketInternal();
- });
- }
- void stopWebsocketInternal() {
- AtmobLog.d(tag, 'stopWebsocketInternal');
- cancelableFuture?.cancel();
- _disposePreviousConnection();
- }
- void _disposePreviousConnection() {
- _webSocket?.sink.close();
- _webSocket = null;
- _subscription?.cancel();
- _subscription = null;
- _isConnecting = false;
- }
- Future<void> _startConnect() async {
- AtmobLog.d(tag, '_startConnect');
- _disposePreviousConnection();
- final webSocket = WebSocketChannel.connect(Uri.parse(
- '${SocketConstants.locationBaseUrl}${AccountRepository.token}'));
- _webSocket = webSocket;
- try {
- await webSocket.ready;
- AtmobLog.d(tag, 'webSocket 连接成功');
- _isConnecting = true;
- } catch (e) {
- AtmobLog.d(tag, 'webSocket 连接失败 error:$e');
- rethrow;
- }
- _subscription = webSocket.stream
- .map((s) {
- AtmobLog.d(tag, 'webSocket receive:$s');
- try {
- Map<String, dynamic> data = jsonDecode(s);
- return BaseMessage.fromJson(data);
- } catch (e) {
- AtmobLog.d(tag, 'BaseMessage jsonDecode error:$e');
- }
- return null;
- })
- .where((message) {
- if (message == null || message.cmd == null) {
- return false;
- }
- switch (message.cmd) {
- case SocketConstants.refreshFriendList:
- FriendsRepository.getInstance().refreshFriends();
- break;
- case SocketConstants.refreshFriendRequest:
- MessageRepository.getInstance().refreshFriendWaitingCount();
- break;
- case SocketConstants.refreshFriendMessage:
- MessageRepository.getInstance().refreshUnreadMessage();
- break;
- case SocketConstants.refreshContact:
- ContactRepository.getInstance().refreshContactList();
- break;
- case SocketConstants.refreshMember:
- AccountRepository.getInstance().refreshMemberStatus();
- break;
- case SocketConstants.refreshUserLogin:
- AccountReplaceDialog.show();
- AccountRepository.getInstance().logout();
- break;
- }
- return SocketConstants.receiveFriendBatchLocation == message.cmd;
- })
- .map((message) => message?.data)
- .where((data) => data != null)
- .cast<String>()
- .map((s) {
- try {
- List<dynamic> jsonList = jsonDecode(s);
- return jsonList.map((e) => LocationInfo.fromJson(e)).toList();
- } catch (e) {
- AtmobLog.d(tag, 'List<LocationInfo> jsonDecode error:$e');
- }
- })
- .bufferTime(Duration(seconds: 5))
- .where((locationInfos) => locationInfos.isNotEmpty)
- .map((lists) {
- Map<String, LocationInfo> idLocation = {};
- for (var list in lists) {
- if (list == null || list.isEmpty) {
- continue;
- }
- for (var location in list) {
- String? userId = location.userId;
- if (userId == null ||
- location.longitude == 0 ||
- location.latitude == 0) {
- continue;
- }
- idLocation[userId] = location;
- }
- }
- return idLocation.values.toList();
- })
- .listen(
- _handleLocationMessage,
- onError: _handleError,
- onDone: _handleDisconnect,
- );
- }
- void _handleLocationMessage(List<LocationInfo> data) {
- AtmobLog.d(tag, '接收到位置信息: ${data.length}');
- for (var listener in _locationListeners) {
- listener(data);
- }
- }
- // 断开处理
- void _handleDisconnect() {
- AtmobLog.e(tag, 'WebSocket 断开连接');
- _isConnecting = false;
- startWebsocketInternal();
- }
- void _handleError(error) {
- AtmobLog.e(tag, 'WebSocket 错误: $error');
- }
- static void addLocationListener(OnLocationChangeListener listener) {
- _locationListeners.add(listener);
- }
- static void removeLocationListener(OnLocationChangeListener listener) {
- _locationListeners.remove(listener);
- }
- void _sendMessage(String msg) {
- if (_webSocket == null) {
- return;
- }
- // _webSocket!.sink.add(msg);
- AtmobLog.d(tag, 'send location: $msg');
- }
- void uploadLocation(MapLocation location) {
- if (_webSocket == null ||
- location.latitude == 0 && location.longitude == 0 ||
- location.address == null ||
- location.address!.isEmpty) {
- return;
- }
- _sendMessage(LocationMessage.obtainMessage(location));
- }
- }
|