manager.dart 6.02 KB
import 'dart:convert';

import 'package:android_id/android_id.dart';
import 'package:auto_track/auto_track/config/queue.dart';
import 'package:crypto/crypto.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/widgets.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:http/http.dart' as http; // 使用 http 包

import '../log/logger.dart';
import '../utils/sign.dart';
import 'config.dart';

typedef UpdateConfigFunc = AutoTrackConfig Function(AutoTrackConfig);

const String GET_TOKEN = "/equipment-auth/equipment/getToken/v1";
const String UPLOAD = "/bd-datapoint/equipment/dataPoint/zip";

class AutoTrackConfigManager {
  static final AutoTrackConfigManager instance = AutoTrackConfigManager._();

  AutoTrackConfigManager._() {
    PackageInfo.fromPlatform().then( (value) {
      _appVersion = value.version;
      _appName = value.appName;
      _pkgName = value.packageName;
    });
  }

  String _appVersion = '';
  String get appVersion => _appVersion;

  String _appName = '';
  String get appName => _appName;

  String _pkgName = '';
  String get pkgName => _pkgName;

  BaseDeviceInfo? _baseDeviceInfo;
  BaseDeviceInfo? get baseDeviceInfo => _baseDeviceInfo;


  String? _deviceId;
  String? get deviceId => _deviceId;

  Map<String, dynamic> _deviceInfo = {};
  Map<String, dynamic> get deviceInfo => _deviceInfo;

  AutoTrackConfig _config = AutoTrackConfig();
  AutoTrackConfig get config => _config;

  bool _autoTrackEnable = false;
  bool get autoTrackEnable => _autoTrackEnable;

  void setConfig(AutoTrackConfig config) {
    updateConfig((old) {
      return config;
    });
  }

  void updateConfig(UpdateConfigFunc func) {
    _config = func(_config);
    if (_config.enableUpload) {
      AutoTrackQueue.instance.start();
    } else {
      AutoTrackQueue.instance.stop();
    }
  }

  void _updateDeviceId() {
    if (_baseDeviceInfo is IosDeviceInfo) {
      _deviceId = md5
          .convert(utf8.encode(
              '${(_baseDeviceInfo as IosDeviceInfo).identifierForVendor}#${config.appKey}'))
          .toString();
    } else if (_baseDeviceInfo is AndroidDeviceInfo) {
      const AndroidId().getId().then((value) => _deviceId =
          md5.convert(utf8.encode('$value#${config.appKey}')).toString());
    } else if (_baseDeviceInfo is MacOsDeviceInfo) {
      _deviceId =
          '${(_baseDeviceInfo as MacOsDeviceInfo).hostName}-${(_baseDeviceInfo as MacOsDeviceInfo).computerName}';
    } else if (_baseDeviceInfo is OhosDeviceInfo) {
      _deviceId =
      '${(_baseDeviceInfo as OhosDeviceInfo).odID}${config.appKey}';
    } else {
      _deviceId = null;
    }
  }

  void enableAutoTrack(bool enable) {
    _autoTrackEnable = enable;
    if(enable){
      DeviceInfoPlugin().deviceInfo.then((value) {
        _deviceInfo = value.data;
        _baseDeviceInfo = value;
        _updateDeviceId();
      });
    }
    //获取token
    getToken(false);
  }

  bool _isGetting = false;

  void getToken(bool refreshToken) async {
    if (_isGetting) {
      return;
    }
    _isGetting = true;
    AutoTrackLogger.getInstance().debug('track getToken => start');

    await Future.delayed(const Duration(milliseconds: 2000));
    try {
      int currentSeconds = DateTime.now().millisecondsSinceEpoch;

      Map<String, String> sParams = {
        "productKey": _config.appKey ?? '',
        "equipmentId": _deviceId ?? '',
        "otherInfo": _appName,
        "time": currentSeconds.toString(),
      };

      AutoTrackLogger.getInstance().debug('track getToken => param $sParams');

      String sign = SignUtil.sign(sParams, _config.appSecret!);
      sParams["sign"] = sign;

      // 发送 POST 请求(使用 http 包)
      final response = await http
          .post(
            Uri.parse(_config.host! + GET_TOKEN),
            body: sParams,
          )
          .timeout(const Duration(seconds: 10)); // 添加超时

      // 处理响应
      if (response.statusCode == 200) {
        final jsonResponse = jsonDecode(response.body) as Map<String, dynamic>;
        final code = jsonResponse['code'] as int;
        if (code == 200) {
          final tokenValue = jsonResponse['data'] as String;
          AutoTrackLogger.getInstance().debug('track getToken => success $tokenValue');
          _config.token = tokenValue;
        } else {
          AutoTrackLogger.getInstance().debug('track getToken => fail $code');
          _reGetToken(refreshToken); // 重试
        }
      } else {
        AutoTrackLogger.getInstance().debug('track getToken => failCode: ${response.statusCode}');
        _reGetToken(refreshToken); // 非 200 状态码重试
      }
    } catch (e) {
      print('BoeDataAPI Error: $e');
      _reGetToken(refreshToken); // 异常重试
    } finally {
      _isGetting = false; // 无论成功与否,重置标志
    }
  }

  void _reGetToken(bool refreshToken) {
    Future.delayed(const Duration(seconds: 2), () => getToken(refreshToken));
  }


  List<AutoTrackPageConfig> get pageConfigs => _config.pageConfigs;

  bool get useCustomRoute => _config.useCustomRoute;

  AutoTrackPageConfig getPageConfig(Widget pageWidget) {
    return _config.pageConfigs.firstWhere(
        (pageConfig) => pageConfig.isPageWidget!(pageWidget),
        orElse: () => AutoTrackPageConfig());
  }

  Set<Key> getIgnoreElementKeySet() => _config.getIgnoreElementKeySet();

  Set<String> getIgnoreElementStringKeySet() =>
      _config.getIgnoreElementStringKeySet();

  bool isIgnoreElement(Key? key) {
    if (key == null) {
      return false;
    }
    if (getIgnoreElementKeySet().contains(key)) {
      return true;
    }
    if (getIgnoreElementStringKeySet().contains(key.toString())) {
      return true;
    }

    if (key is ValueKey) {
      return getIgnoreElementStringKeySet().contains(key.value);
    }

    return false;
  }

  bool get pageViewEnabled => _config.enablePageView;

  bool get pageLeaveEnable => _config.enablePageLeave;

  bool get clickEnable => _config.enableClick;

  bool get dragEnable => _config.enableDrag;

  bool get ignoreNullKeyEnable => _config.enableIgnoreNullKey;
}