Przeglądaj źródła

hotconi 自动登录

数据抓不到, 使用protobuf做RPC调用,逆向出来的文件无法截取数据。
xiao.qiang 11 miesięcy temu
rodzic
commit
408cf3238b

+ 8 - 7
client/api.js

@@ -1,3 +1,4 @@
+
 class Api {
 
     /**
@@ -16,13 +17,13 @@ class Api {
             'languageType': 1,
         }
             , b = {
-                'symbolId': 'EOSUSDT_UMCBL',
-                'tokenId': 'USDT',
-                'afterLeverage': 19,
-                'businessLine': 10,
-                'batchMark': 0,
-                'secondBusinessLine': 'N/A',
-                'languageType': 1,
+            'symbolId': 'EOSUSDT_UMCBL',
+            'tokenId': 'USDT',
+            'afterLeverage': 19,
+            'businessLine': 10,
+            'batchMark': 0,
+            'secondBusinessLine': 'N/A',
+            'languageType': 1,
         }, c = {
             'symbolId': 'EOSUSDT_UMCBL',
             'tokenId': 'USDT',

+ 0 - 3
client/binance.test.js

@@ -4,9 +4,6 @@ const {
     expect,
 } = require('@jest/globals')
 const { WebDriver } = require('../common/web_driver')
-const { inflate } = require('pako')
-
-const { cookieToJSON } = require('../common/utils')
 
 const timeout = 9999999
 

Plik diff jest za duży
+ 17 - 6
client/hotcoin.test.js


+ 285 - 0
client/hotconi.proto.js

@@ -0,0 +1,285 @@
+// JSON descriptor
+//提示词: 通过这个json 结构给我生成一个 protobufjs使用的   JSON descriptors
+
+//通用返回值结构。
+const common = {
+    'nested': {
+        'Response': {
+            'fields': {
+                'code': {
+                    'type': 'int32',
+                    'id': 1,
+                },
+                'msg': {
+                    'type': 'string',
+                    'id': 2,
+                },
+                'status': {
+                    'type': 'string',
+                    'id': 3,
+                },
+                'ts': {
+                    'type': 'int64',
+                    'id': 4,
+                },
+                'ch': {
+                    'type': 'string',
+                    'id': 5,
+                },
+            },
+        },
+    },
+}
+
+//market.v2.trade.recommend.pair
+const market_v2_trade_recommend_pair = {
+    'nested': {
+        'Response': {  // 把 Response 放在最外层
+            'fields': {
+                'code': {
+                    'type': 'int32',
+                    'id': 1
+                },
+                'msg': {
+                    'type': 'string',
+                    'id': 2
+                },
+                'status': {
+                    'type': 'string',
+                    'id': 3
+                },
+                'ts': {
+                    'type': 'int64',
+                    'id': 4
+                },
+                'ch': {
+                    'type': 'string',
+                    'id': 5
+                },
+                'recommendpair': {
+                    'type': 'RecommendPair',
+                    'id': 6
+                }
+            }
+        },
+        'RecommendPair': {  // 定义内部消息类型
+            'nested': {  // 新增 nested 层
+                'TradePair': {  // 把 TradePair 定义移到 RecommendPair 内部
+                    'fields': {
+                        'tradeId': {
+                            'type': 'int64',
+                            'id': 1
+                        },
+                        'cny': {
+                            'type': 'string',
+                            'id': 2
+                        },
+                        'totalamount': {
+                            'type': 'string',
+                            'id': 3
+                        },
+                        'last': {
+                            'type': 'string',
+                            'id': 4
+                        },
+                        'volume': {
+                            'type': 'string',
+                            'id': 5
+                        },
+                        'change': {
+                            'type': 'string',
+                            'id': 6
+                        }
+                    }
+                }
+            },
+            'fields': {
+                'listList': {
+                    'rule': 'repeated',
+                    'type': 'TradePair',
+                    'id': 1
+                }
+            }
+        }
+    }
+};
+
+const market_v2_trade_area_tickers = {
+    'nested': {
+        'TradeAreaPair': {
+            'fields': {
+                'listList': {
+                    'rule': 'repeated',
+                    'type': 'TradePair',
+                    'id': 1,
+                    'default': [],  // 添加默认值
+                },
+            },
+        },
+        'TradePair': {
+            'fields': {
+                'tradeid': {
+                    'type': 'int64',
+                    'id': 1,
+                },
+                'cny': {
+                    'type': 'double',
+                    'id': 2,
+                },
+                'buy': {
+                    'type': 'double',
+                    'id': 3,
+                },
+                'lever': {
+                    'type': 'int64',
+                    'id': 4,
+                },
+                'sell': {
+                    'type': 'double',
+                    'id': 5,
+                },
+                'last': {
+                    'type': 'double',
+                    'id': 6,
+                },
+                'volume': {
+                    'type': 'double',
+                    'id': 7,
+                },
+                'change': {
+                    'type': 'double',
+                    'id': 8,
+                },
+                'high': {
+                    'type': 'double',
+                    'id': 9,
+                },
+                'low': {
+                    'type': 'double',
+                    'id': 10,
+                },
+                'isopen': {
+                    'type': 'int64',
+                    'id': 11,
+                },
+                'open': {
+                    'type': 'int64',
+                    'id': 12,
+                },
+                'amount': {
+                    'type': 'double',
+                    'id': 13,
+                },
+                'isfiatconvert': {
+                    'type': 'bool',
+                    'id': 14,
+                },
+            },
+        },
+        'Response': {
+            'fields': {
+                'code': {
+                    'type': 'int32',
+                    'id': 1,
+                },
+                'msg': {
+                    'type': 'string',
+                    'id': 2,
+                },
+                'status': {
+                    'type': 'string',
+                    'id': 3,
+                },
+                'ts': {
+                    'type': 'int64',
+                    'id': 4,
+                },
+                'ch': {
+                    'type': 'string',
+                    'id': 5,
+                },
+                'tradeareapair': {
+                    'type': 'TradeAreaPair',
+                    'id': 6,
+                },
+            },
+        },
+    },
+}
+
+const market_v2_trade_main_pair = {
+    'nested': {
+        'MainPair': {
+            'fields': {
+                'listList': {
+                    'rule': 'repeated',
+                    'type': 'Trade',
+                    'id': 1,
+                    'default': [],  // 添加默认值
+                },
+            },
+        },
+        'Trade': {
+            'fields': {
+                'tradeId': {
+                    'type': 'int64',
+                    'id': 1,
+                },
+                'cny': {
+                    'type': 'double',
+                    'id': 2,
+                },
+                'totalamount': {
+                    'type': 'double',
+                    'id': 3,
+                },
+                'last': {
+                    'type': 'double',
+                    'id': 4,
+                },
+                'volume': {
+                    'type': 'double',
+                    'id': 5,
+                },
+                'change': {
+                    'type': 'double',
+                    'id': 6,
+                },
+            },
+        },
+        'Response': {
+            'fields': {
+                'code': {
+                    'type': 'int32',
+                    'id': 1,
+                },
+                'msg': {
+                    'type': 'string',
+                    'id': 2,
+                },
+                'status': {
+                    'type': 'string',
+                    'id': 3,
+                },
+                'ts': {
+                    'type': 'int64',
+                    'id': 4,
+                },
+                'ch': {
+                    'type': 'string',
+                    'id': 5,
+                },
+                'mainpair': {
+                    'type': 'MainPair',
+                    'id': 6,
+                },
+            },
+        },
+    },
+}
+module.exports = {
+    common,
+    market_v2_trade_recommend_pair,
+    market_v2_trade_area_tickers,
+    market_v2_trade_main_pair,
+}

+ 12 - 0
client/hotconi/proto/01.pbjs.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+
+pbjs=../../../node_modules/protobufjs-cli/bin/pbjs
+
+export PATH=$PATH:$pbjs
+pbjs  -h
+pbjs -t static-module -w commonjs  market.v2.trade.area.tickers.proto  > market.v2.trade.area.tickers.js
+pbjs -t static-module -w commonjs   market.v2.trade.main.pair.proto  > market.v2.trade.main.pair.js
+pbjs -t static-module -w commonjs   market.v2.trade.recommend.pair.proto  > market.v2.trade.recommend.pair.js
+pbjs -t json market.v2.trade.area.tickers.proto  > market.v2.trade.area.tickers.json
+pbjs -t json market.v2.trade.main.pair.proto  > market.v2.trade.main.pair.json
+pbjs -t json market.v2.trade.recommend.pair.proto  > market.v2.trade.recommend.pair.json

+ 1137 - 0
client/hotconi/proto/market.v2.trade.area.tickers.js

@@ -0,0 +1,1137 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("protobufjs/minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
+
+$root.market = (function() {
+
+    /**
+     * Namespace market.
+     * @exports market
+     * @namespace
+     */
+    var market = {};
+
+    market.v2 = (function() {
+
+        /**
+         * Namespace v2.
+         * @memberof market
+         * @namespace
+         */
+        var v2 = {};
+
+        v2.trade = (function() {
+
+            /**
+             * Namespace trade.
+             * @memberof market.v2
+             * @namespace
+             */
+            var trade = {};
+
+            trade.area = (function() {
+
+                /**
+                 * Namespace area.
+                 * @memberof market.v2.trade
+                 * @namespace
+                 */
+                var area = {};
+
+                area.tickers = (function() {
+
+                    /**
+                     * Namespace tickers.
+                     * @memberof market.v2.trade.area
+                     * @namespace
+                     */
+                    var tickers = {};
+
+                    tickers.Response = (function() {
+
+                        /**
+                         * Properties of a Response.
+                         * @memberof market.v2.trade.area.tickers
+                         * @interface IResponse
+                         * @property {number|null} [code] Response code
+                         * @property {string|null} [msg] Response msg
+                         * @property {string|null} [status] Response status
+                         * @property {number|Long|null} [ts] Response ts
+                         * @property {string|null} [ch] Response ch
+                         * @property {market.v2.trade.area.tickers.ITradeAreaPair|null} [tradeareapair] Response tradeareapair
+                         */
+
+                        /**
+                         * Constructs a new Response.
+                         * @memberof market.v2.trade.area.tickers
+                         * @classdesc Represents a Response.
+                         * @implements IResponse
+                         * @constructor
+                         * @param {market.v2.trade.area.tickers.IResponse=} [properties] Properties to set
+                         */
+                        function Response(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * Response code.
+                         * @member {number} code
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.code = 0;
+
+                        /**
+                         * Response msg.
+                         * @member {string} msg
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.msg = "";
+
+                        /**
+                         * Response status.
+                         * @member {string} status
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.status = "";
+
+                        /**
+                         * Response ts.
+                         * @member {number|Long} ts
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+                        /**
+                         * Response ch.
+                         * @member {string} ch
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.ch = "";
+
+                        /**
+                         * Response tradeareapair.
+                         * @member {market.v2.trade.area.tickers.ITradeAreaPair|null|undefined} tradeareapair
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         */
+                        Response.prototype.tradeareapair = null;
+
+                        /**
+                         * Creates a new Response instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {market.v2.trade.area.tickers.IResponse=} [properties] Properties to set
+                         * @returns {market.v2.trade.area.tickers.Response} Response instance
+                         */
+                        Response.create = function create(properties) {
+                            return new Response(properties);
+                        };
+
+                        /**
+                         * Encodes the specified Response message. Does not implicitly {@link market.v2.trade.area.tickers.Response.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {market.v2.trade.area.tickers.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.code != null && Object.hasOwnProperty.call(message, "code"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.code);
+                            if (message.msg != null && Object.hasOwnProperty.call(message, "msg"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.msg);
+                            if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.status);
+                            if (message.ts != null && Object.hasOwnProperty.call(message, "ts"))
+                                writer.uint32(/* id 4, wireType 0 =*/32).int64(message.ts);
+                            if (message.ch != null && Object.hasOwnProperty.call(message, "ch"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.ch);
+                            if (message.tradeareapair != null && Object.hasOwnProperty.call(message, "tradeareapair"))
+                                $root.market.v2.trade.area.tickers.TradeAreaPair.encode(message.tradeareapair, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified Response message, length delimited. Does not implicitly {@link market.v2.trade.area.tickers.Response.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {market.v2.trade.area.tickers.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.area.tickers.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.area.tickers.Response();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.code = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.msg = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.status = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.ts = reader.int64();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.ch = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.tradeareapair = $root.market.v2.trade.area.tickers.TradeAreaPair.decode(reader, reader.uint32());
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.area.tickers.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a Response message.
+                         * @function verify
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        Response.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                if (!$util.isInteger(message.code))
+                                    return "code: integer expected";
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                if (!$util.isString(message.msg))
+                                    return "msg: string expected";
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                if (!$util.isString(message.status))
+                                    return "status: string expected";
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))
+                                    return "ts: integer|Long expected";
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                if (!$util.isString(message.ch))
+                                    return "ch: string expected";
+                            if (message.tradeareapair != null && message.hasOwnProperty("tradeareapair")) {
+                                var error = $root.market.v2.trade.area.tickers.TradeAreaPair.verify(message.tradeareapair);
+                                if (error)
+                                    return "tradeareapair." + error;
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a Response message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.area.tickers.Response} Response
+                         */
+                        Response.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.area.tickers.Response)
+                                return object;
+                            var message = new $root.market.v2.trade.area.tickers.Response();
+                            if (object.code != null)
+                                message.code = object.code | 0;
+                            if (object.msg != null)
+                                message.msg = String(object.msg);
+                            if (object.status != null)
+                                message.status = String(object.status);
+                            if (object.ts != null)
+                                if ($util.Long)
+                                    (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;
+                                else if (typeof object.ts === "string")
+                                    message.ts = parseInt(object.ts, 10);
+                                else if (typeof object.ts === "number")
+                                    message.ts = object.ts;
+                                else if (typeof object.ts === "object")
+                                    message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();
+                            if (object.ch != null)
+                                message.ch = String(object.ch);
+                            if (object.tradeareapair != null) {
+                                if (typeof object.tradeareapair !== "object")
+                                    throw TypeError(".market.v2.trade.area.tickers.Response.tradeareapair: object expected");
+                                message.tradeareapair = $root.market.v2.trade.area.tickers.TradeAreaPair.fromObject(object.tradeareapair);
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a Response message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {market.v2.trade.area.tickers.Response} message Response
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        Response.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.code = 0;
+                                object.msg = "";
+                                object.status = "";
+                                if ($util.Long) {
+                                    var long = new $util.Long(0, 0, false);
+                                    object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                                } else
+                                    object.ts = options.longs === String ? "0" : 0;
+                                object.ch = "";
+                                object.tradeareapair = null;
+                            }
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                object.code = message.code;
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                object.msg = message.msg;
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                object.status = message.status;
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (typeof message.ts === "number")
+                                    object.ts = options.longs === String ? String(message.ts) : message.ts;
+                                else
+                                    object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                object.ch = message.ch;
+                            if (message.tradeareapair != null && message.hasOwnProperty("tradeareapair"))
+                                object.tradeareapair = $root.market.v2.trade.area.tickers.TradeAreaPair.toObject(message.tradeareapair, options);
+                            return object;
+                        };
+
+                        /**
+                         * Converts this Response to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        Response.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for Response
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.area.tickers.Response
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        Response.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.area.tickers.Response";
+                        };
+
+                        return Response;
+                    })();
+
+                    tickers.TradeAreaPair = (function() {
+
+                        /**
+                         * Properties of a TradeAreaPair.
+                         * @memberof market.v2.trade.area.tickers
+                         * @interface ITradeAreaPair
+                         * @property {Array.<market.v2.trade.area.tickers.ITradeArea>|null} [tradeidList] TradeAreaPair tradeidList
+                         */
+
+                        /**
+                         * Constructs a new TradeAreaPair.
+                         * @memberof market.v2.trade.area.tickers
+                         * @classdesc Represents a TradeAreaPair.
+                         * @implements ITradeAreaPair
+                         * @constructor
+                         * @param {market.v2.trade.area.tickers.ITradeAreaPair=} [properties] Properties to set
+                         */
+                        function TradeAreaPair(properties) {
+                            this.tradeidList = [];
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * TradeAreaPair tradeidList.
+                         * @member {Array.<market.v2.trade.area.tickers.ITradeArea>} tradeidList
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @instance
+                         */
+                        TradeAreaPair.prototype.tradeidList = $util.emptyArray;
+
+                        /**
+                         * Creates a new TradeAreaPair instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeAreaPair=} [properties] Properties to set
+                         * @returns {market.v2.trade.area.tickers.TradeAreaPair} TradeAreaPair instance
+                         */
+                        TradeAreaPair.create = function create(properties) {
+                            return new TradeAreaPair(properties);
+                        };
+
+                        /**
+                         * Encodes the specified TradeAreaPair message. Does not implicitly {@link market.v2.trade.area.tickers.TradeAreaPair.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeAreaPair} message TradeAreaPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        TradeAreaPair.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.tradeidList != null && message.tradeidList.length)
+                                for (var i = 0; i < message.tradeidList.length; ++i)
+                                    $root.market.v2.trade.area.tickers.TradeArea.encode(message.tradeidList[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified TradeAreaPair message, length delimited. Does not implicitly {@link market.v2.trade.area.tickers.TradeAreaPair.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeAreaPair} message TradeAreaPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        TradeAreaPair.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a TradeAreaPair message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.area.tickers.TradeAreaPair} TradeAreaPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        TradeAreaPair.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.area.tickers.TradeAreaPair();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        if (!(message.tradeidList && message.tradeidList.length))
+                                            message.tradeidList = [];
+                                        message.tradeidList.push($root.market.v2.trade.area.tickers.TradeArea.decode(reader, reader.uint32()));
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a TradeAreaPair message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.area.tickers.TradeAreaPair} TradeAreaPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        TradeAreaPair.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a TradeAreaPair message.
+                         * @function verify
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        TradeAreaPair.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.tradeidList != null && message.hasOwnProperty("tradeidList")) {
+                                if (!Array.isArray(message.tradeidList))
+                                    return "tradeidList: array expected";
+                                for (var i = 0; i < message.tradeidList.length; ++i) {
+                                    var error = $root.market.v2.trade.area.tickers.TradeArea.verify(message.tradeidList[i]);
+                                    if (error)
+                                        return "tradeidList." + error;
+                                }
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a TradeAreaPair message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.area.tickers.TradeAreaPair} TradeAreaPair
+                         */
+                        TradeAreaPair.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.area.tickers.TradeAreaPair)
+                                return object;
+                            var message = new $root.market.v2.trade.area.tickers.TradeAreaPair();
+                            if (object.tradeidList) {
+                                if (!Array.isArray(object.tradeidList))
+                                    throw TypeError(".market.v2.trade.area.tickers.TradeAreaPair.tradeidList: array expected");
+                                message.tradeidList = [];
+                                for (var i = 0; i < object.tradeidList.length; ++i) {
+                                    if (typeof object.tradeidList[i] !== "object")
+                                        throw TypeError(".market.v2.trade.area.tickers.TradeAreaPair.tradeidList: object expected");
+                                    message.tradeidList[i] = $root.market.v2.trade.area.tickers.TradeArea.fromObject(object.tradeidList[i]);
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a TradeAreaPair message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {market.v2.trade.area.tickers.TradeAreaPair} message TradeAreaPair
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        TradeAreaPair.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.arrays || options.defaults)
+                                object.tradeidList = [];
+                            if (message.tradeidList && message.tradeidList.length) {
+                                object.tradeidList = [];
+                                for (var j = 0; j < message.tradeidList.length; ++j)
+                                    object.tradeidList[j] = $root.market.v2.trade.area.tickers.TradeArea.toObject(message.tradeidList[j], options);
+                            }
+                            return object;
+                        };
+
+                        /**
+                         * Converts this TradeAreaPair to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        TradeAreaPair.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for TradeAreaPair
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.area.tickers.TradeAreaPair
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        TradeAreaPair.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.area.tickers.TradeAreaPair";
+                        };
+
+                        return TradeAreaPair;
+                    })();
+
+                    tickers.TradeArea = (function() {
+
+                        /**
+                         * Properties of a TradeArea.
+                         * @memberof market.v2.trade.area.tickers
+                         * @interface ITradeArea
+                         * @property {number|null} [tradeid] TradeArea tradeid
+                         * @property {string|null} [cny] TradeArea cny
+                         * @property {string|null} [buy] TradeArea buy
+                         * @property {string|null} [lever] TradeArea lever
+                         * @property {string|null} [sell] TradeArea sell
+                         * @property {string|null} [last] TradeArea last
+                         * @property {string|null} [volume] TradeArea volume
+                         * @property {string|null} [change] TradeArea change
+                         * @property {string|null} [high] TradeArea high
+                         * @property {string|null} [low] TradeArea low
+                         * @property {string|null} [isopen] TradeArea isopen
+                         * @property {number|null} [open] TradeArea open
+                         * @property {string|null} [amount] TradeArea amount
+                         * @property {boolean|null} [isfiatconvert] TradeArea isfiatconvert
+                         */
+
+                        /**
+                         * Constructs a new TradeArea.
+                         * @memberof market.v2.trade.area.tickers
+                         * @classdesc Represents a TradeArea.
+                         * @implements ITradeArea
+                         * @constructor
+                         * @param {market.v2.trade.area.tickers.ITradeArea=} [properties] Properties to set
+                         */
+                        function TradeArea(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * TradeArea tradeid.
+                         * @member {number} tradeid
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.tradeid = 0;
+
+                        /**
+                         * TradeArea cny.
+                         * @member {string} cny
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.cny = "";
+
+                        /**
+                         * TradeArea buy.
+                         * @member {string} buy
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.buy = "";
+
+                        /**
+                         * TradeArea lever.
+                         * @member {string} lever
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.lever = "";
+
+                        /**
+                         * TradeArea sell.
+                         * @member {string} sell
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.sell = "";
+
+                        /**
+                         * TradeArea last.
+                         * @member {string} last
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.last = "";
+
+                        /**
+                         * TradeArea volume.
+                         * @member {string} volume
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.volume = "";
+
+                        /**
+                         * TradeArea change.
+                         * @member {string} change
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.change = "";
+
+                        /**
+                         * TradeArea high.
+                         * @member {string} high
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.high = "";
+
+                        /**
+                         * TradeArea low.
+                         * @member {string} low
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.low = "";
+
+                        /**
+                         * TradeArea isopen.
+                         * @member {string} isopen
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.isopen = "";
+
+                        /**
+                         * TradeArea open.
+                         * @member {number} open
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.open = 0;
+
+                        /**
+                         * TradeArea amount.
+                         * @member {string} amount
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.amount = "";
+
+                        /**
+                         * TradeArea isfiatconvert.
+                         * @member {boolean} isfiatconvert
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         */
+                        TradeArea.prototype.isfiatconvert = false;
+
+                        /**
+                         * Creates a new TradeArea instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeArea=} [properties] Properties to set
+                         * @returns {market.v2.trade.area.tickers.TradeArea} TradeArea instance
+                         */
+                        TradeArea.create = function create(properties) {
+                            return new TradeArea(properties);
+                        };
+
+                        /**
+                         * Encodes the specified TradeArea message. Does not implicitly {@link market.v2.trade.area.tickers.TradeArea.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeArea} message TradeArea message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        TradeArea.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.tradeid != null && Object.hasOwnProperty.call(message, "tradeid"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.tradeid);
+                            if (message.cny != null && Object.hasOwnProperty.call(message, "cny"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.cny);
+                            if (message.buy != null && Object.hasOwnProperty.call(message, "buy"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.buy);
+                            if (message.lever != null && Object.hasOwnProperty.call(message, "lever"))
+                                writer.uint32(/* id 4, wireType 2 =*/34).string(message.lever);
+                            if (message.sell != null && Object.hasOwnProperty.call(message, "sell"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.sell);
+                            if (message.last != null && Object.hasOwnProperty.call(message, "last"))
+                                writer.uint32(/* id 6, wireType 2 =*/50).string(message.last);
+                            if (message.volume != null && Object.hasOwnProperty.call(message, "volume"))
+                                writer.uint32(/* id 7, wireType 2 =*/58).string(message.volume);
+                            if (message.change != null && Object.hasOwnProperty.call(message, "change"))
+                                writer.uint32(/* id 8, wireType 2 =*/66).string(message.change);
+                            if (message.high != null && Object.hasOwnProperty.call(message, "high"))
+                                writer.uint32(/* id 9, wireType 2 =*/74).string(message.high);
+                            if (message.low != null && Object.hasOwnProperty.call(message, "low"))
+                                writer.uint32(/* id 10, wireType 2 =*/82).string(message.low);
+                            if (message.isopen != null && Object.hasOwnProperty.call(message, "isopen"))
+                                writer.uint32(/* id 11, wireType 2 =*/90).string(message.isopen);
+                            if (message.open != null && Object.hasOwnProperty.call(message, "open"))
+                                writer.uint32(/* id 12, wireType 0 =*/96).int32(message.open);
+                            if (message.amount != null && Object.hasOwnProperty.call(message, "amount"))
+                                writer.uint32(/* id 13, wireType 2 =*/106).string(message.amount);
+                            if (message.isfiatconvert != null && Object.hasOwnProperty.call(message, "isfiatconvert"))
+                                writer.uint32(/* id 14, wireType 0 =*/112).bool(message.isfiatconvert);
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified TradeArea message, length delimited. Does not implicitly {@link market.v2.trade.area.tickers.TradeArea.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {market.v2.trade.area.tickers.ITradeArea} message TradeArea message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        TradeArea.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a TradeArea message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.area.tickers.TradeArea} TradeArea
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        TradeArea.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.area.tickers.TradeArea();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.tradeid = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.cny = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.buy = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.lever = reader.string();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.sell = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.last = reader.string();
+                                        break;
+                                    }
+                                case 7: {
+                                        message.volume = reader.string();
+                                        break;
+                                    }
+                                case 8: {
+                                        message.change = reader.string();
+                                        break;
+                                    }
+                                case 9: {
+                                        message.high = reader.string();
+                                        break;
+                                    }
+                                case 10: {
+                                        message.low = reader.string();
+                                        break;
+                                    }
+                                case 11: {
+                                        message.isopen = reader.string();
+                                        break;
+                                    }
+                                case 12: {
+                                        message.open = reader.int32();
+                                        break;
+                                    }
+                                case 13: {
+                                        message.amount = reader.string();
+                                        break;
+                                    }
+                                case 14: {
+                                        message.isfiatconvert = reader.bool();
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a TradeArea message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.area.tickers.TradeArea} TradeArea
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        TradeArea.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a TradeArea message.
+                         * @function verify
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        TradeArea.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.tradeid != null && message.hasOwnProperty("tradeid"))
+                                if (!$util.isInteger(message.tradeid))
+                                    return "tradeid: integer expected";
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                if (!$util.isString(message.cny))
+                                    return "cny: string expected";
+                            if (message.buy != null && message.hasOwnProperty("buy"))
+                                if (!$util.isString(message.buy))
+                                    return "buy: string expected";
+                            if (message.lever != null && message.hasOwnProperty("lever"))
+                                if (!$util.isString(message.lever))
+                                    return "lever: string expected";
+                            if (message.sell != null && message.hasOwnProperty("sell"))
+                                if (!$util.isString(message.sell))
+                                    return "sell: string expected";
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                if (!$util.isString(message.last))
+                                    return "last: string expected";
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                if (!$util.isString(message.volume))
+                                    return "volume: string expected";
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                if (!$util.isString(message.change))
+                                    return "change: string expected";
+                            if (message.high != null && message.hasOwnProperty("high"))
+                                if (!$util.isString(message.high))
+                                    return "high: string expected";
+                            if (message.low != null && message.hasOwnProperty("low"))
+                                if (!$util.isString(message.low))
+                                    return "low: string expected";
+                            if (message.isopen != null && message.hasOwnProperty("isopen"))
+                                if (!$util.isString(message.isopen))
+                                    return "isopen: string expected";
+                            if (message.open != null && message.hasOwnProperty("open"))
+                                if (!$util.isInteger(message.open))
+                                    return "open: integer expected";
+                            if (message.amount != null && message.hasOwnProperty("amount"))
+                                if (!$util.isString(message.amount))
+                                    return "amount: string expected";
+                            if (message.isfiatconvert != null && message.hasOwnProperty("isfiatconvert"))
+                                if (typeof message.isfiatconvert !== "boolean")
+                                    return "isfiatconvert: boolean expected";
+                            return null;
+                        };
+
+                        /**
+                         * Creates a TradeArea message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.area.tickers.TradeArea} TradeArea
+                         */
+                        TradeArea.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.area.tickers.TradeArea)
+                                return object;
+                            var message = new $root.market.v2.trade.area.tickers.TradeArea();
+                            if (object.tradeid != null)
+                                message.tradeid = object.tradeid | 0;
+                            if (object.cny != null)
+                                message.cny = String(object.cny);
+                            if (object.buy != null)
+                                message.buy = String(object.buy);
+                            if (object.lever != null)
+                                message.lever = String(object.lever);
+                            if (object.sell != null)
+                                message.sell = String(object.sell);
+                            if (object.last != null)
+                                message.last = String(object.last);
+                            if (object.volume != null)
+                                message.volume = String(object.volume);
+                            if (object.change != null)
+                                message.change = String(object.change);
+                            if (object.high != null)
+                                message.high = String(object.high);
+                            if (object.low != null)
+                                message.low = String(object.low);
+                            if (object.isopen != null)
+                                message.isopen = String(object.isopen);
+                            if (object.open != null)
+                                message.open = object.open | 0;
+                            if (object.amount != null)
+                                message.amount = String(object.amount);
+                            if (object.isfiatconvert != null)
+                                message.isfiatconvert = Boolean(object.isfiatconvert);
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a TradeArea message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {market.v2.trade.area.tickers.TradeArea} message TradeArea
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        TradeArea.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.tradeid = 0;
+                                object.cny = "";
+                                object.buy = "";
+                                object.lever = "";
+                                object.sell = "";
+                                object.last = "";
+                                object.volume = "";
+                                object.change = "";
+                                object.high = "";
+                                object.low = "";
+                                object.isopen = "";
+                                object.open = 0;
+                                object.amount = "";
+                                object.isfiatconvert = false;
+                            }
+                            if (message.tradeid != null && message.hasOwnProperty("tradeid"))
+                                object.tradeid = message.tradeid;
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                object.cny = message.cny;
+                            if (message.buy != null && message.hasOwnProperty("buy"))
+                                object.buy = message.buy;
+                            if (message.lever != null && message.hasOwnProperty("lever"))
+                                object.lever = message.lever;
+                            if (message.sell != null && message.hasOwnProperty("sell"))
+                                object.sell = message.sell;
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                object.last = message.last;
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                object.volume = message.volume;
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                object.change = message.change;
+                            if (message.high != null && message.hasOwnProperty("high"))
+                                object.high = message.high;
+                            if (message.low != null && message.hasOwnProperty("low"))
+                                object.low = message.low;
+                            if (message.isopen != null && message.hasOwnProperty("isopen"))
+                                object.isopen = message.isopen;
+                            if (message.open != null && message.hasOwnProperty("open"))
+                                object.open = message.open;
+                            if (message.amount != null && message.hasOwnProperty("amount"))
+                                object.amount = message.amount;
+                            if (message.isfiatconvert != null && message.hasOwnProperty("isfiatconvert"))
+                                object.isfiatconvert = message.isfiatconvert;
+                            return object;
+                        };
+
+                        /**
+                         * Converts this TradeArea to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        TradeArea.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for TradeArea
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.area.tickers.TradeArea
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        TradeArea.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.area.tickers.TradeArea";
+                        };
+
+                        return TradeArea;
+                    })();
+
+                    return tickers;
+                })();
+
+                return area;
+            })();
+
+            return trade;
+        })();
+
+        return v2;
+    })();
+
+    return market;
+})();
+
+module.exports = $root;

+ 124 - 0
client/hotconi/proto/market.v2.trade.area.tickers.json

@@ -0,0 +1,124 @@
+{
+  "options": {
+    "syntax": "proto3"
+  },
+  "nested": {
+    "market": {
+      "nested": {
+        "v2": {
+          "nested": {
+            "trade": {
+              "nested": {
+                "area": {
+                  "nested": {
+                    "tickers": {
+                      "nested": {
+                        "Response": {
+                          "fields": {
+                            "code": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "msg": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "status": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "ts": {
+                              "type": "int64",
+                              "id": 4
+                            },
+                            "ch": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "tradeareapair": {
+                              "type": "TradeAreaPair",
+                              "id": 6
+                            }
+                          }
+                        },
+                        "TradeAreaPair": {
+                          "fields": {
+                            "tradeidList": {
+                              "rule": "repeated",
+                              "type": "TradeArea",
+                              "id": 1
+                            }
+                          }
+                        },
+                        "TradeArea": {
+                          "fields": {
+                            "tradeid": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "cny": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "buy": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "lever": {
+                              "type": "string",
+                              "id": 4
+                            },
+                            "sell": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "last": {
+                              "type": "string",
+                              "id": 6
+                            },
+                            "volume": {
+                              "type": "string",
+                              "id": 7
+                            },
+                            "change": {
+                              "type": "string",
+                              "id": 8
+                            },
+                            "high": {
+                              "type": "string",
+                              "id": 9
+                            },
+                            "low": {
+                              "type": "string",
+                              "id": 10
+                            },
+                            "isopen": {
+                              "type": "string",
+                              "id": 11
+                            },
+                            "open": {
+                              "type": "int32",
+                              "id": 12
+                            },
+                            "amount": {
+                              "type": "string",
+                              "id": 13
+                            },
+                            "isfiatconvert": {
+                              "type": "bool",
+                              "id": 14
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 36 - 0
client/hotconi/proto/market.v2.trade.area.tickers.proto

@@ -0,0 +1,36 @@
+syntax = "proto3";
+
+package market.v2.trade.area.tickers; // 替换为你的包名
+
+// 定义最外层的消息类型
+message Response {
+  int32 code = 1;
+  string msg = 2;
+  string status = 3;
+  int64 ts = 4;
+  string ch = 5;
+  TradeAreaPair tradeareapair = 6;
+}
+
+// 定义tradeareapair中的消息类型
+message TradeAreaPair {
+  repeated TradeArea tradeid_list = 1; // 由于JSON中的listList实际上是一个列表,我们使用repeated关键字
+}
+
+// 定义tradeid_list中的消息类型
+message TradeArea {
+  int32 tradeid = 1;
+  string cny = 2;
+  string buy = 3;
+  string lever = 4;
+  string sell = 5;
+  string last = 6;
+  string volume = 7;
+  string change = 8;
+  string high = 9;
+  string low = 10;
+  string isopen = 11;
+  int32 open = 12;
+  string amount = 13;
+  bool isfiatconvert = 14;
+}

+ 953 - 0
client/hotconi/proto/market.v2.trade.main.pair.js

@@ -0,0 +1,953 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("protobufjs/minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
+
+$root.market = (function() {
+
+    /**
+     * Namespace market.
+     * @exports market
+     * @namespace
+     */
+    var market = {};
+
+    market.v2 = (function() {
+
+        /**
+         * Namespace v2.
+         * @memberof market
+         * @namespace
+         */
+        var v2 = {};
+
+        v2.trade = (function() {
+
+            /**
+             * Namespace trade.
+             * @memberof market.v2
+             * @namespace
+             */
+            var trade = {};
+
+            trade.main = (function() {
+
+                /**
+                 * Namespace main.
+                 * @memberof market.v2.trade
+                 * @namespace
+                 */
+                var main = {};
+
+                main.pair = (function() {
+
+                    /**
+                     * Namespace pair.
+                     * @memberof market.v2.trade.main
+                     * @namespace
+                     */
+                    var pair = {};
+
+                    pair.Response = (function() {
+
+                        /**
+                         * Properties of a Response.
+                         * @memberof market.v2.trade.main.pair
+                         * @interface IResponse
+                         * @property {number|null} [code] Response code
+                         * @property {string|null} [msg] Response msg
+                         * @property {string|null} [status] Response status
+                         * @property {number|Long|null} [ts] Response ts
+                         * @property {string|null} [ch] Response ch
+                         * @property {market.v2.trade.main.pair.IMainPair|null} [mainpair] Response mainpair
+                         */
+
+                        /**
+                         * Constructs a new Response.
+                         * @memberof market.v2.trade.main.pair
+                         * @classdesc Represents a Response.
+                         * @implements IResponse
+                         * @constructor
+                         * @param {market.v2.trade.main.pair.IResponse=} [properties] Properties to set
+                         */
+                        function Response(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * Response code.
+                         * @member {number} code
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.code = 0;
+
+                        /**
+                         * Response msg.
+                         * @member {string} msg
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.msg = "";
+
+                        /**
+                         * Response status.
+                         * @member {string} status
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.status = "";
+
+                        /**
+                         * Response ts.
+                         * @member {number|Long} ts
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+                        /**
+                         * Response ch.
+                         * @member {string} ch
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.ch = "";
+
+                        /**
+                         * Response mainpair.
+                         * @member {market.v2.trade.main.pair.IMainPair|null|undefined} mainpair
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.mainpair = null;
+
+                        /**
+                         * Creates a new Response instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {market.v2.trade.main.pair.IResponse=} [properties] Properties to set
+                         * @returns {market.v2.trade.main.pair.Response} Response instance
+                         */
+                        Response.create = function create(properties) {
+                            return new Response(properties);
+                        };
+
+                        /**
+                         * Encodes the specified Response message. Does not implicitly {@link market.v2.trade.main.pair.Response.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {market.v2.trade.main.pair.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.code != null && Object.hasOwnProperty.call(message, "code"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.code);
+                            if (message.msg != null && Object.hasOwnProperty.call(message, "msg"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.msg);
+                            if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.status);
+                            if (message.ts != null && Object.hasOwnProperty.call(message, "ts"))
+                                writer.uint32(/* id 4, wireType 0 =*/32).int64(message.ts);
+                            if (message.ch != null && Object.hasOwnProperty.call(message, "ch"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.ch);
+                            if (message.mainpair != null && Object.hasOwnProperty.call(message, "mainpair"))
+                                $root.market.v2.trade.main.pair.MainPair.encode(message.mainpair, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified Response message, length delimited. Does not implicitly {@link market.v2.trade.main.pair.Response.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {market.v2.trade.main.pair.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.main.pair.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.main.pair.Response();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.code = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.msg = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.status = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.ts = reader.int64();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.ch = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.mainpair = $root.market.v2.trade.main.pair.MainPair.decode(reader, reader.uint32());
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.main.pair.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a Response message.
+                         * @function verify
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        Response.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                if (!$util.isInteger(message.code))
+                                    return "code: integer expected";
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                if (!$util.isString(message.msg))
+                                    return "msg: string expected";
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                if (!$util.isString(message.status))
+                                    return "status: string expected";
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))
+                                    return "ts: integer|Long expected";
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                if (!$util.isString(message.ch))
+                                    return "ch: string expected";
+                            if (message.mainpair != null && message.hasOwnProperty("mainpair")) {
+                                var error = $root.market.v2.trade.main.pair.MainPair.verify(message.mainpair);
+                                if (error)
+                                    return "mainpair." + error;
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a Response message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.main.pair.Response} Response
+                         */
+                        Response.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.main.pair.Response)
+                                return object;
+                            var message = new $root.market.v2.trade.main.pair.Response();
+                            if (object.code != null)
+                                message.code = object.code | 0;
+                            if (object.msg != null)
+                                message.msg = String(object.msg);
+                            if (object.status != null)
+                                message.status = String(object.status);
+                            if (object.ts != null)
+                                if ($util.Long)
+                                    (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;
+                                else if (typeof object.ts === "string")
+                                    message.ts = parseInt(object.ts, 10);
+                                else if (typeof object.ts === "number")
+                                    message.ts = object.ts;
+                                else if (typeof object.ts === "object")
+                                    message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();
+                            if (object.ch != null)
+                                message.ch = String(object.ch);
+                            if (object.mainpair != null) {
+                                if (typeof object.mainpair !== "object")
+                                    throw TypeError(".market.v2.trade.main.pair.Response.mainpair: object expected");
+                                message.mainpair = $root.market.v2.trade.main.pair.MainPair.fromObject(object.mainpair);
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a Response message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {market.v2.trade.main.pair.Response} message Response
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        Response.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.code = 0;
+                                object.msg = "";
+                                object.status = "";
+                                if ($util.Long) {
+                                    var long = new $util.Long(0, 0, false);
+                                    object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                                } else
+                                    object.ts = options.longs === String ? "0" : 0;
+                                object.ch = "";
+                                object.mainpair = null;
+                            }
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                object.code = message.code;
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                object.msg = message.msg;
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                object.status = message.status;
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (typeof message.ts === "number")
+                                    object.ts = options.longs === String ? String(message.ts) : message.ts;
+                                else
+                                    object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                object.ch = message.ch;
+                            if (message.mainpair != null && message.hasOwnProperty("mainpair"))
+                                object.mainpair = $root.market.v2.trade.main.pair.MainPair.toObject(message.mainpair, options);
+                            return object;
+                        };
+
+                        /**
+                         * Converts this Response to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        Response.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for Response
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.main.pair.Response
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        Response.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.main.pair.Response";
+                        };
+
+                        return Response;
+                    })();
+
+                    pair.MainPair = (function() {
+
+                        /**
+                         * Properties of a MainPair.
+                         * @memberof market.v2.trade.main.pair
+                         * @interface IMainPair
+                         * @property {Array.<market.v2.trade.main.pair.IPairInfo>|null} [listList] MainPair listList
+                         */
+
+                        /**
+                         * Constructs a new MainPair.
+                         * @memberof market.v2.trade.main.pair
+                         * @classdesc Represents a MainPair.
+                         * @implements IMainPair
+                         * @constructor
+                         * @param {market.v2.trade.main.pair.IMainPair=} [properties] Properties to set
+                         */
+                        function MainPair(properties) {
+                            this.listList = [];
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * MainPair listList.
+                         * @member {Array.<market.v2.trade.main.pair.IPairInfo>} listList
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @instance
+                         */
+                        MainPair.prototype.listList = $util.emptyArray;
+
+                        /**
+                         * Creates a new MainPair instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {market.v2.trade.main.pair.IMainPair=} [properties] Properties to set
+                         * @returns {market.v2.trade.main.pair.MainPair} MainPair instance
+                         */
+                        MainPair.create = function create(properties) {
+                            return new MainPair(properties);
+                        };
+
+                        /**
+                         * Encodes the specified MainPair message. Does not implicitly {@link market.v2.trade.main.pair.MainPair.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {market.v2.trade.main.pair.IMainPair} message MainPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        MainPair.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.listList != null && message.listList.length)
+                                for (var i = 0; i < message.listList.length; ++i)
+                                    $root.market.v2.trade.main.pair.PairInfo.encode(message.listList[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified MainPair message, length delimited. Does not implicitly {@link market.v2.trade.main.pair.MainPair.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {market.v2.trade.main.pair.IMainPair} message MainPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        MainPair.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a MainPair message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.main.pair.MainPair} MainPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        MainPair.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.main.pair.MainPair();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        if (!(message.listList && message.listList.length))
+                                            message.listList = [];
+                                        message.listList.push($root.market.v2.trade.main.pair.PairInfo.decode(reader, reader.uint32()));
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a MainPair message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.main.pair.MainPair} MainPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        MainPair.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a MainPair message.
+                         * @function verify
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        MainPair.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.listList != null && message.hasOwnProperty("listList")) {
+                                if (!Array.isArray(message.listList))
+                                    return "listList: array expected";
+                                for (var i = 0; i < message.listList.length; ++i) {
+                                    var error = $root.market.v2.trade.main.pair.PairInfo.verify(message.listList[i]);
+                                    if (error)
+                                        return "listList." + error;
+                                }
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a MainPair message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.main.pair.MainPair} MainPair
+                         */
+                        MainPair.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.main.pair.MainPair)
+                                return object;
+                            var message = new $root.market.v2.trade.main.pair.MainPair();
+                            if (object.listList) {
+                                if (!Array.isArray(object.listList))
+                                    throw TypeError(".market.v2.trade.main.pair.MainPair.listList: array expected");
+                                message.listList = [];
+                                for (var i = 0; i < object.listList.length; ++i) {
+                                    if (typeof object.listList[i] !== "object")
+                                        throw TypeError(".market.v2.trade.main.pair.MainPair.listList: object expected");
+                                    message.listList[i] = $root.market.v2.trade.main.pair.PairInfo.fromObject(object.listList[i]);
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a MainPair message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {market.v2.trade.main.pair.MainPair} message MainPair
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        MainPair.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.arrays || options.defaults)
+                                object.listList = [];
+                            if (message.listList && message.listList.length) {
+                                object.listList = [];
+                                for (var j = 0; j < message.listList.length; ++j)
+                                    object.listList[j] = $root.market.v2.trade.main.pair.PairInfo.toObject(message.listList[j], options);
+                            }
+                            return object;
+                        };
+
+                        /**
+                         * Converts this MainPair to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        MainPair.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for MainPair
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.main.pair.MainPair
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        MainPair.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.main.pair.MainPair";
+                        };
+
+                        return MainPair;
+                    })();
+
+                    pair.PairInfo = (function() {
+
+                        /**
+                         * Properties of a PairInfo.
+                         * @memberof market.v2.trade.main.pair
+                         * @interface IPairInfo
+                         * @property {number|null} [tradeId] PairInfo tradeId
+                         * @property {string|null} [cny] PairInfo cny
+                         * @property {string|null} [totalamount] PairInfo totalamount
+                         * @property {string|null} [last] PairInfo last
+                         * @property {string|null} [volume] PairInfo volume
+                         * @property {string|null} [change] PairInfo change
+                         */
+
+                        /**
+                         * Constructs a new PairInfo.
+                         * @memberof market.v2.trade.main.pair
+                         * @classdesc Represents a PairInfo.
+                         * @implements IPairInfo
+                         * @constructor
+                         * @param {market.v2.trade.main.pair.IPairInfo=} [properties] Properties to set
+                         */
+                        function PairInfo(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * PairInfo tradeId.
+                         * @member {number} tradeId
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.tradeId = 0;
+
+                        /**
+                         * PairInfo cny.
+                         * @member {string} cny
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.cny = "";
+
+                        /**
+                         * PairInfo totalamount.
+                         * @member {string} totalamount
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.totalamount = "";
+
+                        /**
+                         * PairInfo last.
+                         * @member {string} last
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.last = "";
+
+                        /**
+                         * PairInfo volume.
+                         * @member {string} volume
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.volume = "";
+
+                        /**
+                         * PairInfo change.
+                         * @member {string} change
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.change = "";
+
+                        /**
+                         * Creates a new PairInfo instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.main.pair.IPairInfo=} [properties] Properties to set
+                         * @returns {market.v2.trade.main.pair.PairInfo} PairInfo instance
+                         */
+                        PairInfo.create = function create(properties) {
+                            return new PairInfo(properties);
+                        };
+
+                        /**
+                         * Encodes the specified PairInfo message. Does not implicitly {@link market.v2.trade.main.pair.PairInfo.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.main.pair.IPairInfo} message PairInfo message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        PairInfo.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.tradeId != null && Object.hasOwnProperty.call(message, "tradeId"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.tradeId);
+                            if (message.cny != null && Object.hasOwnProperty.call(message, "cny"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.cny);
+                            if (message.totalamount != null && Object.hasOwnProperty.call(message, "totalamount"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.totalamount);
+                            if (message.last != null && Object.hasOwnProperty.call(message, "last"))
+                                writer.uint32(/* id 4, wireType 2 =*/34).string(message.last);
+                            if (message.volume != null && Object.hasOwnProperty.call(message, "volume"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.volume);
+                            if (message.change != null && Object.hasOwnProperty.call(message, "change"))
+                                writer.uint32(/* id 6, wireType 2 =*/50).string(message.change);
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified PairInfo message, length delimited. Does not implicitly {@link market.v2.trade.main.pair.PairInfo.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.main.pair.IPairInfo} message PairInfo message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        PairInfo.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a PairInfo message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.main.pair.PairInfo} PairInfo
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        PairInfo.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.main.pair.PairInfo();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.tradeId = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.cny = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.totalamount = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.last = reader.string();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.volume = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.change = reader.string();
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a PairInfo message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.main.pair.PairInfo} PairInfo
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        PairInfo.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a PairInfo message.
+                         * @function verify
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        PairInfo.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.tradeId != null && message.hasOwnProperty("tradeId"))
+                                if (!$util.isInteger(message.tradeId))
+                                    return "tradeId: integer expected";
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                if (!$util.isString(message.cny))
+                                    return "cny: string expected";
+                            if (message.totalamount != null && message.hasOwnProperty("totalamount"))
+                                if (!$util.isString(message.totalamount))
+                                    return "totalamount: string expected";
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                if (!$util.isString(message.last))
+                                    return "last: string expected";
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                if (!$util.isString(message.volume))
+                                    return "volume: string expected";
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                if (!$util.isString(message.change))
+                                    return "change: string expected";
+                            return null;
+                        };
+
+                        /**
+                         * Creates a PairInfo message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.main.pair.PairInfo} PairInfo
+                         */
+                        PairInfo.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.main.pair.PairInfo)
+                                return object;
+                            var message = new $root.market.v2.trade.main.pair.PairInfo();
+                            if (object.tradeId != null)
+                                message.tradeId = object.tradeId | 0;
+                            if (object.cny != null)
+                                message.cny = String(object.cny);
+                            if (object.totalamount != null)
+                                message.totalamount = String(object.totalamount);
+                            if (object.last != null)
+                                message.last = String(object.last);
+                            if (object.volume != null)
+                                message.volume = String(object.volume);
+                            if (object.change != null)
+                                message.change = String(object.change);
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a PairInfo message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.main.pair.PairInfo} message PairInfo
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        PairInfo.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.tradeId = 0;
+                                object.cny = "";
+                                object.totalamount = "";
+                                object.last = "";
+                                object.volume = "";
+                                object.change = "";
+                            }
+                            if (message.tradeId != null && message.hasOwnProperty("tradeId"))
+                                object.tradeId = message.tradeId;
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                object.cny = message.cny;
+                            if (message.totalamount != null && message.hasOwnProperty("totalamount"))
+                                object.totalamount = message.totalamount;
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                object.last = message.last;
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                object.volume = message.volume;
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                object.change = message.change;
+                            return object;
+                        };
+
+                        /**
+                         * Converts this PairInfo to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        PairInfo.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for PairInfo
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.main.pair.PairInfo
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        PairInfo.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.main.pair.PairInfo";
+                        };
+
+                        return PairInfo;
+                    })();
+
+                    return pair;
+                })();
+
+                return main;
+            })();
+
+            return trade;
+        })();
+
+        return v2;
+    })();
+
+    return market;
+})();
+
+module.exports = $root;

+ 92 - 0
client/hotconi/proto/market.v2.trade.main.pair.json

@@ -0,0 +1,92 @@
+{
+  "options": {
+    "syntax": "proto3"
+  },
+  "nested": {
+    "market": {
+      "nested": {
+        "v2": {
+          "nested": {
+            "trade": {
+              "nested": {
+                "main": {
+                  "nested": {
+                    "pair": {
+                      "nested": {
+                        "Response": {
+                          "fields": {
+                            "code": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "msg": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "status": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "ts": {
+                              "type": "int64",
+                              "id": 4
+                            },
+                            "ch": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "mainpair": {
+                              "type": "MainPair",
+                              "id": 6
+                            }
+                          }
+                        },
+                        "MainPair": {
+                          "fields": {
+                            "listList": {
+                              "rule": "repeated",
+                              "type": "PairInfo",
+                              "id": 1
+                            }
+                          }
+                        },
+                        "PairInfo": {
+                          "fields": {
+                            "tradeId": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "cny": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "totalamount": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "last": {
+                              "type": "string",
+                              "id": 4
+                            },
+                            "volume": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "change": {
+                              "type": "string",
+                              "id": 6
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 28 - 0
client/hotconi/proto/market.v2.trade.main.pair.proto

@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+package market.v2.trade.main.pair; // 替换为你的包名
+
+// 定义最外层的消息类型
+message Response {
+  int32 code = 1;
+  string msg = 2;
+  string status = 3;
+  int64 ts = 4;
+  string ch = 5;
+  MainPair mainpair = 6;
+}
+
+// 定义mainpair中的消息类型
+message MainPair {
+  repeated PairInfo list_list = 1; // 使用repeated关键字表示数组
+}
+
+// 定义PairInfo消息类型
+message PairInfo {
+  int32 tradeId = 1;
+  string cny = 2;
+  string totalamount = 3;
+  string last = 4;
+  string volume = 5;
+  string change = 6;
+}

+ 953 - 0
client/hotconi/proto/market.v2.trade.recommend.pair.js

@@ -0,0 +1,953 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("protobufjs/minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
+
+$root.market = (function() {
+
+    /**
+     * Namespace market.
+     * @exports market
+     * @namespace
+     */
+    var market = {};
+
+    market.v2 = (function() {
+
+        /**
+         * Namespace v2.
+         * @memberof market
+         * @namespace
+         */
+        var v2 = {};
+
+        v2.trade = (function() {
+
+            /**
+             * Namespace trade.
+             * @memberof market.v2
+             * @namespace
+             */
+            var trade = {};
+
+            trade.recommend = (function() {
+
+                /**
+                 * Namespace recommend.
+                 * @memberof market.v2.trade
+                 * @namespace
+                 */
+                var recommend = {};
+
+                recommend.pair = (function() {
+
+                    /**
+                     * Namespace pair.
+                     * @memberof market.v2.trade.recommend
+                     * @namespace
+                     */
+                    var pair = {};
+
+                    pair.Response = (function() {
+
+                        /**
+                         * Properties of a Response.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @interface IResponse
+                         * @property {number|null} [code] Response code
+                         * @property {string|null} [msg] Response msg
+                         * @property {string|null} [status] Response status
+                         * @property {number|Long|null} [ts] Response ts
+                         * @property {string|null} [ch] Response ch
+                         * @property {market.v2.trade.recommend.pair.IRecommendPair|null} [recommendpair] Response recommendpair
+                         */
+
+                        /**
+                         * Constructs a new Response.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @classdesc Represents a Response.
+                         * @implements IResponse
+                         * @constructor
+                         * @param {market.v2.trade.recommend.pair.IResponse=} [properties] Properties to set
+                         */
+                        function Response(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * Response code.
+                         * @member {number} code
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.code = 0;
+
+                        /**
+                         * Response msg.
+                         * @member {string} msg
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.msg = "";
+
+                        /**
+                         * Response status.
+                         * @member {string} status
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.status = "";
+
+                        /**
+                         * Response ts.
+                         * @member {number|Long} ts
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.ts = $util.Long ? $util.Long.fromBits(0,0,false) : 0;
+
+                        /**
+                         * Response ch.
+                         * @member {string} ch
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.ch = "";
+
+                        /**
+                         * Response recommendpair.
+                         * @member {market.v2.trade.recommend.pair.IRecommendPair|null|undefined} recommendpair
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         */
+                        Response.prototype.recommendpair = null;
+
+                        /**
+                         * Creates a new Response instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IResponse=} [properties] Properties to set
+                         * @returns {market.v2.trade.recommend.pair.Response} Response instance
+                         */
+                        Response.create = function create(properties) {
+                            return new Response(properties);
+                        };
+
+                        /**
+                         * Encodes the specified Response message. Does not implicitly {@link market.v2.trade.recommend.pair.Response.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.code != null && Object.hasOwnProperty.call(message, "code"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.code);
+                            if (message.msg != null && Object.hasOwnProperty.call(message, "msg"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.msg);
+                            if (message.status != null && Object.hasOwnProperty.call(message, "status"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.status);
+                            if (message.ts != null && Object.hasOwnProperty.call(message, "ts"))
+                                writer.uint32(/* id 4, wireType 0 =*/32).int64(message.ts);
+                            if (message.ch != null && Object.hasOwnProperty.call(message, "ch"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.ch);
+                            if (message.recommendpair != null && Object.hasOwnProperty.call(message, "recommendpair"))
+                                $root.market.v2.trade.recommend.pair.RecommendPair.encode(message.recommendpair, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified Response message, length delimited. Does not implicitly {@link market.v2.trade.recommend.pair.Response.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IResponse} message Response message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        Response.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.recommend.pair.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.recommend.pair.Response();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.code = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.msg = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.status = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.ts = reader.int64();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.ch = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.recommendpair = $root.market.v2.trade.recommend.pair.RecommendPair.decode(reader, reader.uint32());
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a Response message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.recommend.pair.Response} Response
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        Response.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a Response message.
+                         * @function verify
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        Response.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                if (!$util.isInteger(message.code))
+                                    return "code: integer expected";
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                if (!$util.isString(message.msg))
+                                    return "msg: string expected";
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                if (!$util.isString(message.status))
+                                    return "status: string expected";
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (!$util.isInteger(message.ts) && !(message.ts && $util.isInteger(message.ts.low) && $util.isInteger(message.ts.high)))
+                                    return "ts: integer|Long expected";
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                if (!$util.isString(message.ch))
+                                    return "ch: string expected";
+                            if (message.recommendpair != null && message.hasOwnProperty("recommendpair")) {
+                                var error = $root.market.v2.trade.recommend.pair.RecommendPair.verify(message.recommendpair);
+                                if (error)
+                                    return "recommendpair." + error;
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a Response message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.recommend.pair.Response} Response
+                         */
+                        Response.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.recommend.pair.Response)
+                                return object;
+                            var message = new $root.market.v2.trade.recommend.pair.Response();
+                            if (object.code != null)
+                                message.code = object.code | 0;
+                            if (object.msg != null)
+                                message.msg = String(object.msg);
+                            if (object.status != null)
+                                message.status = String(object.status);
+                            if (object.ts != null)
+                                if ($util.Long)
+                                    (message.ts = $util.Long.fromValue(object.ts)).unsigned = false;
+                                else if (typeof object.ts === "string")
+                                    message.ts = parseInt(object.ts, 10);
+                                else if (typeof object.ts === "number")
+                                    message.ts = object.ts;
+                                else if (typeof object.ts === "object")
+                                    message.ts = new $util.LongBits(object.ts.low >>> 0, object.ts.high >>> 0).toNumber();
+                            if (object.ch != null)
+                                message.ch = String(object.ch);
+                            if (object.recommendpair != null) {
+                                if (typeof object.recommendpair !== "object")
+                                    throw TypeError(".market.v2.trade.recommend.pair.Response.recommendpair: object expected");
+                                message.recommendpair = $root.market.v2.trade.recommend.pair.RecommendPair.fromObject(object.recommendpair);
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a Response message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.Response} message Response
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        Response.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.code = 0;
+                                object.msg = "";
+                                object.status = "";
+                                if ($util.Long) {
+                                    var long = new $util.Long(0, 0, false);
+                                    object.ts = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
+                                } else
+                                    object.ts = options.longs === String ? "0" : 0;
+                                object.ch = "";
+                                object.recommendpair = null;
+                            }
+                            if (message.code != null && message.hasOwnProperty("code"))
+                                object.code = message.code;
+                            if (message.msg != null && message.hasOwnProperty("msg"))
+                                object.msg = message.msg;
+                            if (message.status != null && message.hasOwnProperty("status"))
+                                object.status = message.status;
+                            if (message.ts != null && message.hasOwnProperty("ts"))
+                                if (typeof message.ts === "number")
+                                    object.ts = options.longs === String ? String(message.ts) : message.ts;
+                                else
+                                    object.ts = options.longs === String ? $util.Long.prototype.toString.call(message.ts) : options.longs === Number ? new $util.LongBits(message.ts.low >>> 0, message.ts.high >>> 0).toNumber() : message.ts;
+                            if (message.ch != null && message.hasOwnProperty("ch"))
+                                object.ch = message.ch;
+                            if (message.recommendpair != null && message.hasOwnProperty("recommendpair"))
+                                object.recommendpair = $root.market.v2.trade.recommend.pair.RecommendPair.toObject(message.recommendpair, options);
+                            return object;
+                        };
+
+                        /**
+                         * Converts this Response to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        Response.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for Response
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.recommend.pair.Response
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        Response.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.recommend.pair.Response";
+                        };
+
+                        return Response;
+                    })();
+
+                    pair.RecommendPair = (function() {
+
+                        /**
+                         * Properties of a RecommendPair.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @interface IRecommendPair
+                         * @property {Array.<market.v2.trade.recommend.pair.IPairInfo>|null} [listList] RecommendPair listList
+                         */
+
+                        /**
+                         * Constructs a new RecommendPair.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @classdesc Represents a RecommendPair.
+                         * @implements IRecommendPair
+                         * @constructor
+                         * @param {market.v2.trade.recommend.pair.IRecommendPair=} [properties] Properties to set
+                         */
+                        function RecommendPair(properties) {
+                            this.listList = [];
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * RecommendPair listList.
+                         * @member {Array.<market.v2.trade.recommend.pair.IPairInfo>} listList
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @instance
+                         */
+                        RecommendPair.prototype.listList = $util.emptyArray;
+
+                        /**
+                         * Creates a new RecommendPair instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IRecommendPair=} [properties] Properties to set
+                         * @returns {market.v2.trade.recommend.pair.RecommendPair} RecommendPair instance
+                         */
+                        RecommendPair.create = function create(properties) {
+                            return new RecommendPair(properties);
+                        };
+
+                        /**
+                         * Encodes the specified RecommendPair message. Does not implicitly {@link market.v2.trade.recommend.pair.RecommendPair.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IRecommendPair} message RecommendPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        RecommendPair.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.listList != null && message.listList.length)
+                                for (var i = 0; i < message.listList.length; ++i)
+                                    $root.market.v2.trade.recommend.pair.PairInfo.encode(message.listList[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified RecommendPair message, length delimited. Does not implicitly {@link market.v2.trade.recommend.pair.RecommendPair.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IRecommendPair} message RecommendPair message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        RecommendPair.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a RecommendPair message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.recommend.pair.RecommendPair} RecommendPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        RecommendPair.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.recommend.pair.RecommendPair();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        if (!(message.listList && message.listList.length))
+                                            message.listList = [];
+                                        message.listList.push($root.market.v2.trade.recommend.pair.PairInfo.decode(reader, reader.uint32()));
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a RecommendPair message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.recommend.pair.RecommendPair} RecommendPair
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        RecommendPair.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a RecommendPair message.
+                         * @function verify
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        RecommendPair.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.listList != null && message.hasOwnProperty("listList")) {
+                                if (!Array.isArray(message.listList))
+                                    return "listList: array expected";
+                                for (var i = 0; i < message.listList.length; ++i) {
+                                    var error = $root.market.v2.trade.recommend.pair.PairInfo.verify(message.listList[i]);
+                                    if (error)
+                                        return "listList." + error;
+                                }
+                            }
+                            return null;
+                        };
+
+                        /**
+                         * Creates a RecommendPair message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.recommend.pair.RecommendPair} RecommendPair
+                         */
+                        RecommendPair.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.recommend.pair.RecommendPair)
+                                return object;
+                            var message = new $root.market.v2.trade.recommend.pair.RecommendPair();
+                            if (object.listList) {
+                                if (!Array.isArray(object.listList))
+                                    throw TypeError(".market.v2.trade.recommend.pair.RecommendPair.listList: array expected");
+                                message.listList = [];
+                                for (var i = 0; i < object.listList.length; ++i) {
+                                    if (typeof object.listList[i] !== "object")
+                                        throw TypeError(".market.v2.trade.recommend.pair.RecommendPair.listList: object expected");
+                                    message.listList[i] = $root.market.v2.trade.recommend.pair.PairInfo.fromObject(object.listList[i]);
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a RecommendPair message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.RecommendPair} message RecommendPair
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        RecommendPair.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.arrays || options.defaults)
+                                object.listList = [];
+                            if (message.listList && message.listList.length) {
+                                object.listList = [];
+                                for (var j = 0; j < message.listList.length; ++j)
+                                    object.listList[j] = $root.market.v2.trade.recommend.pair.PairInfo.toObject(message.listList[j], options);
+                            }
+                            return object;
+                        };
+
+                        /**
+                         * Converts this RecommendPair to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        RecommendPair.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for RecommendPair
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.recommend.pair.RecommendPair
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        RecommendPair.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.recommend.pair.RecommendPair";
+                        };
+
+                        return RecommendPair;
+                    })();
+
+                    pair.PairInfo = (function() {
+
+                        /**
+                         * Properties of a PairInfo.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @interface IPairInfo
+                         * @property {number|null} [tradeId] PairInfo tradeId
+                         * @property {string|null} [cny] PairInfo cny
+                         * @property {string|null} [totalamount] PairInfo totalamount
+                         * @property {string|null} [last] PairInfo last
+                         * @property {string|null} [volume] PairInfo volume
+                         * @property {string|null} [change] PairInfo change
+                         */
+
+                        /**
+                         * Constructs a new PairInfo.
+                         * @memberof market.v2.trade.recommend.pair
+                         * @classdesc Represents a PairInfo.
+                         * @implements IPairInfo
+                         * @constructor
+                         * @param {market.v2.trade.recommend.pair.IPairInfo=} [properties] Properties to set
+                         */
+                        function PairInfo(properties) {
+                            if (properties)
+                                for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                                    if (properties[keys[i]] != null)
+                                        this[keys[i]] = properties[keys[i]];
+                        }
+
+                        /**
+                         * PairInfo tradeId.
+                         * @member {number} tradeId
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.tradeId = 0;
+
+                        /**
+                         * PairInfo cny.
+                         * @member {string} cny
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.cny = "";
+
+                        /**
+                         * PairInfo totalamount.
+                         * @member {string} totalamount
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.totalamount = "";
+
+                        /**
+                         * PairInfo last.
+                         * @member {string} last
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.last = "";
+
+                        /**
+                         * PairInfo volume.
+                         * @member {string} volume
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.volume = "";
+
+                        /**
+                         * PairInfo change.
+                         * @member {string} change
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         */
+                        PairInfo.prototype.change = "";
+
+                        /**
+                         * Creates a new PairInfo instance using the specified properties.
+                         * @function create
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IPairInfo=} [properties] Properties to set
+                         * @returns {market.v2.trade.recommend.pair.PairInfo} PairInfo instance
+                         */
+                        PairInfo.create = function create(properties) {
+                            return new PairInfo(properties);
+                        };
+
+                        /**
+                         * Encodes the specified PairInfo message. Does not implicitly {@link market.v2.trade.recommend.pair.PairInfo.verify|verify} messages.
+                         * @function encode
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IPairInfo} message PairInfo message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        PairInfo.encode = function encode(message, writer) {
+                            if (!writer)
+                                writer = $Writer.create();
+                            if (message.tradeId != null && Object.hasOwnProperty.call(message, "tradeId"))
+                                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.tradeId);
+                            if (message.cny != null && Object.hasOwnProperty.call(message, "cny"))
+                                writer.uint32(/* id 2, wireType 2 =*/18).string(message.cny);
+                            if (message.totalamount != null && Object.hasOwnProperty.call(message, "totalamount"))
+                                writer.uint32(/* id 3, wireType 2 =*/26).string(message.totalamount);
+                            if (message.last != null && Object.hasOwnProperty.call(message, "last"))
+                                writer.uint32(/* id 4, wireType 2 =*/34).string(message.last);
+                            if (message.volume != null && Object.hasOwnProperty.call(message, "volume"))
+                                writer.uint32(/* id 5, wireType 2 =*/42).string(message.volume);
+                            if (message.change != null && Object.hasOwnProperty.call(message, "change"))
+                                writer.uint32(/* id 6, wireType 2 =*/50).string(message.change);
+                            return writer;
+                        };
+
+                        /**
+                         * Encodes the specified PairInfo message, length delimited. Does not implicitly {@link market.v2.trade.recommend.pair.PairInfo.verify|verify} messages.
+                         * @function encodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.IPairInfo} message PairInfo message or plain object to encode
+                         * @param {$protobuf.Writer} [writer] Writer to encode to
+                         * @returns {$protobuf.Writer} Writer
+                         */
+                        PairInfo.encodeDelimited = function encodeDelimited(message, writer) {
+                            return this.encode(message, writer).ldelim();
+                        };
+
+                        /**
+                         * Decodes a PairInfo message from the specified reader or buffer.
+                         * @function decode
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @param {number} [length] Message length if known beforehand
+                         * @returns {market.v2.trade.recommend.pair.PairInfo} PairInfo
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        PairInfo.decode = function decode(reader, length) {
+                            if (!(reader instanceof $Reader))
+                                reader = $Reader.create(reader);
+                            var end = length === undefined ? reader.len : reader.pos + length, message = new $root.market.v2.trade.recommend.pair.PairInfo();
+                            while (reader.pos < end) {
+                                var tag = reader.uint32();
+                                switch (tag >>> 3) {
+                                case 1: {
+                                        message.tradeId = reader.int32();
+                                        break;
+                                    }
+                                case 2: {
+                                        message.cny = reader.string();
+                                        break;
+                                    }
+                                case 3: {
+                                        message.totalamount = reader.string();
+                                        break;
+                                    }
+                                case 4: {
+                                        message.last = reader.string();
+                                        break;
+                                    }
+                                case 5: {
+                                        message.volume = reader.string();
+                                        break;
+                                    }
+                                case 6: {
+                                        message.change = reader.string();
+                                        break;
+                                    }
+                                default:
+                                    reader.skipType(tag & 7);
+                                    break;
+                                }
+                            }
+                            return message;
+                        };
+
+                        /**
+                         * Decodes a PairInfo message from the specified reader or buffer, length delimited.
+                         * @function decodeDelimited
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+                         * @returns {market.v2.trade.recommend.pair.PairInfo} PairInfo
+                         * @throws {Error} If the payload is not a reader or valid buffer
+                         * @throws {$protobuf.util.ProtocolError} If required fields are missing
+                         */
+                        PairInfo.decodeDelimited = function decodeDelimited(reader) {
+                            if (!(reader instanceof $Reader))
+                                reader = new $Reader(reader);
+                            return this.decode(reader, reader.uint32());
+                        };
+
+                        /**
+                         * Verifies a PairInfo message.
+                         * @function verify
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {Object.<string,*>} message Plain object to verify
+                         * @returns {string|null} `null` if valid, otherwise the reason why it is not
+                         */
+                        PairInfo.verify = function verify(message) {
+                            if (typeof message !== "object" || message === null)
+                                return "object expected";
+                            if (message.tradeId != null && message.hasOwnProperty("tradeId"))
+                                if (!$util.isInteger(message.tradeId))
+                                    return "tradeId: integer expected";
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                if (!$util.isString(message.cny))
+                                    return "cny: string expected";
+                            if (message.totalamount != null && message.hasOwnProperty("totalamount"))
+                                if (!$util.isString(message.totalamount))
+                                    return "totalamount: string expected";
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                if (!$util.isString(message.last))
+                                    return "last: string expected";
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                if (!$util.isString(message.volume))
+                                    return "volume: string expected";
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                if (!$util.isString(message.change))
+                                    return "change: string expected";
+                            return null;
+                        };
+
+                        /**
+                         * Creates a PairInfo message from a plain object. Also converts values to their respective internal types.
+                         * @function fromObject
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {Object.<string,*>} object Plain object
+                         * @returns {market.v2.trade.recommend.pair.PairInfo} PairInfo
+                         */
+                        PairInfo.fromObject = function fromObject(object) {
+                            if (object instanceof $root.market.v2.trade.recommend.pair.PairInfo)
+                                return object;
+                            var message = new $root.market.v2.trade.recommend.pair.PairInfo();
+                            if (object.tradeId != null)
+                                message.tradeId = object.tradeId | 0;
+                            if (object.cny != null)
+                                message.cny = String(object.cny);
+                            if (object.totalamount != null)
+                                message.totalamount = String(object.totalamount);
+                            if (object.last != null)
+                                message.last = String(object.last);
+                            if (object.volume != null)
+                                message.volume = String(object.volume);
+                            if (object.change != null)
+                                message.change = String(object.change);
+                            return message;
+                        };
+
+                        /**
+                         * Creates a plain object from a PairInfo message. Also converts values to other types if specified.
+                         * @function toObject
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {market.v2.trade.recommend.pair.PairInfo} message PairInfo
+                         * @param {$protobuf.IConversionOptions} [options] Conversion options
+                         * @returns {Object.<string,*>} Plain object
+                         */
+                        PairInfo.toObject = function toObject(message, options) {
+                            if (!options)
+                                options = {};
+                            var object = {};
+                            if (options.defaults) {
+                                object.tradeId = 0;
+                                object.cny = "";
+                                object.totalamount = "";
+                                object.last = "";
+                                object.volume = "";
+                                object.change = "";
+                            }
+                            if (message.tradeId != null && message.hasOwnProperty("tradeId"))
+                                object.tradeId = message.tradeId;
+                            if (message.cny != null && message.hasOwnProperty("cny"))
+                                object.cny = message.cny;
+                            if (message.totalamount != null && message.hasOwnProperty("totalamount"))
+                                object.totalamount = message.totalamount;
+                            if (message.last != null && message.hasOwnProperty("last"))
+                                object.last = message.last;
+                            if (message.volume != null && message.hasOwnProperty("volume"))
+                                object.volume = message.volume;
+                            if (message.change != null && message.hasOwnProperty("change"))
+                                object.change = message.change;
+                            return object;
+                        };
+
+                        /**
+                         * Converts this PairInfo to JSON.
+                         * @function toJSON
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @instance
+                         * @returns {Object.<string,*>} JSON object
+                         */
+                        PairInfo.prototype.toJSON = function toJSON() {
+                            return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+                        };
+
+                        /**
+                         * Gets the default type url for PairInfo
+                         * @function getTypeUrl
+                         * @memberof market.v2.trade.recommend.pair.PairInfo
+                         * @static
+                         * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
+                         * @returns {string} The default type url
+                         */
+                        PairInfo.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
+                            if (typeUrlPrefix === undefined) {
+                                typeUrlPrefix = "type.googleapis.com";
+                            }
+                            return typeUrlPrefix + "/market.v2.trade.recommend.pair.PairInfo";
+                        };
+
+                        return PairInfo;
+                    })();
+
+                    return pair;
+                })();
+
+                return recommend;
+            })();
+
+            return trade;
+        })();
+
+        return v2;
+    })();
+
+    return market;
+})();
+
+module.exports = $root;

+ 92 - 0
client/hotconi/proto/market.v2.trade.recommend.pair.json

@@ -0,0 +1,92 @@
+{
+  "options": {
+    "syntax": "proto3"
+  },
+  "nested": {
+    "market": {
+      "nested": {
+        "v2": {
+          "nested": {
+            "trade": {
+              "nested": {
+                "recommend": {
+                  "nested": {
+                    "pair": {
+                      "nested": {
+                        "Response": {
+                          "fields": {
+                            "code": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "msg": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "status": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "ts": {
+                              "type": "int64",
+                              "id": 4
+                            },
+                            "ch": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "recommendpair": {
+                              "type": "RecommendPair",
+                              "id": 6
+                            }
+                          }
+                        },
+                        "RecommendPair": {
+                          "fields": {
+                            "listList": {
+                              "rule": "repeated",
+                              "type": "PairInfo",
+                              "id": 1
+                            }
+                          }
+                        },
+                        "PairInfo": {
+                          "fields": {
+                            "tradeId": {
+                              "type": "int32",
+                              "id": 1
+                            },
+                            "cny": {
+                              "type": "string",
+                              "id": 2
+                            },
+                            "totalamount": {
+                              "type": "string",
+                              "id": 3
+                            },
+                            "last": {
+                              "type": "string",
+                              "id": 4
+                            },
+                            "volume": {
+                              "type": "string",
+                              "id": 5
+                            },
+                            "change": {
+                              "type": "string",
+                              "id": 6
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 28 - 0
client/hotconi/proto/market.v2.trade.recommend.pair.proto

@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+package market.v2.trade.recommend.pair; // 替换为你的包名
+
+// 定义最外层的消息类型
+message Response {
+  int32 code = 1;
+  string msg = 2;
+  string status = 3;
+  int64 ts = 4;
+  string ch = 5;
+  RecommendPair recommendpair = 6;
+}
+
+// 定义recommendpair中的消息类型
+message RecommendPair {
+  repeated PairInfo listList = 1; // 使用repeated关键字表示数组
+}
+
+// 定义PairInfo消息类型
+message PairInfo {
+  int32 tradeId = 1;
+  string cny = 2; // 假设cny是浮点数
+  string totalamount = 3; // 假设totalamount是浮点数
+  string last = 4; // 假设last是浮点数
+  string volume = 5; // 假设volume是浮点数
+  string change = 6; // 假设change是浮点数
+}

+ 8 - 0
client/hotconi/proto/readme.md

@@ -0,0 +1,8 @@
+```js
+JSON.stringify(obj, (key, value) => {
+    if (value === undefined) {
+        return null
+    }
+    return value
+})
+```

+ 1 - 0
client/tmp/readme.md

@@ -0,0 +1 @@
+临时文件目录。

+ 2 - 0
common/utils.js

@@ -1,4 +1,6 @@
 // document.cookie
+const fs = require('fs')
+const path = require('node:path')
 
 function cookieToJSON (cookieString) {
     // 分割多个cookie

+ 567 - 4
package-lock.json

@@ -15,15 +15,18 @@
         "debug": "~2.6.9",
         "ejs": "~3.1.10",
         "express": "~5.0.0",
+        "google-protobuf": "^3.21.4",
         "http-errors": "~1.6.3",
         "morgan": "~1.9.1",
         "pako": "^2.1.0",
+        "protobufjs": "^7.4.0",
         "selenium-webdriver": "^4.26.0",
         "stylus": "0.54.5"
       },
       "devDependencies": {
         "@jest/globals": "^29.7.0",
-        "jest": "^29.7.0"
+        "jest": "^29.7.0",
+        "protobufjs-cli": "^1.1.3"
       }
     },
     "node_modules/@ampproject/remapping": {
@@ -923,6 +926,72 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@jsdoc/salty": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmmirror.com/@jsdoc/salty/-/salty-0.2.8.tgz",
+      "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.21"
+      },
+      "engines": {
+        "node": ">=v12.0.0"
+      }
+    },
+    "node_modules/@protobufjs/aspromise": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+    },
+    "node_modules/@protobufjs/base64": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz",
+      "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+    },
+    "node_modules/@protobufjs/codegen": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+      "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+    },
+    "node_modules/@protobufjs/eventemitter": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+    },
+    "node_modules/@protobufjs/fetch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.1",
+        "@protobufjs/inquire": "^1.1.0"
+      }
+    },
+    "node_modules/@protobufjs/float": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+    },
+    "node_modules/@protobufjs/inquire": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+    },
+    "node_modules/@protobufjs/path": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+    },
+    "node_modules/@protobufjs/pool": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+    },
+    "node_modules/@protobufjs/utf8": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+    },
     "node_modules/@sinclair/typebox": {
       "version": "0.27.8",
       "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -1031,11 +1100,32 @@
         "@types/istanbul-lib-report": "*"
       }
     },
+    "node_modules/@types/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+      "dev": true
+    },
+    "node_modules/@types/markdown-it": {
+      "version": "14.1.2",
+      "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+      "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+      "dev": true,
+      "dependencies": {
+        "@types/linkify-it": "^5",
+        "@types/mdurl": "^2"
+      }
+    },
+    "node_modules/@types/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+      "dev": true
+    },
     "node_modules/@types/node": {
       "version": "22.9.0",
       "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.9.0.tgz",
       "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
-      "devOptional": true,
       "dependencies": {
         "undici-types": "~6.19.8"
       }
@@ -1082,6 +1172,27 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/acorn": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
     "node_modules/agent-base": {
       "version": "7.1.1",
       "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.1.tgz",
@@ -1358,6 +1469,12 @@
         "node": ">=10.0.0"
       }
     },
+    "node_modules/bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
     "node_modules/body-parser": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.0.2.tgz",
@@ -1617,6 +1734,18 @@
         }
       ]
     },
+    "node_modules/catharsis": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmmirror.com/catharsis/-/catharsis-0.9.0.tgz",
+      "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.15"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
     "node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
@@ -2084,6 +2213,18 @@
         "once": "^1.4.0"
       }
     },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
     "node_modules/error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz",
@@ -2164,6 +2305,35 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.6.1",
+      "resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.9.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.4.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
     "node_modules/esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz",
@@ -2456,6 +2626,12 @@
       "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
       "dev": true
     },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true
+    },
     "node_modules/fb-watchman": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/fb-watchman/-/fb-watchman-2.0.2.tgz",
@@ -2796,6 +2972,11 @@
         "node": ">=4"
       }
     },
+    "node_modules/google-protobuf": {
+      "version": "3.21.4",
+      "resolved": "https://registry.npmmirror.com/google-protobuf/-/google-protobuf-3.21.4.tgz",
+      "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ=="
+    },
     "node_modules/gopd": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
@@ -3895,11 +4076,61 @@
         "js-yaml": "bin/js-yaml.js"
       }
     },
+    "node_modules/js2xmlparser": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmmirror.com/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+      "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+      "dev": true,
+      "dependencies": {
+        "xmlcreate": "^2.0.4"
+      }
+    },
     "node_modules/jsbn": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-1.1.0.tgz",
       "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
     },
+    "node_modules/jsdoc": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmmirror.com/jsdoc/-/jsdoc-4.0.4.tgz",
+      "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/parser": "^7.20.15",
+        "@jsdoc/salty": "^0.2.1",
+        "@types/markdown-it": "^14.1.1",
+        "bluebird": "^3.7.2",
+        "catharsis": "^0.9.0",
+        "escape-string-regexp": "^2.0.0",
+        "js2xmlparser": "^4.0.2",
+        "klaw": "^3.0.0",
+        "markdown-it": "^14.1.0",
+        "markdown-it-anchor": "^8.6.7",
+        "marked": "^4.0.10",
+        "mkdirp": "^1.0.4",
+        "requizzle": "^0.2.3",
+        "strip-json-comments": "^3.1.0",
+        "underscore": "~1.13.2"
+      },
+      "bin": {
+        "jsdoc": "jsdoc.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/jsdoc/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/jsesc": {
       "version": "3.0.2",
       "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz",
@@ -3957,6 +4188,15 @@
       "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
       "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
     },
+    "node_modules/klaw": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/klaw/-/klaw-3.0.0.tgz",
+      "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.9"
+      }
+    },
     "node_modules/kleur": {
       "version": "3.0.3",
       "resolved": "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz",
@@ -3975,6 +4215,19 @@
         "node": ">=6"
       }
     },
+    "node_modules/levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmmirror.com/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/lie": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz",
@@ -3989,6 +4242,15 @@
       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
       "dev": true
     },
+    "node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "dev": true,
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
     "node_modules/locate-path": {
       "version": "5.0.0",
       "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
@@ -4001,6 +4263,17 @@
         "node": ">=8"
       }
     },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true
+    },
+    "node_modules/long": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmmirror.com/long/-/long-5.2.3.tgz",
+      "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+    },
     "node_modules/lru-cache": {
       "version": "7.18.3",
       "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -4045,6 +4318,57 @@
         "tmpl": "1.0.5"
       }
     },
+    "node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
+    "node_modules/markdown-it-anchor": {
+      "version": "8.6.7",
+      "resolved": "https://registry.npmmirror.com/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
+      "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
+      "dev": true,
+      "peerDependencies": {
+        "@types/markdown-it": "*",
+        "markdown-it": "*"
+      }
+    },
+    "node_modules/markdown-it/node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/marked": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmmirror.com/marked/-/marked-4.3.0.tgz",
+      "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+      "dev": true,
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "dev": true
+    },
     "node_modules/media-typer": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.0.tgz",
@@ -4277,6 +4601,23 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/p-limit": {
       "version": "3.1.0",
       "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz",
@@ -4494,6 +4835,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/pretty-format": {
       "version": "29.7.0",
       "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-29.7.0.tgz",
@@ -4538,6 +4888,151 @@
         "node": ">= 6"
       }
     },
+    "node_modules/protobufjs": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.4.0.tgz",
+      "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@protobufjs/aspromise": "^1.1.2",
+        "@protobufjs/base64": "^1.1.2",
+        "@protobufjs/codegen": "^2.0.4",
+        "@protobufjs/eventemitter": "^1.1.0",
+        "@protobufjs/fetch": "^1.1.0",
+        "@protobufjs/float": "^1.0.2",
+        "@protobufjs/inquire": "^1.1.0",
+        "@protobufjs/path": "^1.1.2",
+        "@protobufjs/pool": "^1.1.0",
+        "@protobufjs/utf8": "^1.1.0",
+        "@types/node": ">=13.7.0",
+        "long": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/protobufjs-cli": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmmirror.com/protobufjs-cli/-/protobufjs-cli-1.1.3.tgz",
+      "integrity": "sha512-MqD10lqF+FMsOayFiNOdOGNlXc4iKDCf0ZQPkPR+gizYh9gqUeGTWulABUCdI+N67w5RfJ6xhgX4J8pa8qmMXQ==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.0.0",
+        "escodegen": "^1.13.0",
+        "espree": "^9.0.0",
+        "estraverse": "^5.1.0",
+        "glob": "^8.0.0",
+        "jsdoc": "^4.0.0",
+        "minimist": "^1.2.0",
+        "semver": "^7.1.2",
+        "tmp": "^0.2.1",
+        "uglify-js": "^3.7.7"
+      },
+      "bin": {
+        "pbjs": "bin/pbjs",
+        "pbts": "bin/pbts"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "protobufjs": "^7.0.0"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmmirror.com/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+      "dev": true,
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=4.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/escodegen/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/glob": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz",
+      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+      "deprecated": "Glob versions prior to v9 are no longer supported",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/semver": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz",
+      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/protobufjs-cli/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/proxy-addr": {
       "version": "2.0.7",
       "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -4603,6 +5098,15 @@
         "once": "^1.3.1"
       }
     },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/pure-rand": {
       "version": "6.1.0",
       "resolved": "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz",
@@ -4736,6 +5240,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/requizzle": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmmirror.com/requizzle/-/requizzle-0.2.4.tgz",
+      "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
     "node_modules/resolve": {
       "version": "1.22.8",
       "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz",
@@ -5398,6 +5911,18 @@
       "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
       "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
     },
+    "node_modules/type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/type-detect": {
       "version": "4.0.8",
       "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz",
@@ -5432,11 +5957,34 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "dev": true
+    },
+    "node_modules/uglify-js": {
+      "version": "3.19.3",
+      "resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.19.3.tgz",
+      "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+      "dev": true,
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/underscore": {
+      "version": "1.13.7",
+      "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.13.7.tgz",
+      "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+      "dev": true
+    },
     "node_modules/undici-types": {
       "version": "6.19.8",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz",
-      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
-      "devOptional": true
+      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
     },
     "node_modules/universalify": {
       "version": "2.0.1",
@@ -5543,6 +6091,15 @@
         "node": ">= 8"
       }
     },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/wrap-ansi": {
       "version": "7.0.0",
       "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -5598,6 +6155,12 @@
         }
       }
     },
+    "node_modules/xmlcreate": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmmirror.com/xmlcreate/-/xmlcreate-2.0.4.tgz",
+      "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+      "dev": true
+    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

+ 4 - 1
package.json

@@ -13,14 +13,17 @@
     "debug": "~2.6.9",
     "ejs": "~3.1.10",
     "express": "~5.0.0",
+    "google-protobuf": "^3.21.4",
     "http-errors": "~1.6.3",
     "morgan": "~1.9.1",
     "pako": "^2.1.0",
+    "protobufjs": "^7.4.0",
     "selenium-webdriver": "^4.26.0",
     "stylus": "0.54.5"
   },
   "devDependencies": {
     "@jest/globals": "^29.7.0",
-    "jest": "^29.7.0"
+    "jest": "^29.7.0",
+    "protobufjs-cli": "^1.1.3"
   }
 }

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików