api.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import 'dart:async';
  2. import 'dart:typed_data';
  3. import 'package:common_pub/model/position.dart';
  4. import 'package:common_pub/model/game_map.dart';
  5. import 'package:get/get.dart';
  6. import 'package:grpc/grpc.dart';
  7. import '../logger.dart';
  8. import 'app.dart';
  9. import '../global_var.dart';
  10. import '../pb.dart' as pb;
  11. export '../pb.dart';
  12. typedef SmsType = pb.SmsType;
  13. class ApiService extends GetxService{
  14. static ApiService get to => Get.find();
  15. AppService get app => AppService.to;
  16. ClientChannel? channel;
  17. String get _appVersion => app.appVersion;
  18. Future<ApiService> init()async{
  19. channel = _newChannel();
  20. await syncTime();
  21. return this;
  22. }
  23. String? get token {
  24. final out = app.userProfile.token.val;
  25. if (out.isEmpty) {
  26. return null;
  27. }
  28. return out;
  29. }
  30. set token(String? v) {
  31. app.userProfile.token.val = v ?? '';
  32. }
  33. ClientChannel _newChannel(){
  34. return ClientChannel(
  35. GlobalVar.apiHost,
  36. port: GlobalVar.apiPort,
  37. options: const ChannelOptions(credentials:
  38. ChannelCredentials.secure()
  39. // ChannelCredentials.insecure()
  40. ),
  41. );
  42. }
  43. pb.ApiToAppClient _newStub({Duration? timeout, ClientChannel? channel}){
  44. if (this.channel == null) {
  45. throw Exception('$runtimeType 未初始化');
  46. }
  47. final metadata = <String, String>{
  48. 'source': "${pb.LoginSource.ToApp.value}"
  49. };
  50. metadata['version'] = _appVersion;
  51. if (token != null) {
  52. metadata['token'] = token!;
  53. }
  54. // debug("token: $token");
  55. return pb.ApiToAppClient(channel??this.channel!,
  56. options: CallOptions(
  57. metadata: metadata,
  58. timeout: timeout,
  59. ));
  60. }
  61. pb.ApiToAppClient get stub {
  62. return _newStub(timeout: 10.seconds);
  63. }
  64. // 获取系统时间
  65. Future<DateTime> serverTime() async {
  66. final begin = DateTime.now();
  67. final r = await stub.toGetServerTime(pb.DefaultRequest());
  68. final cost = DateTime.now().difference(begin);
  69. final serverNow = DateTime.fromMillisecondsSinceEpoch(
  70. r.millisecondStamp.toInt(),
  71. isUtc: true)
  72. .toLocal();
  73. return serverNow.add(cost);
  74. }
  75. Future<void> syncTime()async{
  76. try {
  77. final serverNow = await serverTime();
  78. app.correctByServerNow(serverNow);
  79. info('服务器时间:${app.now}');
  80. } catch(e){
  81. warn("获取服务器时间失败: ", e);
  82. }
  83. }
  84. // 获取短信验证码
  85. Future<void> authSendCodeToPhone(String phone, SmsType smsType)async{
  86. info('authSendCodeToPhone [$phone]');
  87. await stub.toSendCodeToPhoneV2(pb.ToSendCodeToPhoneRequestV2()
  88. ..phone= phone
  89. ..smsType= smsType
  90. );
  91. }
  92. // 场控端_登录
  93. Future<void> signIn(String userCode, String password, String ip) async {
  94. final r = await stub.toSignInV2(pb.ToSignInRequestV2()
  95. ..userCode = userCode
  96. ..password = password
  97. ..ip = ip
  98. );
  99. token = r.token;
  100. debug('sign in success: $token');
  101. }
  102. // 场控端_登出
  103. void signOut(){
  104. stub.toSignOutV2(pb.DefaultRequest());
  105. token = null;
  106. }
  107. Future<Duration> getSmsSendLeftTime(String phone)async{
  108. final r = await stub.toGetSmsSendLeftTimeV2(pb.GetSmsSendLeftTimeRequest()..phone= phone);
  109. info('getSmsSendLeftTime: $phone - ${r.second}s');
  110. return r.second.seconds;
  111. }
  112. Future<BinReader> getBinReaderByMd5(Uint8List md5) async {
  113. final stream = stub.toGetBinaryByMd5(pb.ToGetBinaryByMd5Request()..md5=md5);
  114. final controller = StreamController<List<int>>();
  115. controller.onCancel = (){
  116. stream.cancel();
  117. };
  118. Future<void> rcv()async{
  119. try{
  120. await for(final one in stream){
  121. controller.add(one.data);
  122. }
  123. }finally{
  124. controller.close();
  125. stream.cancel();
  126. }
  127. }
  128. rcv();
  129. stream.headers.then((value) => debug(value));
  130. final headers = await stream.headers;
  131. final lenStr = headers['all-length']!;
  132. final length = int.parse(lenStr);
  133. final nonce = headers['nonce']!;
  134. final ext = headers['ext']!;
  135. return BinReader(
  136. data: controller.stream,
  137. length: length,
  138. ext: ext,
  139. nonce: nonce
  140. );
  141. }
  142. }
  143. extension NetImageExt on pb.NetImage{
  144. GameMap toGameMap(){
  145. final md5Data = Uint8List.fromList(md5);
  146. return GameMap()
  147. ..url = url
  148. ..md5 = md5Data
  149. ..readerBuilder = ()=> ApiService.to.getBinReaderByMd5(md5Data);
  150. }
  151. }
  152. extension DateTimeExt on pb.Timestamp{
  153. DateTime toModel(){
  154. return toDateTime(toLocal: true);
  155. }
  156. }
  157. extension PositionExt on pb.GameGpsInfo{
  158. Position toModel(){
  159. return Position(latitude: latitude, longitude: longitude)
  160. ..altitude=altitude;
  161. }
  162. }