| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:grpc/grpc.dart';
- import 'package:fixnum/fixnum.dart' as fixnum;
- import 'package:trackoffical_app/model.dart';
- import 'package:trackoffical_app/service/app.dart';
- import 'package:trackoffical_app/pb.dart' as pb;
- import 'package:trackoffical_app/service/service.dart';
- import 'package:trackoffical_app/utils.dart';
- import 'package:protobuf/protobuf.dart';
- import '../logger.dart';
- import '../global.dart';
- class _Stub{
- _Stub(
- this.channel,
- this.stub
- );
- ClientChannel channel;
- pb.ApiAppClient stub;
- }
- class ApiService extends IService {
- static ApiService get to => Get.find();
- ClientChannel? channel;
- String? get token {
- final out = App.to.userProfile.token.val;
- if (out.isEmpty) {
- return null;
- }
- return out;
- }
- set token(String? v) {
- App.to.userProfile.token.val = v ?? '';
- }
- String get _appVersion => App.to.appVersion;
- ClientChannel _newChannel(){
- return ClientChannel(
- GlobalVar.apiHost,
- port: GlobalVar.apiPort,
- options: const ChannelOptions(credentials: ChannelCredentials.secure()),
- );
- }
- pb.ApiAppClient _getStub({Duration? timeout, ClientChannel? channel}){
- if (this.channel == null) {
- throw Exception('$runtimeType 未初始化');
- }
- final metadata = <String, String>{
- 'source': "${pb.LoginSource.UserApp.value}"
- };
- metadata['version'] = _appVersion;
- if (token != null) {
- metadata['token'] = token!;
- }
- return pb.ApiAppClient(channel??this.channel!,
- options: CallOptions(
- metadata: metadata,
- timeout: timeout,
- ));
- }
- pb.ApiAppClient get stub {
- return _getStub(timeout: 10.seconds);
- }
- _Stub get _stubForStream {
- final ch = _newChannel();
- return _Stub(ch, _getStub(channel: ch)) ;
- }
- Future<void> syncTime()async{
- try{
- final serverNow = await serverTime();
- App.to.correctByServerNow(serverNow);
- info('服务器时间:${App.to.now}');
- }catch(e){
- warn("获取服务器时间失败: ", e);
- }
- }
- @override
- Future<ApiService> init() async {
- channel = _newChannel();
- syncTime();
- return this;
- }
- Future<bool> isSignIn() async {
- final token = this.token;
- if (token == null) {
- return false;
- }
- if (token.isNotEmpty) {
- try {
- await flushUserInfo();
- } catch (e) {
- return false;
- }
- return true;
- } else {
- return false;
- }
- }
- Future<void> getVfCode() async {
- await stub.getVfPic(pb.DefaultRequest());
- }
- Future<void> authSendCodeToPhone(String phone, pb.SmsType smsType)async{
- info('authSendCodeToPhone [$phone]');
- await stub.authSendCodeToPhone(pb.AuthSendCodeToPhoneRequest()
- ..phone= phone
- ..userType= pb.UserType.AppUser
- ..smsType= smsType
- );
- }
- Future<void> signUp(String phone, String code, String? name, pb.User_Sex sex)async{
- info('signUp [$phone]');
- var r = await stub.signUp(pb.SignUpRequest()
- ..phone= phone
- ..password= code
- ..nickname= name??''
- ..userType= pb.UserType.AppUser
- ..sex= sex
- );
- token = r.token;
- }
- Future<void> signIn(String name, String password) async {
- final r = await stub.signIn(pb.SignInRequest()
- ..name = name
- ..password = password
- );
- token = r.token;
- debug('sign in success: $token');
- }
- void signOut(){
- stub.signOut(pb.SignOutRequest());
- token = null;
- }
- Future<pb.GameData> gameStart(
- int actId,
- fixnum.Int64 courseId,
- ) async {
- await syncTime();
- final r = await stub.gameStart(pb.GameStartRequest()
- ..actId= fixnum.Int64(actId)
- ..courseId= courseId
- ..hrBand= pb.HrBandType.UseHrBand
- );
- return r.gameData;
- }
- Future<void> gameSaveUpload(pb.GameSaveUploadRequest save) async {
- info('gameSaveUpload');
- final save2 = save.deepCopy();
- save2.gameSave.gameHrInfos.clear();
- save2.gameSave.gameGpsInfos.clear();
- await stub.gameSaveUpload(save2);
- return;
- }
- Future<pb.ActivityListReply> activityList({
- MPosition? position
- }) async {
- info('call providerList $position');
- final req = pb.PositionRequest();
- if(position!= null){
- req.position=position.toPb();
- }
- final r = await stub.activityList(req);
- return r;
- }
- Future<pb.ActivityDetailReply> activityDetail(int id) async {
- debug('call activityDetail $id');
- final r =
- await stub.activityDetail(pb.IdRequest()..id= fixnum.Int64(id));
- return r;
- }
- Future<void> flushUserInfo()async{
- info('flushUserInfo');
- final r = await stub.myUserQuery(pb.DefaultRequest());
- final userProfile = App.to.userProfile;
- userProfile.username.value = r.name;
- userProfile.head.value = r.head.toModel();
- userProfile.sex = r.sex.toModel();
- userProfile.age.val = App.to.now.year - r.birthdayYear;
- userProfile.heightCm.val = r.heightMillimeter / 10;
- userProfile.weightKg.val = r.weightGram / 1000;
- userProfile.rhr.val = r.staticHr;
- }
- Future<void> _userInfoEdit(
- String nickName,
- Sex sex,
- int birthdayYear,
- double heightCm,
- double weightKg,
- int rhr,
- ){
- return stub.userInfoEdit(pb.UserInfoEditRequest()
- ..nickName= nickName
- ..sex= sex.toPb()
- ..birthdayYear= birthdayYear
- ..heightMillimeter= (heightCm * 10).toInt()
- ..weightGram= (weightKg*1000).toInt()
- ..staticHr = rhr
- );
- }
- Future<void> saveUserInfo(){
- App app = Get.find();
- final userProfile = app.userProfile;
- return _userInfoEdit(
- userProfile.username.value,
- userProfile.sex,
- app.now.year - userProfile.age.val,
- userProfile.heightCm.val,
- userProfile.weightKg.val,
- userProfile.rhr.val);
- }
- Future<pb.MyHistoryGameReply> gameHistory({
- required pb.GameState state,
- required int offset,
- required int limit,
- })async{
- return await stub.myHistoryGame(pb.MyHistoryGameRequest()
- ..state= state
- ..offset= offset
- ..limit=limit
- );
- }
- Future<void> gameHistoryDel(fixnum.Int64 id){
- return stub.historyGameDel(pb.IdRequest()..id= id);
- }
- Future<void> closeAccount()async{
- await stub.unsubscribe(pb.DefaultRequest());
- }
- Future<void> gameGpsUpload(
- fixnum.Int64 gameId,
- List<MPosition> data,
- int distanceMeter,
- int paceSecond,
- ){
- info('gameGpsUpload');
- List<pb.GameGpsInfo> l = data.map((p) => p.toPb2()).toList();
- final req = pb.GameGpsUploadRequest()
- ..gameId= gameId.toInt()
- ..distance= distanceMeter
- ..pace= paceSecond
- ..gameGpsInfos.addAll(l);
- return stub.gameGpsUpload(req);
- }
- Future<void> gameHrUpload(
- fixnum.Int64 gameId,
- List<pb.HeartRate> data,
- ){
- info('gameHrUpload');
- return stub.gameHrUpload(pb.GameHrUploadRequest()
- ..gameId= gameId.toInt()
- ..gameHrInfos.addAll(data)
- );
- }
- Future<void> gameExerciseStateUpload(
- fixnum.Int64 gameId,
- int avgHr,
- int maxHr,
- /// 单位卡,不是千卡
- int cle,
- double ck,
- double ei,
- int stepCount,
- // %
- int heartRatePercent
- ){
- info('gameExerciseStateUpload');
- return stub.gameCleUpload(pb.GameCleUploadRequest()
- ..gameId= gameId.toInt()
- ..avgHr= avgHr
- ..maxHr= maxHr
- ..cle= cle
- ..ck= ck.round()
- .. ei= ei
- ..stepNum= stepCount
- ..heartRatePercent= heartRatePercent
- );
- }
- @override
- void onClose() {
- channel?.shutdown();
- }
- Future<DateTime> serverTime() async {
- final begin = DateTime.now();
- final r = await stub.getServerTime(pb.DefaultRequest());
- final cost = DateTime.now().difference(begin);
- final serverNow = DateTime.fromMillisecondsSinceEpoch(
- r.millisecondStamp.toInt(),
- isUtc: true)
- .toLocal();
- return serverNow.add(cost);
- }
- Future<String> getRegionCode() async{
- final r =await stub.getRegion(pb.DefaultRequest());
- info('位置:${r.name}');
- return r.code;
- }
- Future<List<pb.Region>> getRegionList() async{
- info('getRegionList');
- final r =await stub.regionList(pb.RegionListRequest()..countryCode= "CN");
- final list = r.region;
- return list;
- }
- Future<Duration> getSmsSendLeftTime(String phone)async{
- final r = await stub.getSmsSendLeftTime(pb.GetSmsSendLeftTimeRequest()..phone= phone);
- info('getSmsSendLeftTime: $phone - ${r.second}s');
- return r.second.seconds;
- }
- Future<pb.GetUpdateVersionReply> getUpdateVersion(String version)async{
- info('getUpdateVersion: $version');
- final r = await stub.getUpdateVersion(pb.GetUpdateVersionRequest()..vCode= version);
- return r;
- }
- Future<pb.GameDetailReply> getGameHistoryDetail(fixnum.Int64 id)async{
- info('getGameHistoryDetail: $id');
- return await stub.historyGameDetail(id.toIdRequest());
- }
- Future<pb.GameDetailReply> gameFinish(fixnum.Int64 id, bool isDrop)async{
- info('gameFinish: $id , isDrop: $isDrop');
- return await stub.gameFinish(pb.GameFinishRequest()..gameId= id.toInt().. isDrop= isDrop);
- }
- Future<pb.GetInGameDataReply> getInGameData()async{
- info('getInGameData');
- return await stub.getInGameData(pb.DefaultRequest());
- }
- Future<List<pb.CareTakerInfo>> guardianList()async{
- info('guardianList');
- final r = await stub.myCareTakerQuery(pb.DefaultRequest());
- return r.list;
- }
- Future<List<pb.MyPupil>> underGuardianList()async{
- info('underGuardianList');
- final r = await stub.myPupilListQuery(pb.DefaultRequest());
- return r.list;
- }
- Future<void> guardianAdd(String phone, String memo)async{
- info('guardianAdd: $phone');
- await stub.myCareTakerAdd(pb.CareTakerInfo()
- ..cPhone= phone
- ..memo= memo
- );
- return;
- }
- Future<void> guardianDel(pb.CareTakerInfo v)async{
- info('guardianAdd: ${v.crId}');
- await stub.myCareTakerDel(v.crId.toIdRequest());
- return;
- }
- Future<List<MapInfo>> mapRecommendList(MPosition? position)async{
- info('mapRecommendList: $position');
- final req = pb.PositionRequest();
- if(position!= null){
- req.position=position.toPb();
- }
- final r = await stub.mapRecommendList(req);
- return r.mapList.map((e) => e.toModel()..isRecommend=true).toList();
- }
- Future<List<MapInfo>> mapList(MPosition? position, int offset, int limit)async{
- info('mapList: $position');
- final req = pb.MapListRequest()
- ..offset=offset
- ..limit=limit;
- if(position!= null){
- req.position=position.toPb();
- }
- final r = await stub.mapList(req);
- return r.mapList.map((e) => e.toModel()).toList();
- }
- StreamGuardianWatch guardianWatch(int id){
- info('guardianWatch: $id');
- final stub = _stubForStream;
- final stream = stub.stub.pupilInGameWatch(id.toIdRequest());
- return StreamGuardianWatch(stub.channel, stream);
- }
- Future<Bin> getBinByMd5(Uint8List md5, OnPercentage onPercentage)async{
- final stream = _getStub().getBinaryByMd5(pb.GetBinaryByMd5Request()..md5= md5);
- String ext='';
- Uint8List? data;
- var nonce=Uint8List(0);
- var i = 0;
- await for (var one in stream){
- if(data == null){
- data = Uint8List(one.allCount);
- ext = one.ext;
- nonce= Uint8List.fromList(one.nonce);
- }
- for(var b in one.data){
- data[i]=b;
- i++;
- }
- onPercentage(i, data.length);
- }
- await stream.cancel();
- return Bin()
- ..ext=ext
- ..data=data??Uint8List(0)
- ..nonce=nonce;
- }
- Future<void> userHeadEdit(String ext, Uint8List data)async{
- await stub.userHeadEdit(pb.Image()..ext= ext ..data= data);
- }
- Future<pb.MapActivityListReply> mapActivityList(int mapId, String pin)async{
- info('mapActivityList mapId: $mapId pin: $pin');
- final r = await stub.mapActivityList(pb.MapActivityListRequest()
- ..id= mapId
- ..pinCode= pin.trim()
- );
- return r;
- }
- Future<pb.MapActivityListReply> pinCodeActivityList(String pin)async{
- info('pinCodeActivityList pin: $pin');
- final r = await stub.pinCodeActivityList(pb.PinCodeActivityListRequest()
- .. pinCode= pin.trim()
- );
- return r;
- }
- }
- class Bin{
- var ext='';
- var data=Uint8List(0);
- var nonce=Uint8List(0);
- }
- typedef OnPercentage = void Function(int, int);
- class ApiServiceMock extends ApiService {
- @override
- Future<ApiService> init() async {
- debug('$runtimeType ready!');
- return this;
- }
- final random = Random();
- @override
- Future<void> signIn(String name, String password) async {}
- @override
- Future<pb.GameData> gameStart(
- int projectId, fixnum.Int64 mapRouteId) async {
- info('gameStart Mock');
- final data = pb.GameData();
- final p1 = pb.ControlPoint()
- ..id= fixnum.Int64(1)
- ..info = pb.ControlPointInfo();
- final p2 = pb.ControlPoint()..id= fixnum.Int64(2)
- ..info = pb.ControlPointInfo();
- p1.nfcIdList.add('0465be121c1291');
- p2.nfcIdList.add('0465bd121c1291');
- data.controlPointSortedList.addAll([p1, p2]);
- data.mapZip = pb.NetImage()
- ..url=
- 'https://p3.itc.cn/q_70/images03/20210317/94c7636527d042d8a7c9ed08529cc8b2.jpeg'
- ..md5= [1, 1, 1];
- data.maxDuration = pb.Duration()..seconds= fixnum.Int64(60) * 60;
- return data;
- }
- @override
- Future<void> gameSaveUpload(pb.GameSaveUploadRequest save) async {
- return;
- }
- @override
- void onReady() {}
- @override
- void onClose() {}
- @override
- Future<DateTime> serverTime() async {
- return DateTime.now();
- }
- @override
- Future<pb.MapActivityListReply> mapActivityList(int mapId, String pin)async{
- return pb.MapActivityListReply()
- ..list.addAll([
- pb.MapActivitySimpleInfo()
- ..name= '穿越荒野:勇闯野性之旅-穿越荒野:勇闯野性之旅'
- ..difficulty= 1
- ..distanceMinMeter= 217.1
- ..closeDoorTime= 190.minutes.toPb()
- ..isUsed= false
- ..routeCount= 28
- ..totalControlNum= 12
- ,
- pb.MapActivitySimpleInfo()
- ..name= '极限挑战 战胜重力'
- ..difficulty= 2
- ..distanceMinMeter= 8.1
- ..closeDoorTime= 190.minutes.toPb()
- ..isUsed= true
- ..routeCount= 6
- ..totalControlNum= 16
- ,
- ])
- ;
- }
- @override
- Future<pb.ActivityDetailReply> activityDetail(int id) async {
- final simple = pb.MapActivitySimpleInfo()
- ..id= 1
- ..name= '周末爬山健身运动'
- ..closeDoorTime= 90.minutes.toPb()
- ..distanceMinMeter= 71.3;
- return pb.ActivityDetailReply()
- ..baseInfoV2= simple
- ..content= ' 此主题为全民爬山健身定向运动,全民爬山健身运动是我国体育事业发展的重要组成部分,也是实现中华民族伟大复兴中国梦的重要内容。'
- ..routes.addAll([
- pb.MapRoute()
- ..name='XL0002'
- ..distanceMeter= 3331
- ..altitudeDiffMeter= 223
- ..useCount= 0
- ,
- pb.MapRoute()
- ..name= 'XL0003'
- ..distanceMeter= 5430
- ..altitudeDiffMeter= 123
- ..useCount=2
- ,
- ])
- ;
- }
- @override
- Future<List<MapInfo>> mapRecommendList(MPosition? position)async{
- info('mapRecommendList: $position');
- return [
- MapInfo()
- ..name= '英雄山风景区'
- ..isOpen=true
- ..isRecommend=true
- ,
- MapInfo()..name= '板桥广场'
- ..isRecommend=true
- ];
- }
- @override
- Future<List<MapInfo>> mapList(MPosition? position, int offset, int limit)async{
- info('mapList: $position');
- final out = <MapInfo>[];
- for(var i=0;i< limit;i++){
- out.add(MapInfo()
- ..name ='$offset-${random.nextInt(10000)}公园'
- );
- }
- return out;
- }
- @override
- Future<String> getRegionCode() async{
- return 'test';
- }
- @override
- Future<List<pb.Region>> getRegionList() async{
- info('getRegionList');
- return [];
- }
- }
- class StreamGuardianWatch{
- StreamGuardianWatch(
- this.channel,
- this.stream
- );
- ClientChannel channel;
- ResponseStream<pb.PupilInGameWatchReply> stream;
- }
- extension ExtInt64 on fixnum.Int64{
- pb.IdRequest toIdRequest(){
- return pb.IdRequest()
- ..id=this;
- }
- }
- extension ExtNum on num{
- pb.IdRequest toIdRequest(){
- return pb.IdRequest()
- ..id=fixnum.Int64(toInt());
- }
- }
|