Browse Source

project initialization

melon.yin 3 years ago
commit
a41dfd5be7

+ 75 - 0
.gitignore

@@ -0,0 +1,75 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+build/
+
+# Android related
+**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/ephemeral
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3

+ 10 - 0
.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: f4abaa0735eba4dfd8f33f73363911d63931fe03
+  channel: stable
+
+project_type: package

+ 3 - 0
CHANGELOG.md

@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.

+ 1 - 0
LICENSE

@@ -0,0 +1 @@
+TODO: Add your license here.

+ 14 - 0
README.md

@@ -0,0 +1,14 @@
+# fisjsonrpc
+
+A new Flutter package project.
+
+## Getting Started
+
+This project is a starting point for a Dart
+[package](https://flutter.dev/developing-packages/),
+a library module containing code that can be shared easily across
+multiple Flutter or Dart projects.
+
+For help getting started with Flutter, view our 
+[online documentation](https://flutter.dev/docs), which offers tutorials, 
+samples, guidance on mobile development, and a full API reference.

+ 81 - 0
lib/base_model.dart

@@ -0,0 +1,81 @@
+import 'package:fiscommon/json_convert.dart';
+
+class RpcResult<T> {
+  final bool isSuccess;
+  final int errorCode;
+  final String msg;
+  T? data;
+
+  RpcResult({
+    required this.isSuccess,
+    required this.errorCode,
+    required this.msg,
+    this.data,
+  });
+
+  factory RpcResult.fromJson(Map<String, dynamic> map) {
+    T? data;
+    if (map['data'] != null) {
+      data = FJsonConvert.fromJson<T>(map['data']);
+    }
+
+    return RpcResult(
+      isSuccess: map['isSuccess'] == true,
+      errorCode: map['errorCode'],
+      msg: map['msg'],
+      data: data,
+    );
+  }
+}
+
+/// 分页数据
+class PagedData<T> {
+  PagedData({
+    required this.currentPage,
+    required this.pageSize,
+    this.pageData = const [],
+  });
+
+  factory PagedData.fromJson(Map<String, dynamic> map) {
+    List<T> dataList = [];
+    if (map['PageData'] != null) {
+      dataList.addAll(
+          (map['PageData'] as List).map((e) => FJsonConvert.fromJson<T>(e)!));
+    }
+    return PagedData(
+      currentPage: map['CurrentPage'],
+      pageSize: map['PageSize'],
+      pageData: dataList,
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> map = {};
+    map['CurrentPage'] = this.currentPage;
+    map['PageSize'] = this.pageSize;
+    map['PageData'] = this.pageData.map((dynamic e) => e.toJson()).toList();
+    return map;
+  }
+
+  final int currentPage;
+  final int pageSize;
+  final List<T> pageData;
+}
+
+/// 分页请求
+class PagedRequest {
+  PagedRequest({
+    this.currentPage = 1,
+    this.pageSize = 10,
+  });
+
+  int currentPage;
+  int pageSize;
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> map = {};
+    map['currentPage'] = this.currentPage;
+    map['pageSize'] = this.pageSize;
+    return map;
+  }
+}

+ 85 - 0
lib/client_base.dart

@@ -0,0 +1,85 @@
+import 'dart:convert';
+import 'package:dio/dio.dart';
+import 'package:fiscommon/http/options.dart';
+import 'package:flutter/foundation.dart';
+
+import 'exception.dart';
+import 'http_pool.dart';
+import 'request.dart';
+
+/// JSON-RPC Client 基类
+class JsonRpcClientBase {
+  /// 服务主机地址
+  final String host;
+
+  /// 服务名称
+  final String serviceName;
+
+  /// 自定义Http header
+  final Map<String, String>? headers;
+
+  /// 超时时间(ms)
+  final int? timeout;
+
+  /// 服务请求地址
+  String get servicePath =>
+      host.endsWith('/') ? "$host$serviceName" : "$host/$serviceName";
+
+  JsonRpcClientBase(
+    this.host,
+    this.serviceName, {
+    this.headers,
+    this.timeout,
+  });
+
+  /// 请求RPC method
+  @protected
+  Future<dynamic> call(String method, [args]) async {
+    var request = JsonRpcRequest(method, args);
+    return _transmit(request);
+  }
+
+  /// 通知 RPC method
+  @protected
+  void notify(String method, [args]) {
+    var request = JsonRpcRequest(method, args, notify: true);
+    _transmit(request);
+  }
+
+  Future<dynamic> _transmit(JsonRpcRequest request) async {
+    String package = jsonEncode(request.toJson());
+    var response = await _postRequest(package);
+    if (response == null) throw JsonRpcException("Response Empty");
+
+    var result = _handleDecoded(response);
+    return result;
+  }
+
+  Future<dynamic> _postRequest(String package) async {
+    try {
+      final httpClient = jrpcHttpPool.getClient(this.host,
+          timeout: this.timeout, headers: this.headers);
+      var response =
+          await httpClient.post('/${this.serviceName}', data: package);
+      // if (response.statusCode != HttpStatus.ok) {
+      if (response.statusCode != 200) {
+        throw JsonRpcException("Http error", response.statusCode!);
+      }
+      return response.data;
+    } on DioError catch (e) {
+      throw JsonRpcException("Http error", 0, e);
+    }
+  }
+
+  dynamic _handleDecoded(Map<String, dynamic> resp) {
+    if (resp.containsKey('error')) {
+      throw JsonRpcServerError.fromJson(resp['error']);
+    }
+    return resp['result'];
+  }
+}
+
+abstract class JsonRpcRequestModelBase {
+  /// 转成Json Map
+  Map<String, dynamic> toJson();
+}

+ 44 - 0
lib/exception.dart

@@ -0,0 +1,44 @@
+/// JSON-RPC exception
+class JsonRpcException implements Exception {
+  String message;
+  int code;
+  dynamic data;
+
+  JsonRpcException(this.message, [this.code = 0, this.data]);
+
+  @override
+  String toString() {
+    return 'JSON-RPC Exception: $code $message';
+  }
+
+  Map<String, dynamic> toJson() {
+    var map = <String, dynamic>{'code': code, 'message': message};
+    if (data != null) {
+      map['data'] = data;
+    }
+    return map;
+  }
+}
+
+/// JSON-RPC network exception
+class JsonRpcNetworkException extends JsonRpcException {
+  JsonRpcNetworkException(String message, [code = -32000, data])
+      : super(message);
+}
+
+/// JSON-RPC Server Error
+class JsonRpcServerError extends JsonRpcException {
+  JsonRpcServerError(String message, [code = -32000, data])
+      : super(message, code, data);
+  JsonRpcServerError.fromJson(Map<String, dynamic> e) : super('') {
+    if (e.containsKey('message')) {
+      message = e['message'];
+    }
+    if (e.containsKey('code')) {
+      code = e['code'];
+    }
+    if (e.containsKey('data')) {
+      data = e['data'];
+    }
+  }
+}

+ 87 - 0
lib/http_pool.dart

@@ -0,0 +1,87 @@
+import 'dart:async';
+
+import 'package:fiscommon/http/http.dart';
+import 'package:fiscommon/http/options.dart';
+import 'package:dio/dio.dart' as dio;
+
+class _JsonRpcHttpPool {
+  _JsonRpcHttpPool({int limitCount = 2}) {
+    _limitCount = limitCount;
+  }
+
+  static const _TimerInterval = 60 * 1000;
+  static const _LifecycleTime = 60 * 1000;
+
+  Timer? _timer;
+  final Map<int, _ClientState> _pool = {};
+  late int _limitCount;
+  int get limitCount => _limitCount;
+  bool _closed = false;
+  bool _firstCall = true;
+
+  void _handleFirstLoad() {
+    if (!_firstCall) return;
+    _timer =
+        Timer.periodic(const Duration(milliseconds: _TimerInterval), (timer) {
+      final now = DateTime.now();
+      _pool.forEach((key, value) {
+        var secDiff = now.difference(value.lastVisitTime).inSeconds;
+        if (_LifecycleTime < secDiff) {
+          _pool.remove(key);
+        }
+      });
+    });
+
+    _firstCall = false;
+  }
+
+  void close() {
+    if (!_closed) {
+      _closed = true;
+      _timer?.cancel();
+    }
+  }
+
+  /// 设置连接池缓存数
+  void setLimitCount(int count) => _limitCount = count;
+
+  /// 获取客户端实例
+  FHttp getClient(
+    String baseUrl, {
+    int? timeout,
+    Map<String, dynamic>? headers,
+  }) {
+    if (!_pool.containsKey(baseUrl.hashCode)) {
+      // 浏览器跨域限制: Content-Type非简单类型 Fetch前会先发一个Options,Server不支持Options导致Cors
+      // 简单类型:
+      //  - application/x-www-form-urlencoded
+      //  - multipart/form-data
+      //  - text/plain
+      final _client = FHttp(FHttpBaseOptions(
+        baseUrl: baseUrl,
+        timeout: timeout ?? 3 * 1000,
+        headers: headers,
+        contentType: dio.Headers.textPlainContentType,
+        responseType: FHttpResponseType.json,
+      ));
+
+      final _state = _ClientState(_client);
+      _pool[baseUrl.hashCode] = _state;
+      if (_pool.length > limitCount) {
+        _pool.remove(_pool.keys.first); // 删除第一个
+      }
+    }
+    final state = _pool[baseUrl.hashCode]!;
+    state.lastVisitTime = DateTime.now();
+    _handleFirstLoad();
+    return state.client;
+  }
+}
+
+class _ClientState {
+  _ClientState(this.client);
+  final FHttp client;
+  DateTime lastVisitTime = DateTime.now();
+}
+
+final _JsonRpcHttpPool jrpcHttpPool = _JsonRpcHttpPool();

+ 29 - 0
lib/request.dart

@@ -0,0 +1,29 @@
+class JsonRpcRequest {
+  static const String _serverVersion = '2.0';
+
+  final String method;
+  final Object? args;
+  final bool notify;
+
+  int? get id => !this.notify ? this.hashCode : null;
+
+  JsonRpcRequest(this.method, this.args, {this.notify = false});
+
+  Map<String, dynamic> toJson() {
+    var map = <String, dynamic>{};
+    map = {
+      'jsonrpc': _serverVersion,
+      'method': method,
+      'params': (args == null)
+          ? []
+          : (args is List || args is Map)
+              ? args
+              : [args]
+    };
+    if (!notify) map['id'] = id;
+    return map;
+  }
+
+  @override
+  String toString() => 'JsonRpcRequest: ${toJson()}';
+}

+ 81 - 0
lib/rpc.dart

@@ -0,0 +1,81 @@
+library fisjsonrpc;
+
+import 'dart:collection';
+
+import 'package:fiscommon/extensions/type.dart';
+
+import 'client_base.dart';
+import 'services/index.dart';
+
+export 'services/index.dart';
+
+typedef T ServiceBuilder<T extends JsonRpcClientBase>();
+
+/// 默认地址标识
+const String _defaultAddressSign = "FLYINSONO";
+
+/// JSON-RPC 代理
+class JsonRpcProxy {
+  JsonRpcProxy({
+    this.defaultServerHost = "cloud.fis.plus",
+    this.platformHost = "platform.fis.plus",
+  }) {
+    _currentHost = this.defaultServerHost;
+  }
+
+  /// 默认主机地址
+  final String defaultServerHost;
+
+  /// 宿主平台代理地址
+  final String platformHost;
+
+  late String _currentHost;
+
+  /// 当前服务主机地址
+  String get currentHostAddress => "http://$_currentHost";
+
+  String get defaultAddressSign => _defaultAddressSign;
+
+  HashMap<Type, dynamic> _serviceCache = HashMap();
+
+  static PlatformService? _platformService;
+
+  /* 服务代理设置 Start */
+
+  /// 平台服务
+  PlatformService get platform {
+    if (_platformService == null)
+      _platformService = PlatformService(platformHost);
+    return _platformService!;
+  }
+
+  /// 登录服务
+  LoginService get login =>
+      findService(() => new LoginService(currentHostAddress));
+
+  /// 诊断服务
+  RemedicalService get remedical =>
+      findService(() => new RemedicalService(currentHostAddress));
+
+  /* 服务代理设置 End */
+
+  /// 设置服务主机地址
+  void setServerHost(String address) {
+    if (address == _defaultAddressSign) {
+      address = defaultServerHost;
+    }
+    _currentHost = address;
+  }
+
+  /// 清空缓存
+  void clearCache() => _serviceCache.clear();
+
+  /// 查找Service实例
+  T findService<T extends JsonRpcClientBase>(ServiceBuilder<T> builder) {
+    Type serviceType = typeOf<T>();
+    if (!_serviceCache.containsKey(serviceType)) {
+      _serviceCache[serviceType] = builder.call();
+    }
+    return _serviceCache[serviceType] as T;
+  }
+}

+ 6 - 0
lib/services/index.dart

@@ -0,0 +1,6 @@
+export 'login.dart';
+export 'login.m.dart';
+export 'platform.dart';
+export 'platform.m.dart';
+export 'remedical.dart';
+export 'remedical.m.dart';

+ 32 - 0
lib/services/login.dart

@@ -0,0 +1,32 @@
+import 'dart:core';
+
+import 'package:fiscommon/json_convert.dart';
+import 'package:fisjsonrpc/base_model.dart';
+import 'package:fisjsonrpc/client_base.dart';
+import 'login.m.dart';
+
+/// 登录服务
+class LoginService extends JsonRpcClientBase {
+  LoginService(
+    String host, {
+    String serviceName = "ILoginService",
+    Map<String, String>? headers,
+    int? timeout,
+  }) : super(
+          host,
+          serviceName,
+          headers: headers,
+          timeout: timeout,
+        ) {
+    /// 注册响应实体反序列化处理器
+    FJsonConvert.setDecoder((map) => LoginResult.fromJson(map));
+  }
+
+  /// 登录
+  Future<RpcResult<LoginResult>> clientLoginAsync(LoginRequest request) async {
+    var rpcRst = await call("ClientLoginAsync", request);
+    var result =
+        RpcResult<LoginResult>.fromJson(rpcRst as Map<String, dynamic>);
+    return result;
+  }
+}

+ 93 - 0
lib/services/login.m.dart

@@ -0,0 +1,93 @@
+enum LoginType {
+  UserNameAndPwd,
+  MobileNumber,
+}
+
+enum RegisterType {
+  MobileNumber,
+  Email,
+}
+
+class LoginRequest {
+  final LoginType loginType;
+  final ProcessorInfo processorInfo;
+  final ClientInfo? clientInfo;
+
+  LoginRequest({
+    required this.loginType,
+    required this.processorInfo,
+    this.clientInfo,
+  });
+
+  Map<String, dynamic> toJson() {
+    final map = Map<String, dynamic>();
+    map['loginType'] = loginType.index;
+    map['processorInfo'] = processorInfo;
+    if (clientInfo != null) map['clientInfo'] = clientInfo;
+    return map;
+  }
+}
+
+class ProcessorInfo {
+  final String? userName;
+  final String? password;
+
+  ProcessorInfo({
+    this.userName,
+    this.password,
+  });
+
+  factory ProcessorInfo.fromJson(Map<String, dynamic> map) {
+    return ProcessorInfo(
+      userName: map['userName'],
+      password: map['password'],
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    final map = Map<String, dynamic>();
+    if (userName != null && userName!.isNotEmpty) map['userName'] = userName;
+    if (password != null && password!.isNotEmpty) map['password'] = password;
+    return map;
+  }
+}
+
+class ClientInfo {
+  final String? clientSource;
+
+  ClientInfo({
+    this.clientSource,
+  });
+
+  factory ClientInfo.fromJson(Map<String, dynamic> map) {
+    return ClientInfo(
+      clientSource: map['clientSource'],
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    final map = Map<String, dynamic>();
+    if (clientSource != null && clientSource!.isNotEmpty)
+      map['clientSource'] = clientSource;
+    return map;
+  }
+}
+
+class LoginResult {
+  final String userId;
+  final String sessionId;
+  final String? deviceId;
+  LoginResult({
+    required this.userId,
+    required this.sessionId,
+    this.deviceId,
+  });
+
+  factory LoginResult.fromJson(Map<String, dynamic> map) {
+    return LoginResult(
+      userId: map['userId'],
+      sessionId: map['sessionId'],
+      deviceId: map['deviceId'],
+    );
+  }
+}

+ 22 - 0
lib/services/platform.dart

@@ -0,0 +1,22 @@
+import 'package:fisjsonrpc/client_base.dart';
+
+/// 平台服务
+class PlatformService extends JsonRpcClientBase {
+  PlatformService(
+    String host, {
+    String serviceName = "IPlatformService",
+    Map<String, String>? headers,
+    int? timeout,
+  }) : super(
+          host,
+          serviceName,
+          headers: headers,
+          timeout: timeout,
+        );
+
+  /// 加载主题
+  Future<bool> loadTheme(String name) async {
+    var rpcRst = await call("loadTheme", name);
+    return rpcRst == true;
+  }
+}

+ 1 - 0
lib/services/platform.m.dart

@@ -0,0 +1 @@
+

+ 35 - 0
lib/services/remedical.dart

@@ -0,0 +1,35 @@
+import 'dart:core';
+
+import 'package:fiscommon/json_convert.dart';
+import 'package:fisjsonrpc/base_model.dart';
+import 'package:fisjsonrpc/client_base.dart';
+
+import 'remedical.m.dart';
+
+/// 诊断服务
+class RemedicalService extends JsonRpcClientBase {
+  RemedicalService(
+    String host, {
+    String serviceName = "IRemedicalService",
+    Map<String, String>? headers,
+    int? timeout,
+  }) : super(
+          host,
+          serviceName,
+          headers: headers,
+          timeout: timeout,
+        ) {
+    /// 注册响应实体反序列化处理器
+    FJsonConvert.setDecoder((map) => RemedicalModel.fromJson(map));
+    FJsonConvert.setDecoder((map) => PagedData<RemedicalModel>.fromJson(map));
+  }
+
+  /// 获取诊断分页列表
+  Future<RpcResult<PagedData<RemedicalModel>>> getRemedicalPageAsync(
+      RemedicalQueryRequest request) async {
+    var rpcRst = await call("GetRemedicalPageAsync", request);
+    var result = RpcResult<PagedData<RemedicalModel>>.fromJson(
+        rpcRst as Map<String, dynamic>);
+    return result;
+  }
+}

+ 123 - 0
lib/services/remedical.m.dart

@@ -0,0 +1,123 @@
+import 'package:fisjsonrpc/base_model.dart';
+
+class RemedicalFilterModel {
+  RemedicalFilterModel({
+    this.recordId,
+  });
+
+  String? recordId;
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> map = {};
+    if (this.recordId != null) map['RecordId'] = this.recordId;
+    return map;
+  }
+}
+
+class RemedicalQueryRequest extends PagedRequest {
+  RemedicalQueryRequest({
+    int currentPage = 1,
+    int pageSize = 10,
+    this.filter = const {},
+    this.modelFilter,
+  }) : super();
+
+  final Map<String, String> filter;
+  RemedicalFilterModel? modelFilter;
+
+  @override
+  Map<String, dynamic> toJson() {
+    var map = super.toJson();
+    map['filter'] = this.filter;
+    if (this.modelFilter != null)
+      map['modelFilter'] = this.modelFilter!.toJson();
+    return map;
+  }
+
+  factory RemedicalQueryRequest.fromJson(Map<String, dynamic> map) {
+    return RemedicalQueryRequest(
+      currentPage: map['currentPage'],
+      pageSize: map['pageSize'],
+      filter: map['filter'],
+    );
+  }
+}
+
+class RemedicalModel {
+  RemedicalModel({
+    required this.id,
+    required this.createTime,
+    required this.recordId,
+    required this.patientName,
+    required this.idCardNo,
+    required this.birthday,
+    required this.genderType,
+    this.sourceOrg,
+    this.terminalImages = const [],
+  });
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> map = {};
+    map['id'] = this.id;
+    map['createTime'] = this.createTime;
+    map['recordId'] = this.recordId;
+    map['patientName'] = this.patientName;
+    map['idCardNo'] = this.idCardNo;
+    map['birthday'] = this.birthday;
+    map['genderType'] = this.genderType;
+    map['terminalImages'] = this.terminalImages.map((e) => e.toJson()).toList();
+    return map;
+  }
+
+  factory RemedicalModel.fromJson(Map<String, dynamic> map) {
+    final imgsData = map['TerminalImages'];
+    return RemedicalModel(
+      id: map['Id'],
+      createTime: map['CreateTime'],
+      recordId: map['RecordId'],
+      patientName: map['PatientName'],
+      idCardNo: map['IdCardNo'],
+      birthday: map['Birthday'],
+      genderType: map['GenderType'],
+      sourceOrg: map['SourceOrg'],
+      terminalImages: imgsData != null
+          ? (imgsData as List)
+              .map((e) => RemedicalTerminalImageModel.fromJson(e))
+              .toList()
+          : const [],
+    );
+  }
+
+  final String id;
+  final String createTime;
+  final String recordId;
+  final String patientName;
+  final String idCardNo;
+  final String birthday;
+  final int genderType;
+  final String? sourceOrg;
+  final List<RemedicalTerminalImageModel> terminalImages;
+}
+
+class RemedicalTerminalImageModel {
+  RemedicalTerminalImageModel({
+    required this.previewUrl,
+    required this.imageUrl,
+  });
+  factory RemedicalTerminalImageModel.fromJson(Map<String, dynamic> map) {
+    return RemedicalTerminalImageModel(
+      imageUrl: map['ImageUrl'],
+      previewUrl: map['PreviewUrl'],
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> map = {};
+    map['previewUrl'] = this.previewUrl;
+    map['imageUrl'] = this.imageUrl;
+    return map;
+  }
+
+  final String previewUrl;
+  final String imageUrl;
+}

+ 289 - 0
pubspec.lock

@@ -0,0 +1,289 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  async:
+    dependency: transitive
+    description:
+      name: async
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.6.1"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  charcode:
+    dependency: transitive
+    description:
+      name: charcode
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.15.0"
+  dio:
+    dependency: transitive
+    description:
+      name: dio
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.0.0"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.2"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.1.2"
+  fiscommon:
+    dependency: "direct main"
+    description:
+      path: "."
+      ref: HEAD
+      resolved-ref: "62cfa3bc0011892328863d4c7fc44d67be405027"
+      url: "http://git.ius.plus:88/Flyinsono-Packages/fis-common.git"
+    source: git
+    version: "0.0.1"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.13.3"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.0.0"
+  intl:
+    dependency: transitive
+    description:
+      name: intl
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.17.0"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.6.3"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.10"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.8.0"
+  path_provider:
+    dependency: transitive
+    description:
+      name: path_provider
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.4"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  path_provider_macos:
+    dependency: transitive
+    description:
+      name: path_provider_macos
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.2"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.1"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.3"
+  pedantic:
+    dependency: transitive
+    description:
+      name: pedantic
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.11.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.2"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.1"
+  process:
+    dependency: transitive
+    description:
+      name: process
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.2.3"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.8.1"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.10.0"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  synchronized:
+    dependency: transitive
+    description:
+      name: synchronized
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.3.0"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.9"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.2.0"
+sdks:
+  dart: ">=2.13.0 <3.0.0"
+  flutter: ">=2.0.0"

+ 60 - 0
pubspec.yaml

@@ -0,0 +1,60 @@
+name: fisjsonrpc
+description: Flyinsono app json-rpc client package project.
+version: 0.0.1
+homepage:
+
+# add this line for pathing dependency
+publish_to: none
+
+environment:
+  sdk: ">=2.12.0 <3.0.0"
+  flutter: ">=1.17.0"
+
+dependencies:
+  flutter:
+    sdk: flutter
+
+  fiscommon:
+      git:
+        url: http://git.ius.plus:88/Flyinsono-Packages/fis-common.git
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter.
+flutter:
+
+  # To add assets to your package, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+  #
+  # For details regarding assets in packages, see
+  # https://flutter.dev/assets-and-images/#from-packages
+  #
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/assets-and-images/#resolution-aware.
+
+  # To add custom fonts to your package, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts in packages, see
+  # https://flutter.dev/custom-fonts/#from-packages

+ 5 - 0
test/fisjsonrpc_test.dart

@@ -0,0 +1,5 @@
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  test('adds one to input values', () {});
+}