From f1df509a7f92d0aef17396b96e9fe029cd74051f Mon Sep 17 00:00:00 2001 From: Daniil <8039921+DaniilSmirnov@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:34:07 +0300 Subject: [PATCH 1/5] Develop to Master for 1.5.1 (#364) * Wire initial typescript (#338) * Wire initial typescript * Fix types * Something works * Finishing touches * Linter fixes * Build problems * hotfix (#361) Co-authored-by: e.khalilov * Remove all DB connections from device side (#368) * hotfix imei * Decrease apt install list in dockerfile (#365) * remove gm and jdk11 * remove libs * Remove console-feed & react dependencies [backend only] (#366) * remove dep console-feed * minor fix * linter fix --------- Co-authored-by: e.khalilov * fix default quotas hierarchy QA-19255 (#367) * -fix quotas -fix lock -fix test -fix lint * -fix test --------- Co-authored-by: a.chistov * dev units without db conn * fix types * minor fix * minor fix * minor fix * remove useless sockets --------- Co-authored-by: Maksim Alzhanov Co-authored-by: Maxim Co-authored-by: Daniil <8039921+DaniilSmirnov@users.noreply.github.com> Co-authored-by: e.khalilov Co-authored-by: Alexey Chistov <33050834+Alk2017@users.noreply.github.com> Co-authored-by: a.chistov * fix device type & types (#374) Co-authored-by: e.khalilov * reconnect in ADBObserver (#376) Co-authored-by: e.khalilov * QA-10057 Remove users watcher groups-engine (#369) * -fix after rebase -remove user watcher -user handler for alert message default quotas handler -fix merge del handler update quoats handler user handler method some fix -move without change method of devices to separate class -fix after move users method -move db.users method to separate class * add missing db method --------- Co-authored-by: a.chistov Co-authored-by: e.khalilov * fix heartbeat (#377) Co-authored-by: e.khalilov * overrides dependencies (#378) Co-authored-by: e.khalilov * Automatic removal of disabled devices (#379) * clear dead devices * minor fix * revert api edits * revert ui (types) edits --------- Co-authored-by: e.khalilov * fix linkifyjs issue (#380) Co-authored-by: e.khalilov * Resolve conflicts (#381) * Hotfix: device imei issue (#371) * hotfix * minor fix * fix types * minor fix --------- Co-authored-by: e.khalilov * increase ram for v8 (#372) * hotfix (#373) Co-authored-by: e.khalilov * hotfix ADBObserver (#375) Co-authored-by: e.khalilov --------- Co-authored-by: e.khalilov Co-authored-by: Daniil <8039921+DaniilSmirnov@users.noreply.github.com> * Fixed transactions & minor optimizations (#382) * minor edits * fix transactions * minor fix * fix ts types --------- Co-authored-by: e.khalilov * Fix lint issues --------- Co-authored-by: Maxim Co-authored-by: Elmir Khalilov <52529096+e-khalilov@users.noreply.github.com> Co-authored-by: e.khalilov Co-authored-by: Maksim Alzhanov Co-authored-by: Alexey Chistov <33050834+Alk2017@users.noreply.github.com> Co-authored-by: a.chistov --- docker-compose-macos.yaml | 8 +- docker-compose-prod.yaml | 6 +- eslint.config.js | 18 +- google/protobuf/any.ts | 326 + lib/cli/groups-engine/index.js | 14 - lib/cli/local/index.js | 20 +- lib/cli/please.js | 2 +- lib/cli/processor/index.js | 28 - lib/cli/reaper/index.js | 12 + lib/db/api.ts | 8 +- lib/db/handlers/group/index.js | 68 +- lib/db/handlers/group/scheduler.js | 3 +- lib/db/handlers/user/index.js | 103 + lib/db/index.ts | 106 +- lib/db/models/all/model.js | 562 +- lib/db/models/device/index.js | 4 + lib/db/models/device/model.js | 138 + lib/db/models/group/model.js | 73 +- lib/db/models/user/index.js | 4 + lib/db/models/user/model.js | 446 + lib/db/proxiedModel.js | 56 - lib/db/proxiedModel.ts | 38 + lib/units/api/controllers/autotests.js | 3 +- lib/units/api/controllers/devices.js | 23 +- lib/units/api/controllers/groups.js | 10 +- lib/units/api/controllers/user.js | 68 +- lib/units/api/controllers/users.js | 64 +- lib/units/api/helpers/test.js | 11 + lib/units/api/helpers/useDevice.js | 39 +- lib/units/base-device/plugins/group.js | 155 - lib/units/base-device/plugins/group.ts | 252 + lib/units/base-device/support/connector.js | 7 +- lib/units/base-device/support/push.ts | 2 +- lib/units/base-device/support/router.js | 2 +- lib/units/device/plugins/account.js | 11 +- lib/units/device/plugins/airplane.js | 3 +- lib/units/device/plugins/bluetooth.js | 7 +- lib/units/device/plugins/browser.js | 5 +- lib/units/device/plugins/clipboard.js | 5 +- .../device/plugins/{connect.js => connect.ts} | 124 +- lib/units/device/plugins/filesystem.js | 5 +- lib/units/device/plugins/forward/index.js | 7 +- lib/units/device/plugins/group.js | 213 - lib/units/device/plugins/group.ts | 96 + lib/units/device/plugins/install.js | 5 +- lib/units/device/plugins/logcat.js | 7 +- lib/units/device/plugins/reboot.js | 3 +- lib/units/device/plugins/ringer.js | 5 +- lib/units/device/plugins/screen/capture.js | 3 +- lib/units/device/plugins/screen/stream.js | 3 +- lib/units/device/plugins/sd.js | 3 +- lib/units/device/plugins/service.ts | 28 +- lib/units/device/plugins/shell.js | 5 +- lib/units/device/plugins/solo.js | 22 +- lib/units/device/plugins/store.js | 3 +- lib/units/device/plugins/touch/index.js | 15 +- lib/units/device/plugins/vnc/index.js | 3 +- lib/units/device/plugins/wifi.js | 5 +- lib/units/device/resources/service.js | 3 +- lib/units/groups-engine/index.js | 8 +- lib/units/groups-engine/watchers/devices.js | 5 +- lib/units/groups-engine/watchers/users.js | 105 - lib/units/ios-device/plugins/clipboard.js | 3 +- lib/units/ios-device/plugins/devicelog.js | 7 +- lib/units/ios-device/plugins/filesystem.js | 5 +- lib/units/ios-device/plugins/info/index.js | 3 + lib/units/ios-device/plugins/install.js | 5 +- lib/units/ios-device/plugins/reboot.js | 3 +- lib/units/ios-device/plugins/wda/client.js | 49 +- lib/units/ios-device/plugins/wda/index.js | 29 +- lib/units/log/mongodb.js | 3 +- lib/units/poorxy/index.js | 2 +- lib/units/processor/index.js | 291 - lib/units/processor/index.ts | 328 + lib/units/provider/index.ts | 16 +- lib/units/reaper/index.js | 108 - lib/units/reaper/index.ts | 174 + lib/units/tizen-device/index.js | 3 +- lib/units/tizen-device/plugins/filesystem.js | 5 +- lib/units/tizen-device/plugins/identity.js | 3 +- lib/units/tizen-device/plugins/install.js | 5 +- lib/units/tizen-device/plugins/launcher.js | 9 +- .../plugins/webinspector/Replicator.ts | 2 - .../plugins/webinspector/index.ts | 59 +- lib/units/vnc-device/plugins/group.js | 7 +- lib/units/vnc-device/plugins/screen/stream.js | 21 +- lib/units/websocket/index.js | 119 +- lib/util/apiutil.js | 4 +- lib/util/devutil.js | 2 +- lib/util/grouputil.js | 59 - lib/util/grouputil.ts | 67 + lib/util/lifecycle.js | 68 - lib/util/lifecycle.ts | 66 + lib/util/logger.ts | 15 +- lib/util/srv.ts | 3 +- lib/util/ttlset.js | 94 - lib/util/ttlset.ts | 113 + lib/util/zmqutil.js | 70 +- lib/wire/google/protobuf/any.ts | 326 + lib/wire/index.js | 14 - lib/wire/index.ts | 35 + lib/wire/messagestream.ts | 2 +- lib/wire/router.ts | 154 +- lib/wire/transmanager.js | 57 - lib/wire/transmanager.ts | 122 + lib/wire/util.js | 63 - lib/wire/util.ts | 108 + lib/wire/wire.proto | 163 +- lib/wire/wire.ts | 11802 ++++++++++++++++ package-lock.json | 646 +- package.json | 13 +- tsconfig.json | 3 + ui/package-lock.json | 45 +- ui/package.json | 5 + ui/src/store/device-connection.ts | 4 +- ui/vite.config.ts | 8 +- 116 files changed, 15644 insertions(+), 3132 deletions(-) create mode 100644 google/protobuf/any.ts create mode 100644 lib/db/handlers/user/index.js create mode 100644 lib/db/models/device/index.js create mode 100644 lib/db/models/device/model.js create mode 100644 lib/db/models/user/index.js create mode 100644 lib/db/models/user/model.js delete mode 100644 lib/db/proxiedModel.js create mode 100644 lib/db/proxiedModel.ts create mode 100644 lib/units/api/helpers/test.js delete mode 100755 lib/units/base-device/plugins/group.js create mode 100755 lib/units/base-device/plugins/group.ts rename lib/units/device/plugins/{connect.js => connect.ts} (53%) delete mode 100644 lib/units/device/plugins/group.js create mode 100644 lib/units/device/plugins/group.ts delete mode 100644 lib/units/groups-engine/watchers/users.js delete mode 100644 lib/units/processor/index.js create mode 100644 lib/units/processor/index.ts delete mode 100644 lib/units/reaper/index.js create mode 100644 lib/units/reaper/index.ts delete mode 100644 lib/util/grouputil.js create mode 100644 lib/util/grouputil.ts delete mode 100644 lib/util/lifecycle.js create mode 100644 lib/util/lifecycle.ts delete mode 100644 lib/util/ttlset.js create mode 100644 lib/util/ttlset.ts create mode 100644 lib/wire/google/protobuf/any.ts delete mode 100644 lib/wire/index.js create mode 100644 lib/wire/index.ts delete mode 100644 lib/wire/transmanager.js create mode 100644 lib/wire/transmanager.ts delete mode 100644 lib/wire/util.js create mode 100644 lib/wire/util.ts create mode 100644 lib/wire/wire.ts diff --git a/docker-compose-macos.yaml b/docker-compose-macos.yaml index 7bf9ca00b1..f61f37477b 100644 --- a/docker-compose-macos.yaml +++ b/docker-compose-macos.yaml @@ -108,7 +108,7 @@ services: container_name: devicehub-processor env_file: - scripts/variables.env - command: stf processor --name processor --connect-app-dealer tcp://devicehub-triproxy-app:7160 --connect-dev-dealer tcp://devicehub-triproxy-dev:7260 --connect-sub tcp://devicehub-triproxy-app:7150 --connect-push tcp://devicehub-triproxy-app:7170 --connect-sub-dev tcp://devicehub-triproxy-dev:7250 --connect-push-dev tcp://devicehub-triproxy-dev:7270 + command: stf processor --name processor --connect-app-dealer tcp://devicehub-triproxy-app:7160 --connect-dev-dealer tcp://devicehub-triproxy-dev:7260 depends_on: devicehub-migrate: condition: service_completed_successfully @@ -121,7 +121,7 @@ services: container_name: devicehub-reaper env_file: - scripts/variables.env - command: stf reaper --name reaper001 --connect-push tcp://devicehub-triproxy-dev:7270 --connect-sub tcp://devicehub-triproxy-app:7150 --heartbeat-timeout 30000 + command: stf reaper --name reaper001 --connect-push tcp://devicehub-triproxy-dev:7270 --connect-sub tcp://devicehub-triproxy-dev:7250 --heartbeat-timeout 30000 depends_on: devicehub-migrate: condition: service_completed_successfully @@ -233,7 +233,7 @@ services: container_name: devicehub-api-groups-engine env_file: - scripts/variables.env - command: stf groups-engine --connect-sub tcp://devicehub-triproxy-app:7150 --connect-push tcp://devicehub-triproxy-app:7170 --connect-sub-dev tcp://devicehub-triproxy-dev:7250 --connect-push-dev tcp://devicehub-triproxy-dev:7270 + command: stf groups-engine --connect-push tcp://devicehub-triproxy-app:7170 --connect-push-dev tcp://devicehub-triproxy-dev:7270 depends_on: devicehub-migrate: condition: service_completed_successfully @@ -263,4 +263,4 @@ services: - certs:/certs:rw volumes: devicehub-db-volume: - certs: \ No newline at end of file + certs: diff --git a/docker-compose-prod.yaml b/docker-compose-prod.yaml index 0f3dd25b53..acdd35dc65 100644 --- a/docker-compose-prod.yaml +++ b/docker-compose-prod.yaml @@ -124,7 +124,7 @@ services: container_name: devicehub-processor env_file: - scripts/variables.env - command: stf processor --name processor --connect-app-dealer tcp://devicehub-triproxy-app:7160 --connect-dev-dealer tcp://devicehub-triproxy-dev:7260 --connect-sub tcp://devicehub-triproxy-app:7150 --connect-push tcp://devicehub-triproxy-app:7170 --connect-sub-dev tcp://devicehub-triproxy-dev:7250 --connect-push-dev tcp://devicehub-triproxy-dev:7270 + command: stf processor --name processor --connect-app-dealer tcp://devicehub-triproxy-app:7160 --connect-dev-dealer tcp://devicehub-triproxy-dev:7260 depends_on: devicehub-migrate: condition: service_completed_successfully @@ -137,7 +137,7 @@ services: container_name: devicehub-reaper env_file: - scripts/variables.env - command: stf reaper --name reaper001 --connect-push tcp://devicehub-triproxy-dev:7270 --connect-sub tcp://devicehub-triproxy-app:7150 --heartbeat-timeout 30000 + command: stf reaper --name reaper001 --connect-push tcp://devicehub-triproxy-dev:7270 --connect-sub tcp://devicehub-triproxy-dev:7250 --heartbeat-timeout 30000 depends_on: devicehub-migrate: condition: service_completed_successfully @@ -249,7 +249,7 @@ services: container_name: devicehub-api-groups-engine env_file: - scripts/variables.env - command: stf groups-engine --connect-sub tcp://devicehub-triproxy-app:7150 --connect-push tcp://devicehub-triproxy-app:7170 --connect-sub-dev tcp://devicehub-triproxy-dev:7250 --connect-push-dev tcp://devicehub-triproxy-dev:7270 + command: stf groups-engine --connect-push tcp://devicehub-triproxy-app:7170 --connect-push-dev tcp://devicehub-triproxy-dev:7270 depends_on: devicehub-migrate: condition: service_completed_successfully diff --git a/eslint.config.js b/eslint.config.js index 99f97b2655..02c704c90e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -51,7 +51,8 @@ export default tseslint.config( }, }, { - ignores: ['dist'], + files: ['lib/**/*.js'], + // ignores: ['dist'], languageOptions: { ecmaVersion: 2025, sourceType: 'module', @@ -213,10 +214,17 @@ export default tseslint.config( 'no-restricted-modules': 0, 'no-sync': 0, 'no-async-promise-executor': 0, + + "no-restricted-imports": ["error", { + "patterns": [{ + "regex": ".*\\.ts", + "message": "Do not import typescript files. Import them with *.js" + }] + }] }, }, { - languageOptions: { + languageOptions: { parser: tseslint.parser, parserOptions: { projectService: true, @@ -224,4 +232,10 @@ export default tseslint.config( }, }, }, + tseslint.configs.eslintRecommended, + { + rules: { + "prefer-const": "off" + } + } ) diff --git a/google/protobuf/any.ts b/google/protobuf/any.ts new file mode 100644 index 0000000000..465a591802 --- /dev/null +++ b/google/protobuf/any.ts @@ -0,0 +1,326 @@ +// @generated by protobuf-ts 2.11.1 +// @generated from protobuf file "google/protobuf/any.proto" (package "google.protobuf", syntax proto3) +// tslint:disable +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import { WireType } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import { UnknownFieldHandler } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { reflectionMergePartial } from "@protobuf-ts/runtime"; +import { isJsonObject } from "@protobuf-ts/runtime"; +import { typeofJsonValue } from "@protobuf-ts/runtime"; +import type { JsonValue } from "@protobuf-ts/runtime"; +import { jsonWriteOptions } from "@protobuf-ts/runtime"; +import type { JsonReadOptions } from "@protobuf-ts/runtime"; +import type { JsonWriteOptions } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IMessageType } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +/** + * `Any` contains an arbitrary serialized protocol buffer message along with a + * URL that describes the type of the serialized message. + * + * Protobuf library provides support to pack/unpack Any values in the form + * of utility functions or additional generated methods of the Any type. + * + * Example 1: Pack and unpack a message in C++. + * + * Foo foo = ...; + * Any any; + * any.PackFrom(foo); + * ... + * if (any.UnpackTo(&foo)) { + * ... + * } + * + * Example 2: Pack and unpack a message in Java. + * + * Foo foo = ...; + * Any any = Any.pack(foo); + * ... + * if (any.is(Foo.class)) { + * foo = any.unpack(Foo.class); + * } + * // or ... + * if (any.isSameTypeAs(Foo.getDefaultInstance())) { + * foo = any.unpack(Foo.getDefaultInstance()); + * } + * + * Example 3: Pack and unpack a message in Python. + * + * foo = Foo(...) + * any = Any() + * any.Pack(foo) + * ... + * if any.Is(Foo.DESCRIPTOR): + * any.Unpack(foo) + * ... + * + * Example 4: Pack and unpack a message in Go + * + * foo := &pb.Foo{...} + * any, err := anypb.New(foo) + * if err != nil { + * ... + * } + * ... + * foo := &pb.Foo{} + * if err := any.UnmarshalTo(foo); err != nil { + * ... + * } + * + * The pack methods provided by protobuf library will by default use + * 'type.googleapis.com/full.type.name' as the type URL and the unpack + * methods only use the fully qualified type name after the last '/' + * in the type URL, for example "foo.bar.com/x/y.z" will yield type + * name "y.z". + * + * JSON + * ==== + * The JSON representation of an `Any` value uses the regular + * representation of the deserialized, embedded message, with an + * additional field `@type` which contains the type URL. Example: + * + * package google.profile; + * message Person { + * string first_name = 1; + * string last_name = 2; + * } + * + * { + * "@type": "type.googleapis.com/google.profile.Person", + * "firstName": , + * "lastName": + * } + * + * If the embedded message type is well-known and has a custom JSON + * representation, that representation will be embedded adding a field + * `value` which holds the custom JSON in addition to the `@type` + * field. Example (for message [google.protobuf.Duration][]): + * + * { + * "@type": "type.googleapis.com/google.protobuf.Duration", + * "value": "1.212s" + * } + * + * + * @generated from protobuf message google.protobuf.Any + */ +export interface Any { + /** + * A URL/resource name that uniquely identifies the type of the serialized + * protocol buffer message. This string must contain at least + * one "/" character. The last segment of the URL's path must represent + * the fully qualified name of the type (as in + * `path/google.protobuf.Duration`). The name should be in a canonical form + * (e.g., leading "." is not accepted). + * + * In practice, teams usually precompile into the binary all types that they + * expect it to use in the context of Any. However, for URLs which use the + * scheme `http`, `https`, or no scheme, one can optionally set up a type + * server that maps type URLs to message definitions as follows: + * + * * If no scheme is provided, `https` is assumed. + * * An HTTP GET on the URL must yield a [google.protobuf.Type][] + * value in binary format, or produce an error. + * * Applications are allowed to cache lookup results based on the + * URL, or have them precompiled into a binary to avoid any + * lookup. Therefore, binary compatibility needs to be preserved + * on changes to types. (Use versioned type names to manage + * breaking changes.) + * + * Note: this functionality is not currently available in the official + * protobuf release, and it is not used for type URLs beginning with + * type.googleapis.com. As of May 2023, there are no widely used type server + * implementations and no plans to implement one. + * + * Schemes other than `http`, `https` (or the empty scheme) might be + * used with implementation specific semantics. + * + * + * @generated from protobuf field: string type_url = 1 + */ + typeUrl: string; + /** + * Must be a valid serialized protocol buffer of the above specified type. + * + * @generated from protobuf field: bytes value = 2 + */ + value: Uint8Array; +} +// @generated message type with reflection information, may provide speed optimized methods +class Any$Type extends MessageType { + constructor() { + super("google.protobuf.Any", [ + { no: 1, name: "type_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "value", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + /** + * Pack the message into a new `Any`. + * + * Uses 'type.googleapis.com/full.type.name' as the type URL. + */ + pack(message: T, type: IMessageType): Any { + return { + typeUrl: this.typeNameToUrl(type.typeName), value: type.toBinary(message), + }; + } + /** + * Unpack the message from the `Any`. + */ + unpack(any: Any, type: IMessageType, options?: Partial): T { + if (!this.contains(any, type)) + throw new Error("Cannot unpack google.protobuf.Any with typeUrl '" + any.typeUrl + "' as " + type.typeName + "."); + return type.fromBinary(any.value, options); + } + /** + * Does the given `Any` contain a packed message of the given type? + */ + contains(any: Any, type: IMessageType | string): boolean { + if (!any.typeUrl.length) + return false; + let wants = typeof type == "string" ? type : type.typeName; + let has = this.typeUrlToName(any.typeUrl); + return wants === has; + } + /** + * Convert the message to canonical JSON value. + * + * You have to provide the `typeRegistry` option so that the + * packed message can be converted to JSON. + * + * The `typeRegistry` option is also required to read + * `google.protobuf.Any` from JSON format. + */ + internalJsonWrite(any: Any, options: JsonWriteOptions): JsonValue { + if (any.typeUrl === "") + return {}; + let typeName = this.typeUrlToName(any.typeUrl); + let opt = jsonWriteOptions(options); + let type = opt.typeRegistry?.find(t => t.typeName === typeName); + if (!type) + throw new globalThis.Error("Unable to convert google.protobuf.Any with typeUrl '" + any.typeUrl + "' to JSON. The specified type " + typeName + " is not available in the type registry."); + let value = type.fromBinary(any.value, { readUnknownField: false }); + let json = type.internalJsonWrite(value, opt); + if (typeName.startsWith("google.protobuf.") || !isJsonObject(json)) + json = { value: json }; + json["@type"] = any.typeUrl; + return json; + } + internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Any): Any { + if (!isJsonObject(json)) + throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON " + typeofJsonValue(json) + "."); + if (typeof json["@type"] != "string" || json["@type"] == "") + return this.create(); + let typeName = this.typeUrlToName(json["@type"]); + let type = options?.typeRegistry?.find(t => t.typeName == typeName); + if (!type) + throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON. The specified type " + typeName + " is not available in the type registry."); + let value; + if (typeName.startsWith("google.protobuf.") && json.hasOwnProperty("value")) + value = type.fromJson(json["value"], options); + else { + let copy = Object.assign({}, json); + delete copy["@type"]; + value = type.fromJson(copy, options); + } + if (target === undefined) + target = this.create(); + target.typeUrl = json["@type"]; + target.value = type.toBinary(value); + return target; + } + typeNameToUrl(name: string): string { + if (!name.length) + throw new Error("invalid type name: " + name); + return "type.googleapis.com/" + name; + } + typeUrlToName(url: string): string { + if (!url.length) + throw new Error("invalid type url: " + url); + let slash = url.lastIndexOf("/"); + let name = slash > 0 ? url.substring(slash + 1) : url; + if (!name.length) + throw new Error("invalid type url: " + url); + return name; + } + create(value?: PartialMessage): Any { + const message = globalThis.Object.create((this.messagePrototype!)); + message.typeUrl = ""; + message.value = new Uint8Array(0); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Any): Any { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string type_url */ 1: + message.typeUrl = reader.string(); + break; + case /* bytes value */ 2: + message.value = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: Any, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string type_url = 1; */ + if (message.typeUrl !== "") + writer.tag(1, WireType.LengthDelimited).string(message.typeUrl); + /* bytes value = 2; */ + if (message.value.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.value); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message google.protobuf.Any + */ +export const Any = new Any$Type(); diff --git a/lib/cli/groups-engine/index.js b/lib/cli/groups-engine/index.js index 62abfefb87..e523713502 100644 --- a/lib/cli/groups-engine/index.js +++ b/lib/cli/groups-engine/index.js @@ -11,24 +11,12 @@ export const builder = function(yargs) { array: true, demand: true }) - .option('connect-sub', { - alias: 'u', - describe: 'App-side ZeroMQ PUB endpoint to connect to.', - array: true, - demand: true - }) .option('connect-push-dev', { alias: 'pd', describe: 'Device-side ZeroMQ PULL endpoint to connect to.', array: true, demand: true }) - .option('connect-sub-dev', { - alias: 'sd', - describe: 'Device-side ZeroMQ PUB endpoint to connect to.', - array: true, - demand: true - }) .epilog('Each option can be be overwritten with an environment variable ' + 'by converting the option to uppercase, replacing dashes with ' + 'underscores and prefixing it with `STF_GROUPS_ENGINE_` .)') @@ -37,9 +25,7 @@ export const handler = function(argv) { return groupsEngine({ endpoints: { push: argv.connectPush, - sub: argv.connectSub, pushdev: argv.connectPushDev, - subdev: argv.connectSubDev } }) } diff --git a/lib/cli/local/index.js b/lib/cli/local/index.js index 6fb69c93a4..83e57c0b94 100644 --- a/lib/cli/local/index.js +++ b/lib/cli/local/index.js @@ -302,6 +302,16 @@ export const builder = function(yargs) { type: 'boolean', default: true }) + .option('time-to-device-cleanup', { + describe: 'Time in seconds after which connected devices should be deleted. 0 - do not delete', + type: 'number', + default: 0 + }) + .option('device-cleanup-interval', { + describe: 'Interval for checking devices for cleanup in minutes', + type: 'number', + default: 120_000 + }) .epilog('Each option can be be overwritten with an environment variable ' + 'by converting the option to uppercase, replacing dashes with ' + 'underscores and prefixing it with `STF_LOCAL_` (e.g. ' + @@ -338,16 +348,14 @@ export const handler = function(argv) { 'processor', 'proc001', '--connect-app-dealer', argv.bindAppDealer, '--connect-dev-dealer', argv.bindDevDealer, - '--connect-push', argv.bindAppPull, - '--connect-push-dev', argv.bindDevPull, - '--connect-sub', argv.bindAppPub, - '--connect-sub-dev', argv.bindDevPub, '--public-ip', argv.publicIp ], [ // reaper one 'reaper', 'reaper001', '--connect-push', argv.bindDevPull, - '--connect-sub', argv.bindAppPub + '--connect-sub', argv.bindDevPub, + '--time-to-device-cleanup', argv.timeToDeviceCleanup, + '--device-cleanup-interval', argv.deviceCleanupInterval ], [ // provider 'provider', @@ -412,9 +420,7 @@ export const handler = function(argv) { [ // groups engine 'groups-engine', '--connect-push', argv.bindAppPull, - '--connect-sub', argv.bindAppPub, '--connect-push-dev', argv.bindDevPull, - '--connect-sub-dev', argv.bindDevPub ], [ // websocket 'websocket', diff --git a/lib/cli/please.js b/lib/cli/please.js index 68fcf377f6..1c513326fd 100644 --- a/lib/cli/please.js +++ b/lib/cli/please.js @@ -1 +1 @@ -import './index.ts' +import './index.js' diff --git a/lib/cli/processor/index.js b/lib/cli/processor/index.js index 5092bc1ba5..a420e9e587 100644 --- a/lib/cli/processor/index.js +++ b/lib/cli/processor/index.js @@ -18,30 +18,6 @@ export const builder = function(yargs) { array: true, demand: true }) - .option('connect-push', { - alias: 'c', - describe: 'App-side ZeroMQ PULL endpoint to connect to.', - array: true, - demand: true - }) - .option('connect-push-dev', { - alias: 'pd', - describe: 'Device-side ZeroMQ PULL endpoint to connect to.', - array: true, - demand: true - }) - .option('connect-sub', { - alias: 'u', - describe: 'App-side ZeroMQ PUB endpoint to connect to.', - array: true, - demand: true - }) - .option('connect-sub-dev', { - alias: 'sd', - describe: 'Device-side ZeroMQ PUB endpoint to connect to.', - array: true, - demand: true - }) .option('name', { describe: 'An easily identifiable name for log output.', type: 'string', @@ -64,10 +40,6 @@ export const handler = function(argv) { endpoints: { appDealer: argv.connectAppDealer, devDealer: argv.connectDevDealer, - push: argv.connectPush, - pushdev: argv.connectPushDev, - sub: argv.connectSub, - subdev: argv.connectSubDev }, publicIp: argv.publicIp }) diff --git a/lib/cli/reaper/index.js b/lib/cli/reaper/index.js index 651889b528..b741bc2214 100644 --- a/lib/cli/reaper/index.js +++ b/lib/cli/reaper/index.js @@ -30,6 +30,16 @@ export const builder = function(yargs) { type: 'string', default: os.hostname() }) + .option('time-to-device-cleanup', { + describe: 'Time in minutes after which connected devices should be deleted. 0 - do not delete', + type: 'number', + default: 0 + }) + .option('device-cleanup-interval', { + describe: 'Interval for checking devices for cleanup in minutes', + type: 'number', + default: 2 + }) .epilog('Each option can be be overwritten with an environment variable ' + 'by converting the option to uppercase, replacing dashes with ' + 'underscores and prefixing it with `STF_REAPER_` (e.g. ' + @@ -39,6 +49,8 @@ export const handler = function(argv) { return reaper({ name: argv.name, heartbeatTimeout: argv.heartbeatTimeout, + timeToDeviceCleanup: argv.timeToDeviceCleanup, + deviceCleanupInterval: argv.deviceCleanupInterval, endpoints: { push: argv.connectPush, sub: argv.connectSub diff --git a/lib/db/api.ts b/lib/db/api.ts index 1e2e3acaab..5200126262 100644 --- a/lib/db/api.ts +++ b/lib/db/api.ts @@ -1,6 +1,8 @@ import AllModel from './models/all/index.js' import GroupModel from './models/group/index.js' import TeamModel from './models/team/index.js' +import UserModel from './models/user/index.js' +import DeviceModel from './models/device/index.js' const concatModels = (...models: T) => Object.assign({}, ...models) @@ -12,5 +14,7 @@ const concatModels = (...models: T) => export default concatModels( AllModel, GroupModel, - TeamModel -) as typeof AllModel & typeof GroupModel & typeof TeamModel + TeamModel, + UserModel, + DeviceModel, +) as typeof AllModel & typeof GroupModel & typeof TeamModel & typeof UserModel & typeof DeviceModel diff --git a/lib/db/handlers/group/index.js b/lib/db/handlers/group/index.js index 7e540ad9be..74e7a8b92a 100644 --- a/lib/db/handlers/group/index.js +++ b/lib/db/handlers/group/index.js @@ -5,6 +5,7 @@ import wire from '../../../wire/index.js' import dbapi from '../../api.js' import GroupsScheduler from './scheduler.js' import {WireRouter} from '../../../wire/router.js' +import {GroupChangeMessage, GroupField, LeaveGroupMessage, UngroupMessage} from '../../../wire/wire.js' class GroupChangeHandler { @@ -31,12 +32,13 @@ class GroupChangeHandler { this.scheduler?.scheduleAllGroupsTasks() this.push.send([ channel, - wireutil.envelope(new wire.UngroupMessage(wireutil.toDeviceRequirements({ - serial: { - value: serial, - match: 'exact' - } - }))) + wireutil.pack(UngroupMessage, { + requirements: wireutil.toDeviceRequirements({ + serial: { + value: serial, + match: 'exact' + } + })}) ]) } @@ -50,32 +52,32 @@ class GroupChangeHandler { this.pushdev.send([ wireutil.global, - wireutil.envelope(new wire.GroupChangeMessage( - new wire.GroupField( - group.id - , group.name - , group.class - , group.privilege - , group.owner - , dates - , group.duration - , group.repetitions - , group.devices - , group.users - , group.state - , group.isActive - , group.moderators - ) - , action - , subscribers - , isChangedDates - , isChangedClass - , isAddedUser - , users - , isAddedDevice - , devices - , timeutil.now('nano') - )) + wireutil.pack(GroupChangeMessage, { + group: GroupField.create({ + id: group.id, + name: group.name, + class: group.class, + privilege: group.privilege, + owner: group.owner, + dates: dates, + duration: group.duration, + repetitions: group.repetitions, + devices: group.devices, + users: group.users, + state: group.state, + isActive: group.isActive, + moderators: group.moderators, + }), + action: action, + subscribers: subscribers, + isChangedDates: isChangedDates, + isChangedClass: isChangedClass, + isAddedUser: isAddedUser, + users: users, + isAddedDevice: isAddedDevice, + devices: devices, + timeStamp: timeutil.now('nano') + }) ]) } @@ -152,7 +154,7 @@ class GroupChangeHandler { } const listener = new WireRouter() - .on(wire.LeaveGroupMessage, (channel, message) => { + .on(LeaveGroupMessage, (channel, message) => { if (message.serial === serial && message.owner.email === email) { clearTimeout(responseTimer) diff --git a/lib/db/handlers/group/scheduler.js b/lib/db/handlers/group/scheduler.js index 3ac71e199b..ddfbca40f6 100644 --- a/lib/db/handlers/group/scheduler.js +++ b/lib/db/handlers/group/scheduler.js @@ -5,6 +5,7 @@ import db from '../../index.js' import logger from '../../../util/logger.js' import mongo from 'mongodb' +import UserModel from '../../models/user/index.js' const log = logger.createLogger('groups-scheduler') @@ -211,7 +212,7 @@ export default class GroupsScheduler { await dbapi.updateDevicesCurrentGroupFromOrigin(group.devices) } - await dbapi.updateUserGroupDuration(group.owner.email, group.duration, duration) + await UserModel.updateUserGroupDuration(group.owner.email, group.duration, duration) await this.scheduleAllGroupsTasks() } catch (err) { diff --git a/lib/db/handlers/user/index.js b/lib/db/handlers/user/index.js new file mode 100644 index 0000000000..132d9a35a0 --- /dev/null +++ b/lib/db/handlers/user/index.js @@ -0,0 +1,103 @@ +import _ from 'lodash' +import logger from '../../../util/logger.js' +import wireutil from '../../../wire/util.js' +import wire from '../../../wire/index.js' +import timeutil from '../../../util/timeutil.js' + +class UserChangeHandler { + + isPrepared = false + log = logger.createLogger('change-handler-users') + + init(push, pushdev, channelRouter) { + this.pushdev = pushdev + this.isPrepared = !!this.pushdev + } + + sendUserChange = (user, isAddedGroup, groups, action, targets) => { + function wireUserField() { + const wireUser = _.cloneDeep(user) + delete wireUser._id + delete wireUser.ip + delete wireUser.group + delete wireUser.lastLoggedInAt + delete wireUser.createdAt + delete wireUser.forwards + delete wireUser.acceptedPolicy + delete wireUser.groups.lock + delete wireUser.groups.defaultGroupsDuration + delete wireUser.groups.defaultGroupsNumber + delete wireUser.groups.defaultGroupsRepetitions + delete wireUser.groups.repetitions + return wireUser + } + const userField = wireUserField() + this.pushdev.send([ + wireutil.global, + wireutil.envelope(new wire.UserChangeMessage( + userField + , isAddedGroup + , groups + , action + , targets + , timeutil.now('nano') + )) + ]) + } + + updateUserHandler = (oldUser, newUser) => { + if (newUser === null && oldUser === null) { + this.log.info('New user doc and old user doc is NULL') + return false + } + const targets = [] + if (newUser?.groups && oldUser?.groups) { + if (newUser.groups.quotas && oldUser.groups.quotas) { + if (!_.isEqual(newUser.groups.quotas.allocated, oldUser.groups.quotas.allocated)) { + targets.push('settings') + targets.push('view') + } + else if (!_.isEqual(newUser.groups.quotas.consumed, oldUser.groups.quotas.consumed)) { + targets.push('view') + } + else if (newUser.groups.quotas.defaultGroupsNumber !== + oldUser.groups.quotas.defaultGroupsNumber || + newUser.groups.quotas.defaultGroupsDuration !== + oldUser.groups.quotas.defaultGroupsDuration || + newUser.groups.quotas.defaultGroupsRepetitions !== + oldUser.groups.quotas.defaultGroupsRepetitions || + newUser.groups.quotas.repetitions !== + oldUser.groups.quotas.repetitions || + !_.isEqual(newUser.groups.subscribed, oldUser.groups.subscribed)) { + targets.push('settings') + } + } + } + if (!_.isEqual(newUser?.settings.alertMessage, oldUser?.settings.alertMessage)) { + targets.push('menu') + } + if (targets.length) { + this.sendUserChange(newUser, newUser.groups.subscribed.length > oldUser.groups.subscribed.length + , _.xor(newUser.groups.subscribed, oldUser.groups.subscribed), 'updated', targets) + } + return !_.isEqual(newUser, oldUser) + } + +} + +// Temporary solution needed to avoid situations +// where a unit may not initialize the change handler, +// but use the db module. In this case, any methods of this handler +// do nothing and will not cause an error. +/** @type {UserChangeHandler} */ +export default new Proxy(new UserChangeHandler(), { + + /** @param {string} prop */ + get(target, prop) { + if (target.isPrepared || prop === 'init' || typeof target[prop] !== 'function') { + return target[prop] + } + + return () => {} + } +}) diff --git a/lib/db/index.ts b/lib/db/index.ts index 26b6eec7d5..8e3ab3b1bf 100644 --- a/lib/db/index.ts +++ b/lib/db/index.ts @@ -3,6 +3,7 @@ import _setup from './setup.js' import srv from '../util/srv.js' import EventEmitter from 'events' import GroupChangeHandler from './handlers/group/index.js' +import UserChangeHandler from './handlers/user/index.js' import * as zmqutil from '../util/zmqutil.js' import lifecycle from '../util/lifecycle.js' import logger from '../util/logger.js' @@ -27,7 +28,7 @@ const handlers: { channelRouter?: EventEmitter ) => Promise | void; isPrepared: boolean; -}[] = [GroupChangeHandler] +}[] = [GroupChangeHandler, UserChangeHandler] export default class DbClient { static connection: mongo.Db @@ -117,21 +118,18 @@ export default class DbClient { pushdev, channelRouter, }: { - sub: SocketWrapper | string[]; - subdev: SocketWrapper | string[]; + sub?: SocketWrapper | string[]; + subdev?: SocketWrapper | string[]; push: SocketWrapper | string[]; pushdev: SocketWrapper | string[]; channelRouter?: EventEmitter; }, _log: ReturnType | undefined = log - ): Promise<{ - sub: SocketWrapper; - subdev: SocketWrapper; - push: SocketWrapper; - pushdev: SocketWrapper; - channelRouter: EventEmitter; - }> { - if (Array.isArray(sub)) { + ) { + let finalSub: SocketWrapper | undefined + let finalSubdev: SocketWrapper | undefined + + if (sub && Array.isArray(sub)) { const _sub = zmqutil.socket('sub') await Promise.all( sub.map(async(endpoint) => { @@ -148,15 +146,18 @@ export default class DbClient { ) } catch (err) { - _log.fatal('Unable to connect to sub endpoint', err) + _log.fatal('Unable to connect to sub endpoint: %s', err) lifecycle.fatal() } }) ) - sub = _sub + finalSub = _sub + } + else if (sub) { + finalSub = sub as SocketWrapper } - if (Array.isArray(subdev)) { + if (subdev && Array.isArray(subdev)) { const _subdev = zmqutil.socket('sub') await Promise.all( subdev.map(async(endpoint) => { @@ -173,17 +174,20 @@ export default class DbClient { ) } catch (err) { - _log.fatal('Unable to connect to subdev endpoint', err) + _log.fatal('Unable to connect to subdev endpoint: %s', err) lifecycle.fatal() } }) ) - subdev = _subdev + finalSubdev = _subdev + } + else if (subdev) { + finalSubdev = subdev as SocketWrapper } if (Array.isArray(push)) { const _push = zmqutil.socket('push') - Promise.all( + await Promise.all( push.map(async(endpoint) => { try { srv.attempt( @@ -195,7 +199,7 @@ export default class DbClient { ) } catch (err) { - _log.fatal('Unable to connect to push endpoint', err) + _log.fatal('Unable to connect to push endpoint: %s', err) lifecycle.fatal() } }) @@ -205,7 +209,7 @@ export default class DbClient { if (Array.isArray(pushdev)) { const _pushdev = zmqutil.socket('push') - Promise.all( + await Promise.all( pushdev.map(async(endpoint) => { try { srv.attempt( @@ -218,7 +222,7 @@ export default class DbClient { } catch (err) { _log.fatal( - 'Unable to connect to pushdev endpoint', + 'Unable to connect to pushdev endpoint: %s', err ) lifecycle.fatal() @@ -229,23 +233,48 @@ export default class DbClient { } if (!channelRouter) { - channelRouter = new EventEmitter(); - [wireutil.global].forEach((channel) => { - _log.info('Subscribing to permanent channel "%s"', channel) - sub.subscribe(channel) - subdev.subscribe(channel) - }) + channelRouter = new EventEmitter() - sub.on('message', (channel, data) => { - channelRouter?.emit(channel.toString(), channel, data) - }) + if (finalSub || finalSubdev) { + ;[wireutil.global].forEach((channel) => { + _log.info('Subscribing to permanent channel "%s"', channel) + if (finalSub) { + finalSub.subscribe(channel) + } + if (finalSubdev) { + finalSubdev.subscribe(channel) + } + }) - subdev.on('message', (channel, data) => { - channelRouter?.emit(channel.toString(), channel, data) - }) + if (finalSub) { + finalSub.on('message', (channel, data) => { + channelRouter?.emit(channel.toString(), channel, data) + }) + } + + if (finalSubdev) { + finalSubdev.on('message', (channel, data) => { + channelRouter?.emit(channel.toString(), channel, data) + }) + } + } + } + + const result: { + sub?: SocketWrapper; + subdev?: SocketWrapper; + push: SocketWrapper; + pushdev: SocketWrapper; + channelRouter: EventEmitter; + } = { + push, + pushdev, + channelRouter, + ... !!finalSub && {sub: finalSub}, + ... !!finalSubdev && {subdev: finalSubdev} } - return {sub, subdev, push, pushdev, channelRouter} + return result } // Verifies that we can form a connection. Useful if it's necessary to make @@ -254,12 +283,11 @@ export default class DbClient { // an issue with the processor unit, as it started processing messages before // it was actually truly able to save anything to the database. This lead to // lost messages in certain situations. - static ensureConnectivity = (fn: Function) => - function() { - let args = [].slice.call(arguments) - return DbClient.connect().then(function() { - return fn.apply(null, args) - }) + static ensureConnectivity = any>(fn: T) => + async(...args: Parameters): Promise> => { + await DbClient.connect(); + log.info("Db is up"); + return fn(...args); } // Sets up the database diff --git a/lib/db/models/all/model.js b/lib/db/models/all/model.js index 06676a9407..327a2427a9 100644 --- a/lib/db/models/all/model.js +++ b/lib/db/models/all/model.js @@ -8,7 +8,8 @@ import wireutil from '../../../wire/util.js' import {v4 as uuidv4} from 'uuid' import * as apiutil from '../../../util/apiutil.js' import GroupModel from '../group/index.js' - +import UserModel from '../user/index.js' +import DeviceModel from '../device/index.js' import logger from '../../../util/logger.js' import {getRootGroup, getGroup} from '../group/model.js' @@ -51,7 +52,7 @@ export const unlockBookingObjects = function() { $set: {'group.lock': false} } ), - db.collection('groups').updateMany( + db.groups.updateMany( {}, { $set: { @@ -74,7 +75,7 @@ export const createBootStrap = function(env) { const now = Date.now() function updateUsersForMigration(group) { - return getUsers().then(function(users) { + return UserModel.getUsers().then(function(users) { return Promise.all(users.map(async(user) => { const data = { privilege: user?.email !== group?.owner.email ? apiutil.USER : apiutil.ADMIN, @@ -161,7 +162,7 @@ export const createBootStrap = function(env) { envUserGroupsRepetitions: apiutil.MAX_USER_GROUPS_REPETITIONS }) .then(function(group) { - return saveUserAfterLogin({ + return UserModel.saveUserAfterLogin({ name: group?.owner.name, email: group?.owner.email, ip: '127.0.0.1' @@ -173,47 +174,11 @@ export const createBootStrap = function(env) { return updateDevicesForMigration(group) }) .then(function() { - return reserveUserGroupInstance(group?.owner?.email) + return UserModel.reserveUserGroupInstance(group?.owner?.email) }) }) } -// dbapi.deleteDevice = function(serial) { -export const deleteDevice = function(serial) { - return db.devices.deleteOne({serial: serial}) -} - -export const deleteUser = function(email) { - return db.users.deleteOne({email: email}) -} - -// dbapi.getUsers = function() { -export const getUsers = function() { - return db.users.find().toArray() -} - -// dbapi.getEmails = function() { -export const getEmails = function() { - return db.users - .find({ - privilege: { - $ne: apiutil.ADMIN - } - }) - .project({email: 1, _id: 0}) - .toArray() -} - -// dbapi.getAdmins = function() { -export const getAdmins = function() { - return db.users - .find({ - privilege: apiutil.ADMIN - }) - .project({email: 1, _id: 0}) - .toArray() -} - export const lockDeviceByCurrent = function(groups, serial) { function wrappedlockDeviceByCurrent() { return db.devices.findOne({serial: serial}).then(oldDoc => { @@ -350,39 +315,10 @@ export const setLockOnDevices = function(serials, lock) { ) } -/** - * @deprecated Do not use locks in database. - */ -function setLockOnUser(email, state) { - return db.users.findOne({email: email}).then(oldDoc => { - if (!oldDoc || !oldDoc.groups) { - throw new Error(`User with email ${email} not found or groups field is missing.`) - } - return db.users.updateOne( - {email: email}, - { - $set: { - 'groups.lock': oldDoc.groups.lock !== state ? state : oldDoc.groups.lock - } - } - ) - .then(updateStats => { - return db.users.findOne({email: email}).then(newDoc => { - // @ts-ignore - updateStats.changes = [ - {new_val: {...newDoc}, old_val: {...oldDoc}} - ] - return updateStats - }) - }) - }) -} - - // dbapi.lockUser = function(email) { export const lockUser = function(email) { function wrappedlockUser() { - return setLockOnUser(email, true) + return UserModel.setLockOnUser(email, true) .then(function(stats) { return apiutil.lockResult(stats) }) @@ -396,7 +332,7 @@ export const lockUser = function(email) { // dbapi.unlockUser = function(email) { export const unlockUser = function(email) { - return setLockOnUser(email, false) + return UserModel.setLockOnUser(email, false) } // dbapi.isDeviceBooked = function(serial) { @@ -405,192 +341,6 @@ export const isDeviceBooked = function(serial) { .then(groups => !!groups?.length) } -// dbapi.createUser = function(email, name, ip) { -export const createUser = function(email, name, ip, privilege) { - return GroupModel.getRootGroup().then(function(group) { - return loadUser(group?.owner.email).then(function(adminUser) { - let userObj = { - email: email, - name: name, - ip: ip, - group: wireutil.makePrivateChannel(), - lastLoggedInAt: getNow(), - createdAt: getNow(), - forwards: [], - settings: {}, - acceptedPolicy: false, - privilege: privilege || (adminUser ? apiutil.USER : apiutil.ADMIN), - groups: { - subscribed: [], - lock: false, - quotas: { - allocated: { - number: adminUser ? adminUser.groups.quotas.defaultGroupsNumber : group?.envUserGroupsNumber, - duration: adminUser ? adminUser.groups.quotas.defaultGroupsDuration : group?.envUserGroupsDuration - }, - consumed: { - number: 0, - duration: 0 - }, - defaultGroupsNumber: adminUser ? 0 : group?.envUserGroupsNumber, - defaultGroupsDuration: adminUser ? 0 : group?.envUserGroupsDuration, - defaultGroupsRepetitions: adminUser ? 0 : group?.envUserGroupsRepetitions, - repetitions: adminUser ? adminUser.groups.quotas.defaultGroupsRepetitions : group?.envUserGroupsRepetitions - } - } - } - return db.users.insertOne(userObj) - .then(function(stats) { - if (stats.insertedId) { - return GroupModel.addGroupUser(group?.id, email).then(function() { - return loadUser(email).then(function(user) { - // @ts-ignore - stats.changes = [ - {new_val: {...user}} - ] - return stats - }) - }) - } - return stats - }) - }) - }) -} - -// dbapi.saveUserAfterLogin = function(user) { -export const saveUserAfterLogin = function(user) { - const updateData = { - name: user?.name, - ip: user?.ip, - lastLoggedInAt: getNow() - } - - if (user?.privilege) { - updateData.privilege = user?.privilege - } - - return db.users.updateOne({email: user?.email}, {$set: updateData}) - // @ts-ignore - .then(stats => { - if (stats.modifiedCount === 0) { - return createUser(user?.email, user?.name, user?.ip, user?.privilege) - } - return stats - }) -} - -// dbapi.loadUser = function(email) { -export const loadUser = function(email) { - return db.users.findOne({email: email}) -} - -// dbapi.updateUsersAlertMessage = function(alertMessage) { -export const updateUsersAlertMessage = function(alertMessage) { - return db.users.updateOne( - { - email: apiutil.STF_ADMIN_EMAIL - } - , { - $set: Object.fromEntries(Object.entries(alertMessage).map(([key, value]) => - ['settings.alertMessage.' + key, value] - )), - } - ).then(updateStats => { - return db.users.findOne({email: apiutil.STF_ADMIN_EMAIL}).then(updatedMainAdmin => { - // @ts-ignore - updateStats.changes = [ - {new_val: {...updatedMainAdmin}} - ] - return updateStats - }) - }) -} - -// dbapi.updateUserSettings = function(email, changes) { -export const updateUserSettings = function(email, changes) { - return db.users.findOne({email: email}).then(user => { - return db.users.updateOne( - { - email: email - } - , { - $set: { - settings: {...user?.settings, ...changes} - } - } - ) - }) -} - -// dbapi.resetUserSettings = function(email) { -export const resetUserSettings = function(email) { - return db.users.updateOne({email: email}, - { - $set: { - settings: {} - } - }) -} - -// dbapi.insertUserAdbKey = function(email, key) { -export const insertUserAdbKey = function(email, key) { - let data = { - title: key.title, - fingerprint: key.fingerprint - } - return db.users.findOne({email: email}).then(user => { - let adbKeys = user?.adbKeys ? user?.adbKeys : [] - adbKeys.push(data) - return db.users.updateOne( - {email: email} - , {$set: {adbKeys: user?.adbKeys ? adbKeys : [data]}} - ) - }) -} - -// dbapi.deleteUserAdbKey = function(email, fingerprint) { -export const deleteUserAdbKey = function(email, fingerprint) { - return db.users.findOne({email: email}).then(user => { - return db.users.updateOne( - {email: email} - , { - $set: { - adbKeys: user?.adbKeys ? user?.adbKeys.filter(key => { - return key.fingerprint !== fingerprint - }) : [] - } - } - ) - }) -} - -// dbapi.lookupUsersByAdbKey = function(fingerprint) { -export const lookupUsersByAdbKey = function(fingerprint) { - return db.users.find({ - adbKeys: fingerprint - }).toArray() -} - -// dbapi.lookupUserByAdbFingerprint = function(fingerprint) { -export const lookupUserByAdbFingerprint = function(fingerprint) { - return db.users.find( - {adbKeys: {$elemMatch: {fingerprint: fingerprint}}} - // @ts-ignore - , {email: 1, name: 1, group: 1, _id: 0} - ).toArray() - .then(function(users) { - switch (users.length) { - case 1: - return users[0] - case 0: - return null - default: - throw new Error('Found multiple users for same ADB fingerprint') - } - }) -} - // dbapi.lookupUserByVncAuthResponse = function(response, serial) { export const lookupUserByVncAuthResponse = function(response, serial) { return db.collection('vncauth').aggregate([ @@ -628,20 +378,6 @@ export const lookupUserByVncAuthResponse = function(response, serial) { }) } -// dbapi.loadUserDevices = function(email) { -export const loadUserDevices = function(email) { - return db.users.findOne({email: email}).then(user => { - let userGroups = user?.groups.subscribed - return db.devices.find( - { - 'owner.email': email, - present: true, - 'group.id': {$in: userGroups} - } - ).toArray() - }) -} - // dbapi.saveDeviceLog = function(serial, entry) { export const saveDeviceLog = function(serial, entry) { return db.connect().then(() => @@ -824,6 +560,8 @@ export const setDeviceAbsent = function(serial) { { $set: { owner: null, + usage: null, + logs_enabled: false, present: false, presenceChangedAt: getNow() } @@ -832,27 +570,22 @@ export const setDeviceAbsent = function(serial) { } // dbapi.setDeviceUsage = function(serial, usage) { -export const setDeviceUsage = function(serial, usage) { - return db.devices.updateOne( - {serial: serial}, - { - $set: { - usage: usage, - usageChangedAt: getNow() - } - } - ) -} +export const setDeviceState = function(serial, {usage, owner, timeout}) { + const usageSet = typeof usage === 'undefined' ? {} : { + usage, usageChangedAt: getNow(), + ... !usage && {logs_enabled: false} + } -// dbapi.unsetDeviceUsage = function(serial) { -export const unsetDeviceUsage = function(serial) { return db.devices.updateOne( {serial: serial}, { $set: { - usage: null, - usageChangedAt: getNow(), - logs_enabled: false + owner, + ...usageSet, + ... typeof timeout === 'number' && { + statusChangedAt: getNow(), + bookedBefore: timeout + }, } } ) @@ -1154,21 +887,6 @@ export const loadStandardDevices = function(groups, fields) { }, fields) } -// dbapi.loadPresentDevices = function() { -export const loadPresentDevices = function() { - return db.devices.find({present: true}).toArray() -} - -// dbapi.loadDeviceBySerial = function(serial) { -export const loadDeviceBySerial = function(serial) { - return findDevice({serial: serial}) -} - -// dbapi.loadDevicesBySerials = function(serials) { -export const loadDevicesBySerials = function(serials) { - return db.devices.find({serial: {$in: serials}}).toArray() -} - // dbapi.loadDevice = function(groups, serial) { export const loadDevice = function(groups, serial) { return findDevice({ @@ -1275,33 +993,6 @@ export const loadAccessTokenByTitle = function(email, title) { return db.collection('accessTokens').findOne({email: email, title: title}) } -// dbapi.grantAdmin = function(email) { -export const grantAdmin = function(email) { - return db.users.findOneAndUpdate({email: email}, { - $set: { - privilege: apiutil.ADMIN - } - }, {returnDocument: 'after'}) -} - -// dbapi.revokeAdmin = function(email) { -export const revokeAdmin = function(email) { - return db.users.findOneAndUpdate({email: email}, { - $set: { - privilege: apiutil.USER - } - }, {returnDocument: 'after'}) -} - -// dbapi.acceptPolicy = function(email) { -export const acceptPolicy = function(email) { - return db.users.updateOne({email: email}, { - $set: { - acceptedPolicy: true - } - }) -} - // dbapi.writeStats = function(user, serial, action) { // { // event_type: string, @@ -1334,32 +1025,9 @@ export const sendEvent = function(eventType, eventDetails, linkedEntities, times }) } -// dbapi.getDevicesCount = function() { -export const getDevicesCount = function() { - return db.devices.find().count() -} - -// dbapi.getOfflineDevicesCount = function() { -export const getOfflineDevicesCount = function() { - return db.devices.find( - { - present: false - } - ).count() -} - -// dbapi.getOfflineDevices = function() { -export const getOfflineDevices = function() { - return db.devices.find( - {present: false}, - // @ts-ignore - {_id: 0, 'provider.name': 1} - ).toArray() -} - // dbapi.isPortExclusive = function(newPort) { export const isPortExclusive = function(newPort) { - return getAllocatedAdbPorts().then((ports) => { + return DeviceModel.getAllocatedAdbPorts().then((ports) => { let result = !!ports.find(port => port === newPort) return !result }) @@ -1367,7 +1035,7 @@ export const isPortExclusive = function(newPort) { // dbapi.getLastAdbPort = function() { export const getLastAdbPort = function() { - return getAllocatedAdbPorts().then((ports) => { + return DeviceModel.getAllocatedAdbPorts().then((ports) => { if (ports.length === 0) { return 0 } @@ -1375,27 +1043,6 @@ export const getLastAdbPort = function() { }) } -// dbapi.getAllocatedAdbPorts = function() { -export const getAllocatedAdbPorts = function() { - // @ts-ignore - return db.devices.find({}, {adbPort: 1, _id: 0}).toArray().then(ports => { - let result = [] - ports.forEach((port) => { - if (port.adbPort) { - let portNum - if (typeof port.adbPort === 'string') { - portNum = parseInt(port.adbPort.replace(/["']/g, ''), 10) - } - else { - portNum = port.adbPort - } - result.push(portNum) - } - }) - return result.sort((a, b) => a - b) - }) -} - // dbapi.initiallySetAdbPort = function(serial) { export const initiallySetAdbPort = function(serial) { return getFreeAdbPort() @@ -1449,29 +1096,6 @@ export const generateIndexes = function() { }) } -// dbapi.setDeviceSocketDisplay = function(data) { -export const setDeviceSocketDisplay = function(data) { - return db.devices.updateOne( - {serial: data.serial}, - { - $set: { - 'display.density': 2, - 'display.fps': 60, - 'display.id': 0, - 'display.rotation': 0, - 'display.secure': true, - 'display.size': 4.971253395080566, - 'display.xdpi': 294.9670104980469, - 'display.ydpi': 295.56298828125, - 'display.width': data.width, - 'display.height': data.height - } - } - ).then(() => { - loadDeviceBySerial(data.serial) - }) -} - // dbapi.setDeviceSocketPorts = function(data, publicIp) { export const setDeviceSocketPorts = function(data, publicIp) { return db.devices.updateOne( @@ -1535,14 +1159,6 @@ export const sizeIosDevice = function(serial, height, width, scale) { ) } -// dbapi.getDeviceDisplaySize = function(serial) { -export const getDeviceDisplaySize = function(serial) { - return db.devices.findOne({serial: serial}) - .then(result => { - return result?.display - }) -} - // TODO Check usage. Probably dead code export const setAbsentDisconnectedDevices = function() { return db.devices.updateOne( @@ -1560,7 +1176,7 @@ export const setAbsentDisconnectedDevices = function() { // dbapi.getInstalledApplications = function(message) { export const getInstalledApplications = function(message) { - return loadDeviceBySerial(message.serial) + return DeviceModel.loadDeviceBySerial(message.serial) } // dbapi.setDeviceType = function(serial, type) { @@ -1577,14 +1193,6 @@ export const setDeviceType = function(serial, type) { ) } -// dbapi.getDeviceType = function(serial) { -export const getDeviceType = function(serial) { - return db.devices.findOne({serial: serial}) - .then(result => { - return result?.deviceType - }) -} - // dbapi.initializeIosDeviceState = function(publicIp, message) { export const initializeIosDeviceState = function(publicIp, message) { const screenWsUrlPattern = @@ -1662,126 +1270,6 @@ export const initializeIosDeviceState = function(publicIp, message) { }) } -export const reserveUserGroupInstance = async(email) => { - return db.users.updateMany( - {email} - , [{ - $set: {'groups.quotas.consumed.number': { - $min: [{ - $sum: ['$groups.quotas.consumed.number', 1] - }, '$groups.quotas.allocated.number']} - } - }] - ) -} - -export const releaseUserGroupInstance = async(email) => { - return db.users.updateMany( - { - email - } - , [{ - $set: {'groups.quotas.consumed.number': { - $max: [{ - $sum: ['$groups.quotas.consumed.number', -1] - }, 0]} - } - }] - ) -} - -export const updateUserGroupDuration = async(email, oldDuration, newDuration) => { - return db.users.updateOne( - {email: email} - , [{ - $set: { - 'groups.quotas.consumed.duration': { - $cond: [ - {$lte: [{$sum: ['$groups.quotas.consumed.duration', newDuration, -oldDuration]}, '$groups.quotas.allocated.duration']}, - {$sum: ['$groups.quotas.consumed.duration', newDuration, -oldDuration]}, - '$groups.quotas.consumed.duration' - ] - } - } - }] - ) -} - -export const updateUserGroupsQuotas = async(email, duration, number, repetitions) => { - const oldDoc = await db.users.findOne({email: email}) - - const consumed = oldDoc?.groups.quotas.consumed.duration - const allocated = oldDoc?.groups.quotas.allocated.duration - const consumedNumber = oldDoc?.groups.quotas.consumed.number - const allocatedNumber = oldDoc?.groups.quotas.allocated.number - - const updateStats = await db.users.updateOne( - {email: email} - , { - $set: { - 'groups.quotas.allocated.duration': duration && consumed <= duration && - (!number || consumedNumber <= number) ? duration : allocated, - 'groups.quotas.allocated.number': number && consumedNumber <= number && - (!duration || consumed <= duration) ? number : allocatedNumber, - 'groups.quotas.repetitions': repetitions || oldDoc?.groups.quotas.repetitions - } - } - ) - - const newDoc = await db.users.findOne({email: email}) - // @ts-ignore - updateStats.changes = [ - {new_val: {...newDoc}, old_val: {...oldDoc}} - ] - - return updateStats -} - -export const updateDefaultUserGroupsQuotas = async(email, duration, number, repetitions) => { - const updateStats = await db.users.updateOne( - {email: email} - , [{ - $set: { - 'groups.quotas.defaultGroupsDuration': { - $cond: [ - { - $ne: [duration, null] - }, - duration, - '$groups.quotas.defaultGroupsDuration' - ] - }, - 'groups.quotas.defaultGroupsNumber': { - $cond: [ - { - $ne: [number, null] - }, - number, - '$groups.quotas.defaultGroupsNumber' - ] - }, - 'groups.quotas.defaultGroupsRepetitions': { - $cond: [ - { - $ne: [repetitions, null] - }, - repetitions, - '$groups.quotas.defaultGroupsRepetitions' - ] - } - } - }] - ) - - const newDoc = await db.users.findOne({email: email}) - // @ts-ignore - updateStats.changes = [ - {new_val: {...newDoc}} - ] - - return updateStats -} - export const updateDeviceGroupName = async(serial, group) => { return db.devices.updateOne( {serial: serial} @@ -1886,7 +1374,7 @@ export const updateDevicesOriginGroup = async(serial, group) => { db.devices.updateOne({serial}, update) ) - if (stats.modifiedCount) { + if (stats.modifiedCount || stats.matchedCount) { log.info( '[updateDevicesOriginGroup] Successfully updated origin group in device [serial: "%s", group: "%s", name: "%s"]', serial, diff --git a/lib/db/models/device/index.js b/lib/db/models/device/index.js new file mode 100644 index 0000000000..61ca31630b --- /dev/null +++ b/lib/db/models/device/index.js @@ -0,0 +1,4 @@ +import proxiedModel from '../../proxiedModel.js' +import * as model from './model.js' + +export default proxiedModel(model) diff --git a/lib/db/models/device/model.js b/lib/db/models/device/model.js new file mode 100644 index 0000000000..b00c715014 --- /dev/null +++ b/lib/db/models/device/model.js @@ -0,0 +1,138 @@ +/* * + * Copyright 2025 contains code contributed by V Kontakte LLC - Licensed under the Apache license 2.0 + * */ +// @ts-nocheck +import logger from '../../../util/logger.js' +import db from '../../index.js' + +const log = logger.createLogger('dbapi:device') + +/* +=========================================================== +==================== without change DB ==================== +=========================================================== +*/ + +// dbapi.loadUserDevices = function(email) { +export const loadUserDevices = function(email) { + return db.users.findOne({email: email}).then(user => { + let userGroups = user?.groups.subscribed + return db.devices.find( + { + 'owner.email': email, + present: true, + 'group.id': {$in: userGroups} + } + ).toArray() + }) +} + +// dbapi.loadPresentDevices = function() { +export const loadPresentDevices = function() { + return db.devices.find({present: true}).toArray() +} + +export const loadDeviceBySerial = function(serial) { + return db.devices.findOne({serial}) +} + +// dbapi.loadDevicesBySerials = function(serials) { +export const loadDevicesBySerials = function(serials) { + return db.devices.find({serial: {$in: serials}}).toArray() +} + +// dbapi.getDevicesCount = function() { +export const getDevicesCount = function() { + return db.devices.countDocuments() +} + +// dbapi.getOfflineDevicesCount = function() { +export const getOfflineDevicesCount = function() { + return db.devices.countDocuments( + { + present: false + } + ) +} + +// dbapi.getOfflineDevices = function() { +export const getOfflineDevices = function() { + return db.devices.find( + {present: false}, + // @ts-ignore + {_id: 0, 'provider.name': 1} + ).toArray() +} + +// dbapi.getAllocatedAdbPorts = function() { +export const getAllocatedAdbPorts = function() { + // @ts-ignore + return db.devices.find({}, {adbPort: 1, _id: 0}).toArray().then(ports => { + let result = [] + ports.forEach((port) => { + if (port.adbPort) { + let portNum + if (typeof port.adbPort === 'string') { + portNum = parseInt(port.adbPort.replace(/["']/g, ''), 10) + } + else { + portNum = port.adbPort + } + result.push(portNum) + } + }) + return result.sort((a, b) => a - b) + }) +} + +// dbapi.getDeviceDisplaySize = function(serial) { +export const getDeviceDisplaySize = function(serial) { + return db.devices.findOne({serial: serial}) + .then(result => { + return result?.display + }) +} + +// dbapi.getDeviceType = function(serial) { +export const getDeviceType = function(serial) { + return db.devices.findOne({serial: serial}) + .then(result => { + return result?.deviceType + }) +} + +export const getDeadDevice = function(time = 60_000) { + return db.devices.find( + { + present: false, + presenceChangedAt: {$lt: new Date(Date.now() - time)} + } + ).project({serial: 1, present: 1, presenceChangedAt: 1}).toArray() +} + +// dbapi.generateIndexes = function() { +export const generateIndexes = function() { + db.devices.createIndex({serial: -1}).then((result) => { + log.info('Created indexes with result - ' + result) + }) +} + +/* +==================================================================== +==================== changing DB - use handlers ==================== +==================================================================== +*/ + + +// dbapi.deleteDevice = function(serial) { +export const deleteDevice = function(serial) { + return db.devices.deleteOne({serial: serial}) +} + +/* +==================================================== +==================== deprecated ==================== +==================================================== +*/ + + diff --git a/lib/db/models/group/model.js b/lib/db/models/group/model.js index dbc836f85b..045093bc58 100644 --- a/lib/db/models/group/model.js +++ b/lib/db/models/group/model.js @@ -2,14 +2,17 @@ * Copyright 2025 contains code contributed by V Kontakte LLC - Licensed under the Apache license 2.0 * */ + import {v4 as uuidv4} from 'uuid' import db from '../../index.js' import * as apiutil from '../../../util/apiutil.js' import logger from '../../../util/logger.js' import AllModel from '../all/index.js' +import UserModel from '../user/index.js' import _ from 'lodash' import util from 'util' import GroupChangeHandler from '../../handlers/group/index.js' +import UserChangeHandler from '../../handlers/user/index.js' import {isOriginGroup} from '../../../util/apiutil.js' import mongo from 'mongodb' @@ -54,7 +57,7 @@ export const getGroups = async(filter) => { export const addGroupUser = async(id, email) => { try { - const stats = await Promise.all([ + const [group, user] = await Promise.all([ db.groups.findOneAndUpdate( { id: id @@ -66,7 +69,7 @@ export const addGroupUser = async(id, email) => { }, {returnDocument: 'before'} ), - db.users.updateOne( + db.users.findOneAndUpdate( { email: email }, @@ -78,12 +81,17 @@ export const addGroupUser = async(id, email) => { ) ]) - if (stats[0]?.id) { - GroupChangeHandler.sendGroupChange(stats[0], stats[0].users.concat([email]), false, false, true, [email], false, [], 'updated') - GroupChangeHandler.treatGroupUsersChange(stats[0], [email], stats[0].isActive, true) + if (group?.id) { + GroupChangeHandler.sendGroupChange(group, group.users.concat([email]), false, false, true, [email], false, [], 'updated') + GroupChangeHandler.treatGroupUsersChange(group, [email], group.isActive, true) } - return stats[0] && stats[1].modifiedCount === 0 ? 'unchanged ' + email : 'added ' + email + var userModifided = false + if (user) { + const newUser = await UserModel.loadUser(email) + userModifided = UserChangeHandler.updateUserHandler(user, newUser) + } + return group && !userModifided ? 'unchanged ' + email : 'added ' + email } catch (err) { if (err instanceof TypeError) { @@ -96,7 +104,7 @@ export const addGroupUser = async(id, email) => { } export const addAdminsToGroup = async(id) => { - const admins = await AllModel.getAdmins() + const admins = await UserModel.getAdmins() const group = await db.groups.findOne({id: id}) const adminsEmails = Array.from( @@ -106,19 +114,19 @@ export const addAdminsToGroup = async(id) => { const newUsers = (group?.users || []).concat(adminsEmails) - await Promise.all( - adminsEmails.map( - email => db.users.findOne({email}) - .then(user => db.users.updateOne( - {email}, - { - $set: { - 'groups.subscribed': (user?.groups?.subscribed || []).concat([id]) - } - } - )) + adminsEmails.map(async email => { + const oldUser = await UserModel.loadUser(email) + const newUser = await db.users.findOneAndUpdate( + {email}, + { + $set: { + 'groups.subscribed': (oldUser?.groups?.subscribed || []).concat([id]) + } + }, + {returnDocument: 'after'} ) - ) + UserChangeHandler.updateUserHandler(oldUser, newUser) + }) const stats = await db.groups.updateOne( @@ -152,7 +160,7 @@ export const removeGroupUser = async(id, email) => { return "Can't remove owner of group." } - const [group] = await Promise.all([ + const [group, user] = await Promise.all([ db.groups.findOneAndUpdate( {id: id} , { @@ -163,7 +171,7 @@ export const removeGroupUser = async(id, email) => { } , {returnDocument: 'after'} ), - db.users.updateOne( + db.users.findOneAndUpdate( {email: email} , { $pull: {'groups.subscribed': id} @@ -174,6 +182,11 @@ export const removeGroupUser = async(id, email) => { GroupChangeHandler.sendGroupChange(group, group?.users, false, false, false, [email], false, [], 'updated') GroupChangeHandler.treatGroupUsersChange(group, [email], group?.isActive, false) + if (user) { + const newUser = await UserModel.loadUser(email) + UserChangeHandler.updateUserHandler(user, newUser) + } + return 'deleted' } @@ -239,7 +252,7 @@ export const addGroupDevices = async(group, serials) => { } const duration = apiutil.computeDuration(group, serials.length) - const stats = await AllModel.updateUserGroupDuration(group.owner.email, group.duration, duration) + const stats = await UserModel.updateUserGroupDuration(group.owner.email, group.duration, duration) if (!stats.modifiedCount) { throw 'quota is reached' } @@ -280,7 +293,7 @@ export const addGroupDevices = async(group, serials) => { /** @returns {Promise | null>} */ export const removeGroupDevices = async(group, serials) => { const duration = apiutil.computeDuration(group, -serials.length) - await AllModel.updateUserGroupDuration(group.owner.email, group.duration, duration) + await UserModel.updateUserGroupDuration(group.owner.email, group.duration, duration) const newGroup = await db.groups.findOneAndUpdate( {id: group.id} @@ -326,7 +339,7 @@ export const getUserGroup = async(email, id) => { export const getUserGroups = async(email) => { const pipeline = {users: {$in: [email]}} - const admins = await AllModel.getAdmins() + const admins = await UserModel.getAdmins() const adminEmails = admins.map(admin => admin.email) if (!adminEmails.includes(email)) { @@ -419,7 +432,7 @@ export const getGroupAsOwnerOrAdmin = async(email, id) => { return group } - const user = await AllModel.loadUser(email) + const user = await UserModel.loadUser(email) if (user && user.privilege === apiutil.ADMIN) { return group } @@ -462,7 +475,7 @@ export const createGroup = async(data) => { /** @returns {Promise | boolean | null>} */ export const createUserGroup = async(data) => { - const stats = await AllModel.reserveUserGroupInstance(data.owner.email) + const stats = await UserModel.reserveUserGroupInstance(data.owner.email) if (!stats.modifiedCount) { log.info(`Could not reserve group for user ${data.owner.email}`) return false @@ -501,7 +514,7 @@ export const updateDeviceOriginGroup = (serial, group, signature) => /** @returns {Promise | boolean | null>} */ export const updateUserGroup = async(group, data) => { - const stats = await AllModel.updateUserGroupDuration(group.owner.email, group.duration, data.duration) + const stats = await UserModel.updateUserGroupDuration(group.owner.email, group.duration, data.duration) if (!stats.modifiedCount && !stats.matchedCount || group.duration !== data.duration) { return false } @@ -555,7 +568,7 @@ export const deleteUserGroup = async(id) => { await db.groups.deleteOne({id}) await Promise.all( - group?.users.map(email => db.groups.updateOne( + group?.users.map(email => db.users.updateOne( {email} , { $pull: {'groups.subscribed': id} @@ -563,8 +576,8 @@ export const deleteUserGroup = async(id) => { )) ) - await AllModel.releaseUserGroupInstance(group?.owner.email) - await AllModel.updateUserGroupDuration(group?.owner.email, group?.duration, 0) + await UserModel.releaseUserGroupInstance(group?.owner.email) + await UserModel.updateUserGroupDuration(group?.owner.email, group?.duration, 0) if (apiutil.isOriginGroup(group?.class)) { await AllModel.returnDevicesToRoot(group?.devices) diff --git a/lib/db/models/user/index.js b/lib/db/models/user/index.js new file mode 100644 index 0000000000..61ca31630b --- /dev/null +++ b/lib/db/models/user/index.js @@ -0,0 +1,4 @@ +import proxiedModel from '../../proxiedModel.js' +import * as model from './model.js' + +export default proxiedModel(model) diff --git a/lib/db/models/user/model.js b/lib/db/models/user/model.js new file mode 100644 index 0000000000..6513dc154c --- /dev/null +++ b/lib/db/models/user/model.js @@ -0,0 +1,446 @@ +/* * + * Copyright 2025 contains code contributed by V Kontakte LLC - Licensed under the Apache license 2.0 + * */ +import db from '../../index.js' +import * as apiutil from '../../../util/apiutil.js' +import logger from '../../../util/logger.js' + +import AllModel from '../all/index.js' +import GroupModel from '../group/index.js' +import wireutil from '../../../wire/util.js' +import UserChangeHandler from '../../handlers/user/index.js' + +const log = logger.createLogger('dbapi:user') + +/* +=========================================================== +==================== without change DB ==================== +=========================================================== +*/ + +// dbapi.getUsers = function() { +export const getUsers = function() { + return db.users.find().toArray() +} + +// dbapi.loadUser = function(email) { +export const loadUser = function(email) { + return db.users.findOne({email: email}) +} + +// dbapi.lookupUsersByAdbKey = function(fingerprint) { +export const lookupUsersByAdbKey = function(fingerprint) { + return db.users.find({ + adbKeys: fingerprint + }).toArray() +} + +// dbapi.lookupUserByAdbFingerprint = function(fingerprint) { +export const lookupUserByAdbFingerprint = function(fingerprint) { + return db.users.find( + {adbKeys: {$elemMatch: {fingerprint: fingerprint}}} + // @ts-ignore + , {email: 1, name: 1, group: 1, _id: 0} + ).toArray() + .then(function(users) { + switch (users.length) { + case 1: + return users[0] + case 0: + return null + default: + throw new Error('Found multiple users for same ADB fingerprint') + } + }) +} + +// dbapi.getEmails = function() { +export const getEmails = function() { + return db.users + .find({ + privilege: { + $ne: apiutil.ADMIN + } + }) + .project({email: 1, _id: 0}) + .toArray() +} + +// dbapi.getAdmins = function() { +export const getAdmins = function() { + return db.users + .find({ + privilege: apiutil.ADMIN + }) + .project({email: 1, _id: 0}) + .toArray() +} + +/* +==================================================================== +==================== changing DB - use handlers ==================== +==================================================================== +*/ + +// dbapi.createUser = function(email, name, ip) { +export const createUser = async(email, name, ip, privilege) => { + const rootGroup = await GroupModel.getRootGroup() + const adminUser = await loadUser(rootGroup?.owner.email) + let userObj = { + email: email, + name: name, + ip: ip, + group: wireutil.makePrivateChannel(), + lastLoggedInAt: AllModel.getNow(), + createdAt: AllModel.getNow(), + forwards: [], + settings: {}, + acceptedPolicy: false, + privilege: privilege || (adminUser ? apiutil.USER : apiutil.ADMIN), + groups: { + subscribed: [], + lock: false, + quotas: { + allocated: { + number: adminUser ? adminUser.groups.quotas.defaultGroupsNumber : rootGroup?.envUserGroupsNumber, + duration: adminUser ? adminUser.groups.quotas.defaultGroupsDuration : rootGroup?.envUserGroupsDuration + }, + consumed: { + number: 0, + duration: 0 + }, + defaultGroupsNumber: adminUser ? 0 : rootGroup?.envUserGroupsNumber, + defaultGroupsDuration: adminUser ? 0 : rootGroup?.envUserGroupsDuration, + defaultGroupsRepetitions: adminUser ? 0 : rootGroup?.envUserGroupsRepetitions, + repetitions: adminUser ? adminUser.groups.quotas.defaultGroupsRepetitions : rootGroup?.envUserGroupsRepetitions + } + } + } + const stats = await db.users.insertOne(userObj) + if (stats.insertedId) { + UserChangeHandler.sendUserChange(userObj, false, [], 'created', ['settings']) + + await GroupModel.addGroupUser(rootGroup?.id, email) + const newUser = await loadUser(email) + + // @ts-ignore + stats.changes = [ + {new_val: {...newUser}} + ] + } + return stats +} + + +// dbapi.saveUserAfterLogin = function(user) { +export const saveUserAfterLogin = function(user) { + const updateData = { + name: user?.name, + ip: user?.ip, + lastLoggedInAt: AllModel.getNow() + } + + if (user?.privilege) { + updateData.privilege = user?.privilege + } + + return db.users.updateOne({email: user?.email}, {$set: updateData}) + // @ts-ignore + .then(stats => { + if (stats.modifiedCount === 0) { + return createUser(user?.email, user?.name, user?.ip, user?.privilege) + } + return stats + }) +} + +// dbapi.updateUsersAlertMessage = function(alertMessage) { +export const updateUsersAlertMessage = async function(alertMessage) { + const oldUser = await db.users.findOne({email: apiutil.STF_ADMIN_EMAIL}) + const newUser = await db.users.findOneAndUpdate( + { + email: apiutil.STF_ADMIN_EMAIL + } + , { + $set: Object.fromEntries(Object.entries(alertMessage).map(([key, value]) => + ['settings.alertMessage.' + key, value] + )), + }, + {returnDocument: 'after'} + ) + + var userModifided = false + const userMatching = oldUser !== null + if (newUser) { + userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + } + return {modifiedCount: userModifided ? 1 : 0, matchedCount: userMatching ? 1 : 0, newUser: newUser} +} + + +// dbapi.updateUserSettings = function(email, changes) { +export const updateUserSettings = async function(email, changes) { + const oldUser = await db.users.findOne({email: email}) + const newUser = await db.users.findOneAndUpdate( + { + email: email + } + , { + $set: { + settings: {...oldUser?.settings, ...changes} + } + }, + {returnDocument: 'after'} + ) + UserChangeHandler.updateUserHandler(oldUser, newUser) +} + +// dbapi.insertUserAdbKey = function(email, key) { +export const insertUserAdbKey = function(email, key) { + let data = { + title: key.title, + fingerprint: key.fingerprint + } + return db.users.findOne({email: email}).then(user => { + let adbKeys = user?.adbKeys ? user?.adbKeys : [] + adbKeys.push(data) + return db.users.updateOne( + {email: email} + , {$set: {adbKeys: user?.adbKeys ? adbKeys : [data]}} + ) + }) +} + +// dbapi.grantAdmin = function(email) { +export const grantAdmin = function(email) { + return db.users.findOneAndUpdate({email: email}, { + $set: { + privilege: apiutil.ADMIN + } + }, {returnDocument: 'after'}) +} + +// dbapi.revokeAdmin = function(email) { +export const revokeAdmin = function(email) { + return db.users.findOneAndUpdate({email: email}, { + $set: { + privilege: apiutil.USER + } + }, {returnDocument: 'after'}) +} + +// dbapi.acceptPolicy = function(email) { +export const acceptPolicy = function(email) { + return db.users.updateOne({email: email}, { + $set: { + acceptedPolicy: true + } + }) +} + +export const reserveUserGroupInstance = async(email) => { + const oldUser = await loadUser(email) + const newUser = await db.users.findOneAndUpdate( + {email} + , [{ + $set: {'groups.quotas.consumed.number': { + $min: [{ + $sum: ['$groups.quotas.consumed.number', 1] + }, '$groups.quotas.allocated.number']} + } + }], + {returnDocument: 'after'} + ) + const userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + return {modifiedCount: userModifided ? 1 : 0} +} + +export const releaseUserGroupInstance = async(email) => { + const oldUser = await loadUser(email) + const newUser = await db.users.findOneAndUpdate( + { + email + } + , [{ + $set: {'groups.quotas.consumed.number': { + $max: [{ + $sum: ['$groups.quotas.consumed.number', -1] + }, 0]} + } + }], + {returnDocument: 'after'} + ) + const userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + return {modifiedCount: userModifided ? 1 : 0} +} + +export const updateUserGroupDuration = async(email, oldDuration, newDuration) => { + const oldUser = await loadUser(email) + const newUser = await db.users.findOneAndUpdate( + {email: email} + , [{ + $set: { + 'groups.quotas.consumed.duration': { + $cond: [ + {$lte: [{$sum: ['$groups.quotas.consumed.duration', newDuration, -oldDuration]}, '$groups.quotas.allocated.duration']}, + {$sum: ['$groups.quotas.consumed.duration', newDuration, -oldDuration]}, + '$groups.quotas.consumed.duration' + ] + } + } + }], + {returnDocument: 'after'} + ) + var userModifided = false + const userMatching = oldUser !== null + if (newUser) { + userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + } + return {modifiedCount: userModifided ? 1 : 0, matchedCount: userMatching ? 1 : 0} +} + +export const updateUserGroupsQuotas = async(email, duration, number, repetitions) => { + const oldUser = await db.users.findOne({email: email}) + + const consumed = oldUser?.groups.quotas.consumed.duration + const allocated = oldUser?.groups.quotas.allocated.duration + const consumedNumber = oldUser?.groups.quotas.consumed.number + const allocatedNumber = oldUser?.groups.quotas.allocated.number + + const newUser = await db.users.findOneAndUpdate( + {email: email} + , { + $set: { + 'groups.quotas.allocated.duration': duration && consumed <= duration && + (!number || consumedNumber <= number) ? duration : allocated, + 'groups.quotas.allocated.number': number && consumedNumber <= number && + (!duration || consumed <= duration) ? number : allocatedNumber, + 'groups.quotas.repetitions': repetitions || oldUser?.groups.quotas.repetitions + } + }, + {returnDocument: 'after'} + ) + + var userModifided = false + if (newUser) { + userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + } + + return {modifiedCount: userModifided ? 1 : 0, newUser: newUser} +} + +export const updateDefaultUserGroupsQuotas = async(email, duration, number, repetitions) => { + const oldUser = await db.users.findOne({email: email}) + const newUser = await db.users.findOneAndUpdate( + {email: email} + , [{ + $set: { + 'groups.quotas.defaultGroupsDuration': { + $cond: [ + { + $ne: [duration, null] + }, + duration, + '$groups.quotas.defaultGroupsDuration' + ] + }, + 'groups.quotas.defaultGroupsNumber': { + $cond: [ + { + $ne: [number, null] + }, + number, + '$groups.quotas.defaultGroupsNumber' + ] + }, + 'groups.quotas.defaultGroupsRepetitions': { + $cond: [ + { + $ne: [repetitions, null] + }, + repetitions, + '$groups.quotas.defaultGroupsRepetitions' + ] + } + } + }], + {returnDocument: 'after'} + ) + var userModifided = false + if (newUser) { + userModifided = UserChangeHandler.updateUserHandler(oldUser, newUser) + } + return {modifiedCount: userModifided ? 1 : 0, newUser: newUser} +} + +// dbapi.deleteUserAdbKey = function(email, fingerprint) { +export const deleteUserAdbKey = function(email, fingerprint) { + return db.users.findOne({email: email}).then(user => { + return db.users.updateOne( + {email: email} + , { + $set: { + adbKeys: user?.adbKeys ? user?.adbKeys.filter(key => { + return key.fingerprint !== fingerprint + }) : [] + } + } + ) + }) +} + +// dbapi.resetUserSettings = function(email) { +export const resetUserSettings = function(email) { + return db.users.updateOne({email: email}, + { + $set: { + settings: {} + } + }) +} + +export const deleteUser = async function(email) { + const deletedUser = await db.users.findOneAndDelete({email: email}) + UserChangeHandler.sendUserChange(deletedUser, false, [], 'deleted', ['settings']) + return {deletedCount: deletedUser !== null ? 1 : 0} +} + + +/* +==================================================== +==================== deprecated ==================== +==================================================== +*/ + +/** + * @deprecated Do not use locks in database. + */ +export const setLockOnUser = function(email, state) { + return db.users.findOne({email: email}).then(oldDoc => { + if (!oldDoc || !oldDoc.groups) { + throw new Error(`User with email ${email} not found or groups field is missing.`) + } + return db.users.updateOne( + {email: email}, + { + $set: { + 'groups.lock': oldDoc.groups.lock !== state ? state : oldDoc.groups.lock + } + } + ) + .then(updateStats => { + return db.users.findOne({email: email}).then(newDoc => { + // @ts-ignore + updateStats.changes = [ + {new_val: {...newDoc}, old_val: {...oldDoc}} + ] + return updateStats + }) + }) + }) +} + +export const getUserAdbKeys = function(email) { + return db.users.findOne({email: email}) + .then(user => user?.adbKeys || []) +} diff --git a/lib/db/proxiedModel.js b/lib/db/proxiedModel.js deleted file mode 100644 index c78417cea6..0000000000 --- a/lib/db/proxiedModel.js +++ /dev/null @@ -1,56 +0,0 @@ -import * as Sentry from '@sentry/node' - -// ----------------------------------Proxy all methods for Sentry error tracing---------------------------------------// - -const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg -const ARGUMENT_NAMES = /([^\s,]+)/g - -// TODO: argument names can be simplified after build -function getArgumentsNames(fn) { - const fnStr = fn.toString().replace(STRIP_COMMENTS, '') - let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES) - return result || [] -} - -const getAddedAttributes = (fn, args) => Object.fromEntries( - getArgumentsNames(fn).map((argument, i) => [ - `dbapi.${argument}`, - args[i] - ]) -) - -/** - * @template ModelType - * @param {ModelType} model - * @return {ModelType} - */ -// @ts-ignore -export default (model) => new Proxy(model, { - - /** @param {string} prop */ - get(target, prop) { - return (...args) => Sentry.startSpan( - { - op: 'dbapi', - name: prop, - attributes: args?.length ? getAddedAttributes(target[prop], args) : {} - } - , () => target[prop](...args) - ) - } -}) - -// export default (model) => model ? Object.keys(model).reduce((proxiedModel, method) => { -// db.connect() -// // console.log('\n\n', method, '\n\n') -// proxiedModel[method] = (...args) => Sentry.startSpan( -// { -// op: 'dbapi' -// , name: method -// , attributes: getAddedAttributes(model[method], args) -// } -// , () => model[method](...args) -// ) -// return proxiedModel -// }, Object.create({})) : model - diff --git a/lib/db/proxiedModel.ts b/lib/db/proxiedModel.ts new file mode 100644 index 0000000000..a1c80dd255 --- /dev/null +++ b/lib/db/proxiedModel.ts @@ -0,0 +1,38 @@ +import * as Sentry from '@sentry/node' + +// ----------------------------------Proxy all methods for Sentry error tracing---------------------------------------// + +const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg +const ARGUMENT_NAMES = /([^\s,]+)/g + +// TODO: argument names can be simplified after build +function getArgumentsNames(fn: Function) { + const fnStr = fn.toString().replace(STRIP_COMMENTS, '') + let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES) + return result || [] +} + +const getAddedAttributes = (fn: Function, args: any[]) => Object.fromEntries( + getArgumentsNames(fn).map((argument, i) => [ + `dbapi.${argument}`, + args[i] + ]) +) + +export default >(model: T) => Object.keys(model).reduce((proxiedModel, method) => { + if (typeof model[method] !== 'function') { + proxiedModel[method] = model[method] + return proxiedModel + } + + proxiedModel[method] = (...args: any[]) => Sentry.startSpan( + { + op: 'dbapi', + name: method, + attributes: getAddedAttributes(model[method], args) + } + , () => model[method](...args) + ) + return proxiedModel +}, {} as any) as T + diff --git a/lib/units/api/controllers/autotests.js b/lib/units/api/controllers/autotests.js index 4a0423e839..93be14cafd 100644 --- a/lib/units/api/controllers/autotests.js +++ b/lib/units/api/controllers/autotests.js @@ -9,6 +9,7 @@ import logger from '../../../util/logger.js' import * as Sentry from '@sentry/node' import _ from 'lodash' import useDevice, {UseDeviceError} from '../helpers/useDevice.js' +import {InstallResultMessage} from '../../../wire/wire.js' const log = logger.createLogger('api:controllers:autotests') @@ -150,7 +151,7 @@ function installOnDevice(req, res) { return apiutil.respond(res, 504, 'Device is not responding') }, apiutil.INSTALL_APK_WAIT) let messageListener = new WireRouter() - .on(wire.InstallResultMessage, function(channel, message) { + .on(InstallResultMessage, function(channel, message) { if (message.serial === serial) { clearTimeout(timer) req.options.sub.unsubscribe(responseChannel) diff --git a/lib/units/api/controllers/devices.js b/lib/units/api/controllers/devices.js index c5be7246b9..58a037c5b0 100644 --- a/lib/units/api/controllers/devices.js +++ b/lib/units/api/controllers/devices.js @@ -15,7 +15,8 @@ import * as jwtutil from '../../../util/jwtutil.js' import useDevice, {UseDeviceError} from '../helpers/useDevice.js' import * as Sentry from '@sentry/node' import {accessTokenAuth} from '../helpers/securityHandlers.js' -var log = logger.createLogger('api:controllers:devices') +import {DeviceOriginGroupMessage} from '../../../wire/wire.js' +const log = logger.createLogger('api:controllers:devices') /* ------------------------------------ PRIVATE FUNCTIONS ------------------------------- */ function filterGenericDevices(req, res, devices) { @@ -236,8 +237,8 @@ function getDevices(req, res) { } } function getDeviceBySerial(req, res) { - var serial = req.params.serial - var fields = req.query.fields + const serial = req.params.serial + const fields = req.query.fields dbapi.loadDevice(req.user.groups.subscribed, serial) .then(device => { if (!device) { @@ -262,8 +263,8 @@ function getDeviceBySerial(req, res) { }) } function getDeviceSize(req, res) { - var serial = req.params.serial - dbapi.getDeviceDisplaySize(serial) + const serial = req.params.serial + return dbapi.getDeviceDisplaySize(serial) .then(response => { return res.status(200).json(response.display) }) @@ -294,8 +295,8 @@ function getDeviceGroups(req, res) { }) } function getDeviceOwner(req, res) { - var serial = req.params.serial - dbapi.getDeviceGroupOwner(serial) + const serial = req.params.serial + return dbapi.getDeviceGroupOwner(serial) .then(response => { if (!response) { return res.status(404).json({ @@ -311,8 +312,8 @@ function getDeviceOwner(req, res) { }) } function getDeviceType(req, res) { - var serial = req.params.serial - dbapi.getDeviceType(serial) + const serial = req.params.serial + return dbapi.getDeviceType(serial) .then(response => { return res.status(200).json(response) }) @@ -480,12 +481,12 @@ function removeOriginGroupDevice(req, res) { function putDeviceInfoBySerial(req, res) { const serial = req.params.serial const body = req.body - dbapi.loadDeviceBySerial(serial) + return dbapi.loadDeviceBySerial(serial) .then((data) => { if (!data) { return apiutil.respond(res, 404, `Not Found (${serial})`) } - var updates = [] + const updates = [] // Update fields based on given body if (_.has(body, 'note')) { updates.push(dbapi.setDeviceNote(serial, body.note)) diff --git a/lib/units/api/controllers/groups.js b/lib/units/api/controllers/groups.js index b39620ac78..c15b25db35 100644 --- a/lib/units/api/controllers/groups.js +++ b/lib/units/api/controllers/groups.js @@ -11,7 +11,7 @@ import {v4 as uuidv4} from 'uuid' import usersapi from './users.js' import lockutil from '../../../util/lockutil.js' import {isOriginGroup} from '../../../util/apiutil.js' -import {loadDevicesBySerials} from '../../../db/models/all/model.js' +import DeviceModel from '../../../db/models/device/index.js' const log = logger.createLogger('groups-controller:') /* ---------------------------------- PRIVATE FUNCTIONS --------------------------------- */ @@ -168,7 +168,7 @@ function addGroupDevices(req, res) { } if (isInternal) { - return loadDevicesBySerials(autotestsGroup?.devices) + return DeviceModel.loadDevicesBySerials(autotestsGroup?.devices) .then(devices => apiutil.respond(res, 200, `Added (group ${target})`, { group: { id: autotestsGroup?.id, @@ -824,7 +824,7 @@ function updateGroup(req, res) { .then(function(group) { if (group && typeof group !== 'boolean') { if (isInternal) { - loadDevicesBySerials(group.devices) + DeviceModel.loadDevicesBySerials(group.devices) .then(devices => apiutil.respond(res, 200, 'Updated (group)', {group: {id: group.id, devices: devices}})) } else { @@ -909,7 +909,7 @@ function updateGroup(req, res) { repetitions === group.repetitions ) { if (isInternal) { - return loadDevicesBySerials(group.devices) + return DeviceModel.loadDevicesBySerials(group.devices) .then(devices => apiutil.respond(res, 200, 'Unchanged (group)', {group: {id: group.id, devices: devices}})) } } @@ -999,7 +999,7 @@ function getGroupDevices(req, res) { }) } else { - loadDevicesBySerials(group.devices) + DeviceModel.loadDevicesBySerials(group.devices) .then(function(devices) { devices = devices.map(device => apiutil.filterDevice(req, device)) apiutil.respond(res, 200, 'Devices Information', {devices: devices}) diff --git a/lib/units/api/controllers/user.js b/lib/units/api/controllers/user.js index 2bb043d0c0..390d7c7c5d 100644 --- a/lib/units/api/controllers/user.js +++ b/lib/units/api/controllers/user.js @@ -14,6 +14,7 @@ import * as jwtutil from '../../../util/jwtutil.js' import * as lockutil from '../../../util/lockutil.js' import * as Sentry from '@sentry/node' import generateToken from '../helpers/generateToken.js' +import {ConnectStartedMessage, ConnectStoppedMessage, JoinGroupMessage, LeaveGroupMessage, UngroupMessage} from '../../../wire/wire.js' import {runTransaction} from '../../../wire/transmanager.js' let log = logger.createLogger('api:controllers:user') @@ -47,7 +48,7 @@ function getUser(req, res) { } function getUserDevices(req, res) { - var fields = req.query.fields + const fields = req.query.fields log.info('Loading user devices') dbapi.loadUserDevices(req.user.email) .then(list => { @@ -77,9 +78,9 @@ function getUserDevices(req, res) { } function getUserDeviceBySerial(req, res) { - var serial = req.params.serial - var fields = req.query.fields - dbapi.loadDevice(req.user.groups.subscribed, serial) + const serial = req.params.serial + const fields = req.query.fields + return dbapi.loadDevice(req.user.groups.subscribed, serial) .then(function(device) { if (!device) { return res.status(404).json({ @@ -94,7 +95,7 @@ function getUserDeviceBySerial(req, res) { description: 'Device is not owned by you' }) } - var responseDevice = device + let responseDevice = device if (fields) { responseDevice = _.pick(device, fields.split(',')) } @@ -115,7 +116,7 @@ function addUserDevice(req, res) { let timeout = Object.prototype.hasOwnProperty.call(req, 'body') ? req.body.timeout || null : req.query.timeout || null const lock = {} - lockutil.lockGenericDevice(req, res, lock, dbapi.lockDeviceByCurrent) + return lockutil.lockGenericDevice(req, res, lock, dbapi.lockDeviceByCurrent) .then(function(lockingSuccessed) { if (lockingSuccessed) { const device = lock.device @@ -132,7 +133,7 @@ function addUserDevice(req, res) { return apiutil.respond(res, 504, 'Device is not responding') }, apiutil.GRPC_WAIT_TIMEOUT) let messageListener = new WireRouter() - .on(wire.JoinGroupMessage, function(channel, message) { + .on(JoinGroupMessage, function(channel, message) { log.info(device.serial + ' added to user group ' + req.user) if (message.serial === serial && message.owner.email === req.user.email) { clearTimeout(responseTimer) @@ -148,12 +149,19 @@ function addUserDevice(req, res) { let usage = 'automation' req.options.push.send([ device.channel, - wireutil.envelope(new wire.GroupMessage(new wire.OwnerMessage(req.user.email, req.user.name, req.user.group), timeout, wireutil.toDeviceRequirements({ - serial: { - value: serial, - match: 'exact' - } - }), usage)) + wireutil.envelope(new wire.GroupMessage( + new wire.OwnerMessage(req.user.email, req.user.name, req.user.group), + timeout, + wireutil.toDeviceRequirements({ + serial: { + value: serial, + match: 'exact' + } + }), + usage, + req.user.adbKeys + .map(key => key.fingerprint) + )) ]) } return false @@ -175,7 +183,7 @@ function deleteUserDeviceBySerial(req, res) { else { serial = req.params.serial } - dbapi.loadDevice(req.user.groups.subscribed, serial) + return dbapi.loadDevice(req.user.groups.subscribed, serial) .then(async function(device) { if (!device) { if (isInternal) { @@ -208,12 +216,18 @@ function deleteUserDeviceBySerial(req, res) { } } - await runTransaction(device.channel, new wire.UngroupMessage(wireutil.toDeviceRequirements({ - serial: { - value: serial, - match: 'exact' - } - }))) + await runTransaction(device.channel, UngroupMessage, { + requirements: wireutil.toDeviceRequirements({ + serial: { + value: serial, + match: 'exact' + } + }) + }, { + sub: req.options.sub, + push: req.options.push, + channelRouter: req.options.channelRouter + }) }) .catch(function(err) { let errSerial @@ -235,7 +249,7 @@ function deleteUserDeviceBySerial(req, res) { function remoteConnectUserDeviceBySerial(req, res) { let serial = req.params.serial - dbapi.loadDevice(req.user.groups.subscribed, serial) + return dbapi.loadDevice(req.user.groups.subscribed, serial) .then(function(device) { if (!device) { return res.status(404).json({ @@ -259,7 +273,7 @@ function remoteConnectUserDeviceBySerial(req, res) { return apiutil.respond(res, 504, 'Device is not responding') }, apiutil.GRPC_WAIT_TIMEOUT) let messageListener = new WireRouter() - .on(wire.ConnectStartedMessage, function(channel, message) { + .on(ConnectStartedMessage, function(channel, message) { if (message.serial === serial) { clearTimeout(timer) req.options.sub.unsubscribe(responseChannel) @@ -293,7 +307,7 @@ function remoteDisconnectUserDeviceBySerial(req, res) { else { serial = req.params.serial } - dbapi.loadDevice(req.user.groups.subscribed, serial) + return dbapi.loadDevice(req.user.groups.subscribed, serial) .then(function(device) { if (!device) { if (isInternal) { @@ -318,10 +332,10 @@ function remoteDisconnectUserDeviceBySerial(req, res) { }) } } - var responseChannel = 'txn_' + uuidv4() + const responseChannel = 'txn_' + uuidv4() req.options.sub.subscribe(responseChannel) // Timer will be called if no JoinGroupMessage is received till 5 seconds - var timer = setTimeoutS(function() { + const timer = setTimeoutS(function() { req.options.channelRouter.removeListener(responseChannel, messageListener) req.options.sub.unsubscribe(responseChannel) if (isInternal) { @@ -331,8 +345,8 @@ function remoteDisconnectUserDeviceBySerial(req, res) { return apiutil.respond(res, 504, 'Device is not responding') } }, apiutil.GRPC_WAIT_TIMEOUT) - var messageListener = new WireRouter() - .on(wire.ConnectStoppedMessage, function(channel, message) { + const messageListener = new WireRouter() + .on(ConnectStoppedMessage, function(channel, message) { if (message.serial === serial) { clearTimeout(timer) req.options.sub.unsubscribe(responseChannel) diff --git a/lib/units/api/controllers/users.js b/lib/units/api/controllers/users.js index 7eff6be078..cbb3cecbc6 100644 --- a/lib/units/api/controllers/users.js +++ b/lib/units/api/controllers/users.js @@ -1,4 +1,3 @@ -import dbapi from '../../../db/api.js' import _ from 'lodash' import * as apiutil from '../../../util/apiutil.js' import * as lockutil from '../../../util/lockutil.js' @@ -8,11 +7,14 @@ import wireutil from '../../../wire/util.js' import userapi from './user.js' import * as service from '../../../util/serviceuser.js' import {MongoServerError} from 'mongodb' +import AllModel from '../../../db/models/all/index.js' +import GroupModel from '../../../db/models/group/index.js' +import UserModel from '../../../db/models/user/index.js' /* --------------------------------- PRIVATE FUNCTIONS --------------------------------------- */ function userApiWrapper(fn, req, res) { const email = req.params.email - dbapi.loadUser(email).then(function(user) { + UserModel.loadUser(email).then(function(user) { if (!user) { apiutil.respond(res, 404, 'Not Found (user)') } @@ -39,24 +41,24 @@ async function removeUser(email, req, res) { const groupOwnerState = req.query.groupOwner const anyGroupOwnerState = typeof groupOwnerState === 'undefined' const lock = {} - const user = await dbapi.loadUser(email) + const user = await UserModel.loadUser(email) if (!user) { return 'not found' } async function removeGroupUser(owner, id) { - const userGroup = await dbapi.getUserGroup(owner, id) + const userGroup = await GroupModel.getUserGroup(owner, id) if (!userGroup) { return 'not found' } return owner === email ? - dbapi.deleteUserGroup(id) : - dbapi.removeGroupUser(id, email) + GroupModel.deleteUserGroup(id) : + GroupModel.removeGroupUser(id, email) } function deleteUserInDatabase(channel) { - return dbapi.removeUserAccessTokens(email).then(function() { - return dbapi.deleteUser(email).then(function() { + return AllModel.removeUserAccessTokens(email).then(function() { + return UserModel.deleteUser(email).then(function() { req.options.pushdev.send([ channel, wireutil.envelope(new wire.DeleteUserMessage(email)) @@ -90,12 +92,12 @@ async function removeUser(email, req, res) { if (req.user.email === email) { return Promise.resolve('forbidden') } - return dbapi.lockUser(email).then(function(stats) { + return AllModel.lockUser(email).then(function(stats) { if (stats.modifiedCount === 0) { return apiutil.lightComputeStats(res, stats) } const user = lock.user = stats.changes[0].new_val - return dbapi.getGroupsByUser(user.email).then(function(groups) { + return GroupModel.getGroupsByUser(user.email).then(function(groups) { return computeUserGroupOwnership(groups).then(function(doContinue) { if (!doContinue) { return 'unchanged' @@ -117,7 +119,7 @@ function grantAdmin(req, res) { if (req.user.privilege !== apiutil.ADMIN) { return apiutil.respond(res, 403, 'Forbidden (user doesnt have admin privilege)') } - dbapi.grantAdmin(req.params.email).then((user) => { + UserModel.grantAdmin(req.params.email).then((user) => { if (user) { // @ts-ignore return apiutil.respond(res, 200, 'Grant admin for user', {user: user}) @@ -131,7 +133,7 @@ function revokeAdmin(req, res) { if (req.user.privilege !== apiutil.ADMIN) { return apiutil.respond(res, 403, 'Forbidden (user doesnt have admin privilege)') } - dbapi.revokeAdmin(req.params.email).then((user) => { + UserModel.revokeAdmin(req.params.email).then((user) => { if (user) { // @ts-ignore return apiutil.respond(res, 200, 'Revoke admin for user', {user: user}) @@ -142,7 +144,7 @@ function revokeAdmin(req, res) { }) } function lockStfAdminUser(res) { - return dbapi.lockUser(apiutil.STF_ADMIN_EMAIL).then(function(stats) { + return AllModel.lockUser(apiutil.STF_ADMIN_EMAIL).then(function(stats) { if (stats.modifiedCount === 0) { return apiutil.lightComputeStats(res, stats) } @@ -154,12 +156,12 @@ function updateUsersAlertMessage(req, res) { return apiutil.respond(res, 403, 'Forbidden (user doesnt have admin privilege)') } const lock = lockStfAdminUser(res) - return dbapi.updateUsersAlertMessage(req.body).then(function(/** @type {any} */ stats) { + return UserModel.updateUsersAlertMessage(req.body).then(function(/** @type {any} */ stats) { if (stats.matchedCount > 0 && stats.modifiedCount === 0) { - apiutil.respond(res, 200, 'Unchanged (users alert message)', {alertMessage: stats.changes[0].new_val.settings.alertMessage}) + apiutil.respond(res, 200, 'Unchanged (users alert message)', {alertMessage: stats.newUser.settings.alertMessage}) } else { - apiutil.respond(res, 200, 'Updated (users alert message)', {alertMessage: stats.changes[0].new_val.settings.alertMessage}) + apiutil.respond(res, 200, 'Updated (users alert message)', {alertMessage: stats.newUser.settings.alertMessage}) } }) .catch(function(err) { @@ -178,9 +180,9 @@ function updateUsersAlertMessage(req, res) { /* --------------------------------- PUBLIC FUNCTIONS --------------------------------------- */ function getUserInfo(req, email) { const fields = req.query.fields - return dbapi.loadUser(email).then(function(user) { + return UserModel.loadUser(email).then(function(user) { if (user) { - return dbapi.getRootGroup().then(function(group) { + return GroupModel.getRootGroup().then(function(group) { return getPublishedUser(user, req.user.email, group?.owner?.email, fields) }) } @@ -189,7 +191,7 @@ function getUserInfo(req, email) { } function getUsersAlertMessage(req, res) { const fields = req.query.fields - return dbapi.loadUser(apiutil.STF_ADMIN_EMAIL).then(async function(user) { + return UserModel.loadUser(apiutil.STF_ADMIN_EMAIL).then(async function(user) { if (user?.settings?.alertMessage === undefined) { const lock = await lockStfAdminUser(res) const alertMessage = { @@ -197,9 +199,9 @@ function getUsersAlertMessage(req, res) { data: '*** this site is currently under maintenance, please wait ***', level: 'Critical' } - return dbapi.updateUsersAlertMessage(alertMessage).then(function(/** @type {any} */ stats) { - if (!stats.errors) { - return stats.changes[0].new_val.settings.alertMessage + return UserModel.updateUsersAlertMessage(alertMessage).then(function(/** @type {any} */ stats) { + if (stats.modifiedCount === 1) { + return stats.newUser.settings.alertMessage } throw new Error('Failed to initialize users alert message') }) @@ -239,15 +241,15 @@ function updateUserGroupsQuotas(req, res) { null const lock = {} - dbapi.loadUser(email).then(function(user) { + UserModel.loadUser(email).then(function(user) { if (user) { lockutil.lockUser(email, res, lock).then(function(lockingSuccessed) { if (lockingSuccessed) { - return dbapi.updateUserGroupsQuotas(email, duration, number, repetitions) + return UserModel.updateUserGroupsQuotas(email, duration, number, repetitions) .then(function(/** @type {any} */ stats) { if (stats.modifiedCount > 0) { return apiutil.respond(res, 200, 'Updated (user quotas)', { - user: apiutil.publishUser(stats.changes[0].new_val) + user: apiutil.publishUser(stats.newUser) }) } if ((duration === null || duration === lock.user.groups.quotas.allocated.duration) && @@ -285,11 +287,11 @@ function updateDefaultUserGroupsQuotas(req, res) { const lock = {} lockutil.lockUser(req.user.email, res, lock).then(function(lockingSuccessed) { if (lockingSuccessed) { - return dbapi.updateDefaultUserGroupsQuotas(req.user.email, duration, number, repetitions) + return UserModel.updateDefaultUserGroupsQuotas(req.user.email, duration, number, repetitions) .then(function(/** @type {any} */ stats) { if (stats.modifiedCount > 0) { return apiutil.respond(res, 200, 'Updated (user default quotas)', { - user: apiutil.publishUser(stats) + user: apiutil.publishUser(stats.newUser) }) } return apiutil.respond(res, 200, 'Unchanged (user default quotas)', {user: {}}) @@ -320,8 +322,8 @@ function getUserByEmail(req, res) { } function getUsers(req, res) { const fields = req.query.fields - dbapi.getUsers().then(function(users) { - return dbapi.getRootGroup().then(function(group) { + UserModel.getUsers().then(function(users) { + return GroupModel.getRootGroup().then(function(group) { apiutil.respond(res, 200, 'Users Information', { users: users.map(function(user) { return getPublishedUser(user, req.user.email, group?.owner?.email, fields) @@ -336,7 +338,7 @@ function getUsers(req, res) { function createUser(req, res) { const email = req.params.email const name = req.query.name - dbapi.createUser(email, name, req.user.ip).then(function(/** @type {any} */ stats) { + UserModel.createUser(email, name, req.user.ip).then(function(/** @type {any} */ stats) { apiutil.respond(res, 201, 'Created (user)', { user: apiutil.publishUser(stats.changes[0].new_val) }) @@ -405,7 +407,7 @@ function deleteUsers(req, res) { } (function() { if (typeof emails === 'undefined') { - return dbapi.getEmails().then(function(emails) { + return UserModel.getEmails().then(function(emails) { return removeUsers(emails) }) } diff --git a/lib/units/api/helpers/test.js b/lib/units/api/helpers/test.js new file mode 100644 index 0000000000..6a88e940c4 --- /dev/null +++ b/lib/units/api/helpers/test.js @@ -0,0 +1,11 @@ +import * as jwtutil from '../../../util/jwtutil.js' + +const a = jwtutil.encode({ + payload: { + email: user.email, + name: user.name + }, + secret: secret +}) + +console.log(a) diff --git a/lib/units/api/helpers/useDevice.js b/lib/units/api/helpers/useDevice.js index 7e769d7f3a..01b3ffba78 100644 --- a/lib/units/api/helpers/useDevice.js +++ b/lib/units/api/helpers/useDevice.js @@ -9,6 +9,7 @@ import wire from '../../../wire/index.js' import {v4 as uuidv4} from 'uuid' import {Log} from '../../../util/logger.js' import {runTransaction} from '../../../wire/transmanager.js' +import {ConnectStartedMessage, GroupMessage, JoinGroupMessage, OwnerMessage, UngroupMessage} from '../../../wire/wire.js' export const UseDeviceError = Object.freeze({ NOT_FOUND: 0, @@ -49,10 +50,12 @@ const useDevice = ({user, device, channelRouter, push, sub, usage = null, log}) }) try { - await runTransaction(device.channel, new wire.UngroupMessage(deviceRequirements), {sub, push, channelRouter}) + await runTransaction(device.channel, UngroupMessage, { + requirements: deviceRequirements + }, {sub, push, channelRouter}) } - catch (e) { - log?.info(e) + catch (/** @type {any} */e) { + log?.info('Transaction failed: %s', e?.message) } const responseTimeout = setTimeout(function() { @@ -61,7 +64,7 @@ const useDevice = ({user, device, channelRouter, push, sub, usage = null, log}) }, apiutil.GRPC_WAIT_TIMEOUT) const useDeviceMessageListener = new WireRouter() - .on(wire.JoinGroupMessage, function(channel, message) { + .on(JoinGroupMessage, function(channel, message) { log?.info(device.serial + ' added to user group ' + user) if (message.serial === device.serial && message.owner.email === user.email) { @@ -72,14 +75,14 @@ const useDevice = ({user, device, channelRouter, push, sub, usage = null, log}) sub.subscribe(responseChannel) const connectTimeout = setTimeout(function() { - channelRouter.removeListener(responseChannel, useDeviceMessageListener) + channelRouter.removeListener(responseChannel, messageListener) sub.unsubscribe(responseChannel) reject(UseDeviceError.FAILED_CONNECT) }, apiutil.GRPC_WAIT_TIMEOUT) const messageListener = new WireRouter() - .on(wire.ConnectStartedMessage, function(channel, message) { + .on(ConnectStartedMessage, function(channel, message) { if (message.serial === device.serial) { clearTimeout(connectTimeout) sub.unsubscribe(responseChannel) @@ -101,12 +104,24 @@ const useDevice = ({user, device, channelRouter, push, sub, usage = null, log}) channelRouter.on(wireutil.global, useDeviceMessageListener) - await runTransaction(device.channel, new wire.GroupMessage( - new wire.OwnerMessage(user.email, user.name, user.group) - , timeout - , deviceRequirements - , usage - ), {sub, push, channelRouter}) + try { + await runTransaction(device.channel, GroupMessage, { + owner: OwnerMessage.create({ + email: user.email, + name: user.name, + group: user.group + }), + requirements: deviceRequirements, + usage: usage || undefined, + keys: user.adbKeys?.map((/** @type {{ fingerprint: string }} */ k) => k.fingerprint) || [] + }, {sub, push, channelRouter}) + } + catch (/** @type {any} */e) { + log?.info('Transaction failed: %s', e?.message) + clearTimeout(responseTimeout) + channelRouter.removeListener(wireutil.global, useDeviceMessageListener) + return reject(UseDeviceError.FAILED_JOIN) + } }) export default useDevice diff --git a/lib/units/base-device/plugins/group.js b/lib/units/base-device/plugins/group.js deleted file mode 100755 index fbf8cf3f84..0000000000 --- a/lib/units/base-device/plugins/group.js +++ /dev/null @@ -1,155 +0,0 @@ -import events from 'events' -import Promise from 'bluebird' -import syrup from '@devicefarmer/stf-syrup' -import logger from '../../../util/logger.js' -import wire from '../../../wire/index.js' -import wireutil from '../../../wire/util.js' -import * as grouputil from '../../../util/grouputil.js' -import lifecycle from '../../../util/lifecycle.js' -import db from '../../../db/index.js' -import dbapi from '../../../db/api.js' -import * as apiutil from '../../../util/apiutil.js' -import solo from './solo.js' -import router from '../support/router.js' -import push from '../support/push.js' -import sub from '../support/sub.js' -import channels from '../support/channels.js' -export default syrup.serial() - .dependency(solo) - .dependency(router) - .dependency(push) - .dependency(sub) - .dependency(channels) - .define(async(options, solo, router, push, sub, channels) => { - const log = logger.createLogger('base-device:plugins:group') - let currentGroup = null - - /** @type {any} */ - let plugin = new events.EventEmitter() - - await db.connect() - - plugin.get = Promise.method(function() { - if (!currentGroup) { - throw new grouputil.NoGroupError() - } - return currentGroup - }) - plugin.join = (newGroup, timeout, usage) => { - return plugin.get() - .then(() => { - if (currentGroup.group !== newGroup.group) { - throw new grouputil.AlreadyGroupedError() - } - log.info('Update timeout for ', apiutil.QUARTER_MINUTES) - channels.updateTimeout(currentGroup.group, apiutil.QUARTER_MINUTES) - let newTimeout = channels.getTimeout(currentGroup.group) - plugin.emit('join', currentGroup) - dbapi.enhanceStatusChangedAt(options.serial, newTimeout).then(() => { - return currentGroup - }) - }) - .catch(grouputil.NoGroupError, () => { - currentGroup = newGroup - log.important('Now owned by "%s"', currentGroup.email) - log.important('Device now in group "%s"', currentGroup.name) - log.info('Rent time is ' + timeout) - log.info('Subscribing to group channel "%s"', currentGroup.group) - channels.register(currentGroup.group, { - timeout: timeout || options.groupTimeout, - alias: solo.channel - }) - dbapi.enhanceStatusChangedAt(options.serial, timeout) - sub.subscribe(currentGroup.group) - push.send([ - wireutil.global, - wireutil.envelope(new wire.JoinGroupMessage(options.serial, currentGroup, usage)) - ]) - plugin.emit('join', currentGroup) - return currentGroup - }) - } - plugin.keepalive = () => { - if (currentGroup) { - channels.keepalive(currentGroup.group) - } - } - plugin.leave = (reason) => { - return plugin.get() - .then(group => { - log.important('No longer owned by "%s"', group.email) - log.info('Unsubscribing from group channel "%s"', group.group) - channels.unregister(group.group) - sub.unsubscribe(group.group) - push.send([ - wireutil.global, - wireutil.envelope(new wire.LeaveGroupMessage(options.serial, group, reason)) - ]) - currentGroup = null - plugin.emit('leave', group) - return group - }) - } - router - .on(wire.GroupMessage, (channel, message) => { - let reply = wireutil.reply(options.serial) - // grouputil.match(ident, message.requirements) - plugin.join(message.owner, message.timeout, message.usage) - .then(() => { - push.send([ - channel, - reply.okay() - ]) - }) - .catch(grouputil.RequirementMismatchError, (err) => { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - .catch(grouputil.AlreadyGroupedError, (err) => { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - }) - .on(wire.AutoGroupMessage, (channel, message) => { - return plugin.join(message.owner, message.timeout, message.identifier) - .then(() => { - plugin.emit('autojoin', message.identifier, true) - }) - .catch(grouputil.AlreadyGroupedError, () => { - plugin.emit('autojoin', message.identifier, false) - }) - }) - .on(wire.UngroupMessage, (channel, message) => { - let reply = wireutil.reply(options.serial) - Promise.method(() => { - return plugin.leave('ungroup_request') - })() - .then(() => { - push.send([ - channel, - reply.okay() - ]) - }) - .catch(grouputil.NoGroupError, err => { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - }) - // @ts-ignore - channels.on('timeout', channel => { - if (currentGroup && channel === currentGroup.group) { - plugin.leave('automatic_timeout') - } - }) - lifecycle.observe(() => { - return plugin.leave('device_absent') - .catch(grouputil.NoGroupError, () => true) - }) - return plugin - }) diff --git a/lib/units/base-device/plugins/group.ts b/lib/units/base-device/plugins/group.ts new file mode 100755 index 0000000000..1ffbd304ed --- /dev/null +++ b/lib/units/base-device/plugins/group.ts @@ -0,0 +1,252 @@ +import syrup from '@devicefarmer/stf-syrup' +import logger from '../../../util/logger.js' +import { + AutoGroupMessage, + DeviceStatusChange, + GroupMessage, + JoinGroupMessage, + LeaveGroupMessage, UngroupMessage +} from '../../../wire/wire.js' +import wireutil from '../../../wire/util.js' +import * as grouputil from '../../../util/grouputil.js' +import lifecycle from '../../../util/lifecycle.js' +import * as apiutil from '../../../util/apiutil.js' +import solo from './solo.js' +import router from '../support/router.js' +import push from '../support/push.js' +import sub from '../support/sub.js' +import channels from '../support/channels.js' +import EventEmitter from 'events' + +interface GroupState { + email: string + name: string + group: string +} + +type ADBKey = string +type Joined = boolean + +interface GroupEvents { + join: [GroupState, ADBKey[]] + leave: [GroupState | null] + autojoin: [ADBKey, Joined] +} + +export default syrup.serial() + .dependency(solo) + .dependency(router) + .dependency(push) + .dependency(sub) + .dependency(channels) + .define(async(options, solo, router, push, sub, channels) => { + const log = logger.createLogger('base-device:plugins:group') + + const plugin = new class GroupManager extends EventEmitter { + private currentGroup: GroupState | null = null + + keepalive = () => { + if (this.currentGroup) { + channels.keepalive(this.currentGroup.group) + } + } + + get = async() => { + if (!this.currentGroup) { + throw new grouputil.NoGroupError() + return + } + + return this.currentGroup + } + + join = async(newGroup: GroupState, timeout: number, usage: string, keys: string[]) => { + try { + if (!newGroup?.group) { + throw new Error(`New group is not valid: ${JSON.stringify(newGroup)}`) + } + + if (!!this.currentGroup?.group) { // if device in group + if (this.currentGroup.group !== newGroup.group) { // and is not same + log.error(`Cannot join group ${JSON.stringify(newGroup)} since this device is in group ${JSON.stringify(this.currentGroup)}`) + throw new grouputil.AlreadyGroupedError() + } + + log.info('Update timeout for %s', apiutil.QUARTER_MINUTES) + channels.updateTimeout(this.currentGroup.group, apiutil.QUARTER_MINUTES) + + const newTimeout = channels.getTimeout(this.currentGroup.group) + push.send([ + wireutil.global, + wireutil.pack(DeviceStatusChange, { + serial: options.serial, + timeout: newTimeout || undefined + }) + ]) + + return this.currentGroup + } + + this.currentGroup = newGroup + + log.important('Now owned by "%s"', this.currentGroup.email) + log.important('Device now in group "%s"', this.currentGroup.name) + log.info(`Rent time is ${timeout}`) + log.info('Subscribing to group channel "%s"', this.currentGroup.group) + + channels.register(this.currentGroup.group, { + timeout: timeout || options.groupTimeout, + alias: solo.channel + }) + + sub.subscribe(this.currentGroup.group) + plugin.emit('join', this.currentGroup, keys) + + push.send([ + wireutil.global, + wireutil.pack(JoinGroupMessage, { + serial: options.serial, + owner: this.currentGroup, + usage, + timeout + }) + ]) + + return this.currentGroup + } + catch (err: any) { + log.error(`Failed to join group ${JSON.stringify(newGroup)}, Error: %s`, err?.message) + return this.currentGroup + } + } + + leave = async(reason: string) => { + if (!this.currentGroup) { + throw new grouputil.NoGroupError() + } + + log.important('No longer owned by "%s"', this.currentGroup.email) + log.info('Unsubscribing from group channel "%s"', this.currentGroup.group) + + push.send([ + wireutil.global, + wireutil.pack(LeaveGroupMessage, { + serial: options.serial, + owner: this.currentGroup, + reason + }) + ]) + + channels.unregister(this.currentGroup.group) + sub.unsubscribe(this.currentGroup.group) + + this.currentGroup = null + plugin.emit('leave', this.currentGroup) + return this.currentGroup + } + + beforeActionCheck = + async(message: any) => true + + // Set that for custom checks before GroupMessage/UngroupMessage processed (optional) + setCheckBeforeAction = + (cb: (message: any) => Promise) => { + this.beforeActionCheck = cb + } + + checkBeforeAction = + (msgName: string, message: any, channel: string, reply: ReturnType) => + this.beforeActionCheck(message) + .catch((err: any) => { + log.error('Error before processing %s: %s', msgName, err?.message) + push.send([ + channel, + reply.fail(err.message) + ]) + + return false + }) + }() + + router + .on(GroupMessage, async(channel, message) => { + const reply = wireutil.reply(options.serial) + try { + if (!await plugin.checkBeforeAction('GroupMessage', message, channel, reply)) { + return + } + + await plugin.join(message.owner!, message.timeout!, message.usage!, message.keys) + push.send([ + channel, + reply.okay() + ]) + } + catch (err: any) { + log.error('Failed processing GroupMessage: %s', err?.message) + if (err instanceof grouputil.AlreadyGroupedError) { + push.send([ + channel, + reply.fail(err.message) + ]) + } + } + }) + .on(AutoGroupMessage, async(channel, message) => { + try { + await plugin.join(message.owner!, 0, message.identifier, []) + plugin.emit('autojoin', message.identifier, true) + } + catch (err: any) { + log.error('Failed processing AutoGroupMessage: %s', err?.message) + if (err instanceof grouputil.AlreadyGroupedError) { + plugin.emit('autojoin', message.identifier, false) + } + } + }) + .on(UngroupMessage, async(channel, message) => { + const reply = wireutil.reply(options.serial) + try { + if (!await plugin.checkBeforeAction('UngroupMessage', message, channel, reply)) { + return + } + + await plugin.leave('ungroup_request') + push.send([ + channel, + reply.okay() + ]) + } + catch (err: any) { + log.error('Failed processing UngroupMessage: %s', err?.message) + if (err instanceof grouputil.NoGroupError) { + push.send([ + channel, + reply.fail(err.message) + ]) + } + } + }) + + // @ts-ignore + channels.on('timeout', async(channel) => { + const currentGroup = await plugin.get() + if (currentGroup && channel === currentGroup.group) { + plugin.leave('automatic_timeout') + } + }) + + lifecycle.observe(async() => { + try { + await plugin.leave('device_absent') + } + catch (err: any) { + log.error('Failed leave from group on process exit: %s', err?.message) + if (err instanceof grouputil.NoGroupError) { + return true + } + } + }) + + return plugin + }) diff --git a/lib/units/base-device/support/connector.js b/lib/units/base-device/support/connector.js index c3b5d0e2d3..4e48ca0bd6 100755 --- a/lib/units/base-device/support/connector.js +++ b/lib/units/base-device/support/connector.js @@ -6,6 +6,7 @@ import dbapi from '../../../db/api.js' import wireutil from '../../../wire/util.js' import db from '../../../db/index.js' import push from './push.js' +import {ConnectGetForwardUrlMessage, ConnectStartMessage, ConnectStopMessage} from '../../../wire/wire.js' /** * @typedef {{ @@ -52,13 +53,13 @@ export default syrup.serial() this.urlWithoutAdbPort = urlWithoutAdbPort router - .on(wire.ConnectStartMessage, + .on(ConnectStartMessage, (channel) => this.start(channel) ) - .on(wire.ConnectGetForwardUrlMessage, + .on(ConnectGetForwardUrlMessage, (channel) => this.getUrl(channel) ) - .on(wire.ConnectStopMessage, + .on(ConnectStopMessage, (channel) => this.stop(channel) ) } diff --git a/lib/units/base-device/support/push.ts b/lib/units/base-device/support/push.ts index 0fe7c58d4d..65c066af5a 100755 --- a/lib/units/base-device/support/push.ts +++ b/lib/units/base-device/support/push.ts @@ -32,7 +32,7 @@ export default syrup.serial().define( return push } catch (err) { - log.fatal('Unable to connect to sub endpoint', err) + log.fatal('Unable to connect to sub endpoint: %s', err) return lifecycle.fatal() // kill process } } diff --git a/lib/units/base-device/support/router.js b/lib/units/base-device/support/router.js index 26bf2a7cc6..ee9bb7a68a 100755 --- a/lib/units/base-device/support/router.js +++ b/lib/units/base-device/support/router.js @@ -9,7 +9,7 @@ export default syrup.serial() const router = new WireRouter() sub.on('message', router.handler()) // Special case, we're hooking into a message that's not actually routed. - router.on({$code: 'message'}, channel => { + router.on('message', channel => { channels.keepalive(channel) }) return router diff --git a/lib/units/device/plugins/account.js b/lib/units/device/plugins/account.js index 4323a982d3..52d9951393 100644 --- a/lib/units/device/plugins/account.js +++ b/lib/units/device/plugins/account.js @@ -8,6 +8,7 @@ import touch from './touch/index.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import adb from '../support/adb.js' +import {AccountAddMenuMessage, AccountAddMessage, AccountCheckMessage, AccountGetMessage, AccountRemoveMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(service) .dependency(identity) @@ -27,7 +28,7 @@ export default syrup.serial() throw new Error('The account is not added') }) } - router.on(wire.AccountCheckMessage, function(channel, message) { + router.on(AccountCheckMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Checking if account "%s" is added', message.account) checkAccount(message.type, message.account) @@ -45,7 +46,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.AccountGetMessage, function(channel, message) { + router.on(AccountGetMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Getting account(s)') service.getAccounts(message) @@ -64,7 +65,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.AccountRemoveMessage, function(channel, message) { + router.on(AccountRemoveMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Removing "%s" account(s)', message.type) service.removeAccount(message) @@ -83,7 +84,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.AccountAddMenuMessage, function(channel) { + router.on(AccountAddMenuMessage, function(channel) { var reply = wireutil.reply(options.serial) log.info('Showing add account menu for Google Account') service.addAccountMenu() @@ -102,7 +103,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.AccountAddMessage, function(channel, message) { + router.on(AccountAddMessage, function(channel, message) { var reply = wireutil.reply(options.serial) var type = 'com.google' var account = message.user + '@gmail.com' diff --git a/lib/units/device/plugins/airplane.js b/lib/units/device/plugins/airplane.js index eef54033a6..9649f57ec4 100644 --- a/lib/units/device/plugins/airplane.js +++ b/lib/units/device/plugins/airplane.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import devutil from '../../../util/devutil.js' +import {AirplaneSetMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(devutil) .dependency(router) .dependency(push) .define(function(options, devutil, router, push) { var log = logger.createLogger('device:plugins:airplane') - router.on(wire.AirplaneSetMessage, async function(channel, message) { + router.on(AirplaneSetMessage, async function(channel, message) { const reply = wireutil.reply(options.serial) const enabled = message.enabled log.info('Setting airplane mode to', enabled) diff --git a/lib/units/device/plugins/bluetooth.js b/lib/units/device/plugins/bluetooth.js index dab8241ecd..b47ac65048 100644 --- a/lib/units/device/plugins/bluetooth.js +++ b/lib/units/device/plugins/bluetooth.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import service from './service.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {BluetoothCleanBondedMessage, BluetoothGetStatusMessage, BluetoothSetEnabledMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(service) .dependency(router) .dependency(push) .define(function(options, service, router, push) { var log = logger.createLogger('device:plugins:bluetooth') - router.on(wire.BluetoothSetEnabledMessage, function(channel, message) { + router.on(BluetoothSetEnabledMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Setting Bluetooth "%s"', message.enabled) service.setBluetoothEnabled(message.enabled) @@ -30,7 +31,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.BluetoothGetStatusMessage, function(channel) { + router.on(BluetoothGetStatusMessage, function(channel) { var reply = wireutil.reply(options.serial) log.info('Getting Bluetooth status') service.getBluetoothStatus() @@ -49,7 +50,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.BluetoothCleanBondedMessage, function(channel) { + router.on(BluetoothCleanBondedMessage, function(channel) { var reply = wireutil.reply(options.serial) log.info('Clean bonded Bluetooth devices') service.cleanupBondedBluetoothDevices() diff --git a/lib/units/device/plugins/browser.js b/lib/units/device/plugins/browser.js index 86d65031e0..e1425ee2fe 100644 --- a/lib/units/device/plugins/browser.js +++ b/lib/units/device/plugins/browser.js @@ -7,6 +7,7 @@ import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import adb from '../support/adb.js' import service from './service.js' +import {BrowserClearMessage, BrowserOpenMessage} from '../../../wire/wire.js' const mapping = (function() { var list = Object.create(null) Object.keys(browsers).forEach(function(id) { @@ -76,7 +77,7 @@ export default syrup.serial() return (url.indexOf('://') === -1 ? 'http://' : '') + url } service.on('browserPackageChange', updateBrowsers) - router.on(wire.BrowserOpenMessage, function(channel, message) { + router.on(BrowserOpenMessage, function(channel, message) { message.url = ensureHttpProtocol(message.url) if (message.browser) { log.info('Opening "%s" in "%s"', message.url, message.browser) @@ -109,7 +110,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.BrowserClearMessage, function(channel, message) { + router.on(BrowserClearMessage, function(channel, message) { log.info('Clearing "%s"', message.browser) var reply = wireutil.reply(options.serial) adb.getDevice(options.serial).clear(pkg(message.browser)) diff --git a/lib/units/device/plugins/clipboard.js b/lib/units/device/plugins/clipboard.js index b5c0a20582..30d0278673 100644 --- a/lib/units/device/plugins/clipboard.js +++ b/lib/units/device/plugins/clipboard.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import service from './service.js' +import {CopyMessage, PasteMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(router) .dependency(push) .dependency(service) .define(function(options, router, push, service) { var log = logger.createLogger('device:plugins:clipboard') - router.on(wire.PasteMessage, function(channel, message) { + router.on(PasteMessage, function(channel, message) { log.info('Pasting "%s" to clipboard', message.text) var reply = wireutil.reply(options.serial) service.paste(message.text) @@ -29,7 +30,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.CopyMessage, function(channel) { + router.on(CopyMessage, function(channel) { log.info('Copying clipboard contents') var reply = wireutil.reply(options.serial) service.copy() diff --git a/lib/units/device/plugins/connect.js b/lib/units/device/plugins/connect.ts similarity index 53% rename from lib/units/device/plugins/connect.js rename to lib/units/device/plugins/connect.ts index 80b41d6bd1..8dd727d575 100644 --- a/lib/units/device/plugins/connect.js +++ b/lib/units/device/plugins/connect.ts @@ -1,10 +1,9 @@ import util from 'util' import syrup from '@devicefarmer/stf-syrup' import logger from '../../../util/logger.js' -import wire from '../../../wire/index.js' +import {JoinGroupByAdbFingerprintMessage} from '../../../wire/wire.js' import wireutil from '../../../wire/util.js' import lifecycle from '../../../util/lifecycle.js' -import db from '../../../db/index.js' import adb from '../support/adb.js' import connector, {DEVICE_TYPE} from '../../base-device/support/connector.js' import push from '../../base-device/support/push.js' @@ -14,17 +13,13 @@ import solo from './solo.js' import urlformat from '../../base-device/support/urlformat.js' import identity from './util/identity.js' import data from './util/data.js' -import {GRPC_WAIT_TIMEOUT} from '../../../util/apiutil.js' - -// The promise passed as an argument will not be cancelled after the time has elapsed, -// only the second promise will be rejected. -const promiseTimeout = (promise, ms, message = 'Timeout exceeded') => Promise.race([ - promise, - new Promise((_, reject) => { - const id = setTimeout(() => reject(new Error(message)), ms) - promise.finally(() => clearTimeout(id)) - }) -]) +import type TcpUsbServer from '@u4/adbkit/dist/adb/tcpusb/server.d.ts' +import {AdbKeysUpdatedMessage} from '../../../wire/wire.js' + +interface Key { + fingerprint: string + comment: string +} export default syrup.serial() .dependency(adb) @@ -36,56 +31,58 @@ export default syrup.serial() .dependency(connector) .dependency(identity) .dependency(data) - .define(async function(options, adb, router, push, group, solo, urlformat, connector, identity, data) { + .define(async(options, adb, router, push, group, solo, urlformat, connector, identity, data) => { const log = logger.createLogger('device:plugins:connect') - let activeServer = null - - await db.connect() + let activeServer: TcpUsbServer | null = null - const notify = async(key) => { + const notify = async(key: Key) => { try { - const currentGroup = group.get() + const currentGroup = await group.get() push.send([ solo.channel, - wireutil.envelope(new wire.JoinGroupByAdbFingerprintMessage(options.serial, key.fingerprint, key.comment, currentGroup.group)) + wireutil.pack(JoinGroupByAdbFingerprintMessage, { + serial: options.serial, + fingerprint: key.fingerprint, + comment: key.comment, + currentGroup: currentGroup?.group + }) ]) } catch(e) { push.send([ solo.channel, - wireutil.envelope(new wire.JoinGroupByAdbFingerprintMessage(options.serial, key.fingerprint, key.comment)) + wireutil.pack(JoinGroupByAdbFingerprintMessage, { + serial: options.serial, + fingerprint: key.fingerprint, + comment: key.comment + }) ]) } } - const joinListener = (_, identifier, key, reject) => { - if (identifier !== key.fingerprint) { - reject(new Error('Somebody else took the device')) - } - } - - const autojoinListener = (identifier, joined, key, resolve, reject) => { - if (identifier === key.fingerprint) { - if (joined) { - return resolve() - } - reject(new Error('Device is already in use')) - } - } - const plugin = { serial: options.serial, port: options.connectPort, url: urlformat(options.connectUrlPattern, options.connectPort, identity.model, data ? data.name.id : ''), - auth: (key, resolve, reject) => reject(), + auth: (key: Key): boolean => false, start: () => new Promise((resolve, reject) => { log.info('Starting connect plugin') - const auth = key => promiseTimeout(new Promise((resolve, reject) => { - plugin.auth(key, resolve, reject) - router.on(wire.AdbKeysUpdatedMessage, () => notify(key)) - notify(key) - }), GRPC_WAIT_TIMEOUT) // reject after 2 minutes if autojoin event doesn't fire + // If Auth failed - the entire unit device will fall + // TODO: fix + const auth = (key: Key) => new Promise(async(resolve, reject) => { + // TODO: Dangerous, discuss and remove + router.on(AdbKeysUpdatedMessage, () => notify(key)) + await notify(key) + + if (plugin.auth(key)) { + resolve() + return + } + + // Connection rejected by user-defined auth handler + reject('Auth failed') + }) activeServer = adb.createTcpUsbBridge(plugin.serial, {auth}) .on('listening', () => resolve(plugin.url)) @@ -96,8 +93,7 @@ export default syrup.serial() conn.on('userActivity', () => group.keepalive()) }) - activeServer.listen(plugin.port) - lifecycle.share('Remote ADB', activeServer) + activeServer!.listen(plugin.port) log.info(util.format('Listening on port %d', plugin.port)) resolve(plugin.url) @@ -108,22 +104,19 @@ export default syrup.serial() } log.info('Stop connect plugin') - router.removeAllListeners(wire.AdbKeysUpdatedMessage) - let resolveClose = () => {} + // TODO: Not ideal way, need WireRouter.once + router.removeAllListeners(AdbKeysUpdatedMessage) - const waitCloseServer = new Promise((resolve) => { - // @ts-ignore - resolveClose = resolve - }) - - activeServer.on('close', () => { - resolveClose() + const waitServerClose = new Promise((resolve) => { + activeServer!.on('close', () => { + resolve() + }) }) activeServer.end() activeServer.close() - await waitCloseServer + await waitServerClose activeServer = null }, @@ -134,13 +127,24 @@ export default syrup.serial() } } - group.on('join', (g, id) => - plugin.auth = (key, resolve, reject) => - joinListener(g, id, key, resolve, reject) + group.on('join', (group, keys) => + plugin.auth = key => { + if (keys?.length && !keys.includes(key.fingerprint)) { + log.error('Invalid RSA key. Somebody else took the device') + return false + } + return true + } ) + group.on('autojoin', (id, joined) => - plugin.auth = (key, resolve, reject) => - autojoinListener(id, joined, key, resolve, reject) + plugin.auth = key => { + if (id === key.fingerprint && joined) { + return true + } + log.error('Device is already in use') + return false + } ) connector.init({ @@ -154,6 +158,6 @@ export default syrup.serial() lifecycle.observe(() => connector.stop()) group.on('leave', () => { connector.stop() - plugin.auth = (key, resolve, reject) => reject() + plugin.auth = (key) => false }) }) diff --git a/lib/units/device/plugins/filesystem.js b/lib/units/device/plugins/filesystem.js index 500e593a7f..a24964bb5b 100644 --- a/lib/units/device/plugins/filesystem.js +++ b/lib/units/device/plugins/filesystem.js @@ -7,6 +7,7 @@ import adb from '../support/adb.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import storage from '../../base-device/support/storage.js' +import {FileSystemGetMessage, FileSystemListMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -34,7 +35,7 @@ export default syrup.serial() }) }) } - router.on(wire.FileSystemGetMessage, function(channel, message) { + router.on(FileSystemGetMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.retrieve(message.file, message.jwt) .then(function(file) { @@ -51,7 +52,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.FileSystemListMessage, function(channel, message) { + router.on(FileSystemListMessage, function(channel, message) { var reply = wireutil.reply(options.serial) adb.getDevice(options.serial).readdir(message.dir) .then(function(files) { diff --git a/lib/units/device/plugins/forward/index.js b/lib/units/device/plugins/forward/index.js index bd929415c7..181ca1a560 100644 --- a/lib/units/device/plugins/forward/index.js +++ b/lib/units/device/plugins/forward/index.js @@ -13,6 +13,7 @@ import router from '../../../base-device/support/router.js' import push from '../../../base-device/support/push.js' import minirev from '../../resources/minirev.js' import group from '../group.js' +import {ForwardCreateMessage, ForwardRemoveMessage, ForwardTestMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -108,7 +109,7 @@ export default syrup.serial() .then(awaitServer) .then(function() { router - .on(wire.ForwardTestMessage, function(channel, message) { + .on(ForwardTestMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.connect(message) .then(function(conn) { @@ -125,7 +126,7 @@ export default syrup.serial() ]) }) }) - .on(wire.ForwardCreateMessage, function(channel, message) { + .on(ForwardCreateMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.createForward(message.id, message) .then(function() { @@ -142,7 +143,7 @@ export default syrup.serial() ]) }) }) - .on(wire.ForwardRemoveMessage, function(channel, message) { + .on(ForwardRemoveMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.removeForward(message.id) .then(function() { diff --git a/lib/units/device/plugins/group.js b/lib/units/device/plugins/group.js deleted file mode 100644 index 90da7e25fd..0000000000 --- a/lib/units/device/plugins/group.js +++ /dev/null @@ -1,213 +0,0 @@ -import events from 'events' -import Promise from 'bluebird' -import syrup from '@devicefarmer/stf-syrup' -import logger from '../../../util/logger.js' -import wire from '../../../wire/index.js' -import wireutil from '../../../wire/util.js' -import * as grouputil from '../../../util/grouputil.js' -import lifecycle from '../../../util/lifecycle.js' -import db from '../../../db/index.js' -import dbapi from '../../../db/api.js' -import * as apiutil from '../../../util/apiutil.js' -import solo from './solo.js' -import identity from './util/identity.js' -import service from './service.js' -import router from '../../base-device/support/router.js' -import push from '../../base-device/support/push.js' -import sub from '../../base-device/support/sub.js' -import channels from '../../base-device/support/channels.js' -export default syrup.serial() - .dependency(solo) - .dependency(identity) - .dependency(service) - .dependency(router) - .dependency(push) - .dependency(sub) - .dependency(channels) - .define(async function(options, solo, ident, /** @type {any} */ service, router, push, sub, channels) { - const log = logger.createLogger('device:plugins:group') - let currentGroup = null - - /** @type {any} */ - const plugin = new events.EventEmitter() - - await db.connect() - - plugin.get = Promise.method(function() { - if (!currentGroup) { - throw new grouputil.NoGroupError() - } - return currentGroup - }) - plugin.join = function(newGroup, timeout, usage) { - return plugin.get() - .then(function() { - if (currentGroup.group !== newGroup.group) { - log.error(`Cannot join group ${JSON.stringify(newGroup)} since this device is in group ${JSON.stringify(currentGroup)}`) - throw new grouputil.AlreadyGroupedError() - } - log.info('Update timeout for %s', apiutil.QUARTER_MINUTES) - channels.updateTimeout(currentGroup.group, apiutil.QUARTER_MINUTES) - - const newTimeout = channels.getTimeout(currentGroup.group) - dbapi.enhanceStatusChangedAt(options.serial, newTimeout) - }) - .catch(grouputil.NoGroupError, function() { - currentGroup = newGroup - log.important('Now owned by "%s"', currentGroup.email) - log.important('Device now in group "%s"', currentGroup.name) - log.info(`Rent time is ${timeout}`) - log.info('Subscribing to group channel "%s"', currentGroup.group) - channels.register(currentGroup.group, { - timeout: timeout || options.groupTimeout, - alias: solo.channel - }) - dbapi.enhanceStatusChangedAt(options.serial, timeout).then(() => { - sub.subscribe(currentGroup.group) - plugin.emit('join', currentGroup) - push.send([ - wireutil.global, - wireutil.envelope(new wire.JoinGroupMessage(options.serial, currentGroup, usage)) - ]) - service.freezeRotation(0) - return currentGroup - }) - }) - } - plugin.keepalive = function() { - if (currentGroup) { - channels.keepalive(currentGroup.group) - } - } - plugin.leave = function(reason) { - return plugin.get() - .then(function(group) { - log.important('No longer owned by "%s"', group.email) - log.info('Unsubscribing from group channel "%s"', group.group) - return dbapi.enhanceStatusChangedAt(options.serial, 0).then(() => { - push.send([ - wireutil.global, - wireutil.envelope(new wire.LeaveGroupMessage(options.serial, group, reason)) - ]) - channels.unregister(group.group) - sub.unsubscribe(group.group) - currentGroup = null - plugin.emit('leave', group) - return group - }) - }) - } - plugin.on('join', function() { - service.wake() - service.acquireWakeLock() - }) - plugin.on('leave', function() { - if (options.screenReset) { - service.pressKey('home') - service.thawRotation() - dbapi.loadDeviceBySerial(options.serial).then(device => { - if (device.group.id === device.origin) { - log.warn('Cleaning device') - service.sendCommand('settings put system screen_brightness_mode 0') - service.sendCommand('settings put system screen_brightness 0') - service.setMasterMute(true) - service.sendCommand('input keyevent 26') - service.sendCommand('settings put global http_proxy :0') - service.sendCommand('pm clear com.android.chrome') - service.sendCommand('pm clear com.chrome.beta') - service.sendCommand('pm clear com.sec.android.app.sbrowser') - service.sendCommand('pm uninstall com.vkontakte.android') - service.sendCommand('pm uninstall com.vk.im') - service.sendCommand('pm uninstall com.vk.clips') - service.sendCommand('pm uninstall com.vk.calls') - service.sendCommand('pm uninstall com.vk.admin') - service.sendCommand('pm clear com.mi.globalbrowser') - service.sendCommand('pm clear com.microsoft.emmx') - service.sendCommand('pm clear com.huawei.browser') - service.sendCommand('pm uninstall --user 0 com.samsung.clipboardsaveservice') - service.sendCommand('pm uninstall --user 0 com.samsung.android.clipboarduiservice') - service.sendCommand('rm -rf /sdcard/Downloads') - service.sendCommand('rm -rf /storage/emulated/legacy/Downloads') - service.sendCommand('settings put global always_finish_activities 0') - service.sendCommand('pm enable-user com.google.android.gms') - service.sendCommand('settings put system font_scale 1.0') - service.sendCommand('su') - service.sendCommand('echo "chrome --disable-fre --no-default-browser-check --no-first-run" > /data/local/tmp/chrome-command-line') - service.sendCommand('am set-debug-app --persistent com.android.chrome') - } - else { - log.warn('Device was not cleared because it in custom group') - } - }) - } - service.releaseWakeLock() - }) - router - .on(wire.GroupMessage, function(channel, message) { - let reply = wireutil.reply(options.serial) - grouputil.match(ident, message.requirements) - .then(function() { - return plugin.join(message.owner, message.timeout, message.usage) - }) - .then(function() { - push.send([ - channel, - reply.okay() - ]) - }) - .catch(grouputil.RequirementMismatchError, function(err) { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - .catch(grouputil.AlreadyGroupedError, function(err) { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - }) - .on(wire.AutoGroupMessage, function(channel, message) { - return plugin.join(message.owner, message.timeout, message.identifier) - .then(function() { - plugin.emit('autojoin', message.identifier, true) - }) - .catch(grouputil.AlreadyGroupedError, function() { - plugin.emit('autojoin', message.identifier, false) - }) - }) - .on(wire.UngroupMessage, function(channel, message) { - let reply = wireutil.reply(options.serial) - grouputil.match(ident, message.requirements) - .then(function() { - return plugin.leave('ungroup_request') - }) - .then(function() { - push.send([ - channel, - reply.okay() - ]) - }) - .catch(grouputil.NoGroupError, function(err) { - push.send([ - channel, - reply.fail(err.message) - ]) - }) - }) - - // @ts-ignore - channels.on('timeout', function(channel) { - if (currentGroup && channel === currentGroup.group) { - plugin.leave('automatic_timeout') - } - }) - lifecycle.observe(function() { - return plugin.leave('device_absent') - .catch(grouputil.NoGroupError, function() { - return true - }) - }) - return plugin - }) diff --git a/lib/units/device/plugins/group.ts b/lib/units/device/plugins/group.ts new file mode 100644 index 0000000000..c628918805 --- /dev/null +++ b/lib/units/device/plugins/group.ts @@ -0,0 +1,96 @@ +import syrup from '@devicefarmer/stf-syrup' +import logger from '../../../util/logger.js' +import {DeviceGetIsInOrigin} from '../../../wire/wire.js' +import wireutil from '../../../wire/util.js' +import * as grouputil from '../../../util/grouputil.js' +import solo from './solo.js' +import identity from './util/identity.js' +import service from './service.js' +import router from '../../base-device/support/router.js' +import push from '../../base-device/support/push.js' +import sub from '../../base-device/support/sub.js' +import channels from '../../base-device/support/channels.js' +import group from '../../base-device/plugins/group.js' +import {runTransactionDev} from '../../../wire/transmanager.js' + +export default syrup.serial() + .dependency(solo) + .dependency(identity) + .dependency(service) + .dependency(router) + .dependency(push) + .dependency(sub) + .dependency(channels) + .dependency(group) + .define(async(options, solo, ident, /** @type {any} */ service, router, push, sub, channels, group) => { + const log = logger.createLogger('device:plugins:group') + + group.setCheckBeforeAction(async(message: any) => + !message.requirements || grouputil.match(ident, message.requirements) + ) + + group.on('join', () => { + service.freezeRotation(0) + service.wake() + service.acquireWakeLock() + }) + + group.on('leave', async() => { + try { + if (options.screenReset) { + service.pressKey('home') + service.thawRotation() + + const {isInOrigin} = await runTransactionDev( + wireutil.global, + DeviceGetIsInOrigin, + {serial: options.serial}, + {sub, push, router} + ) as { isInOrigin: boolean } + + if (isInOrigin) { + log.warn('Cleaning device') + await Promise.all([ + service.sendCommand('settings put system screen_brightness_mode 0'), + service.sendCommand('settings put system screen_brightness 0'), + service.setMasterMute(true), + service.sendCommand('input keyevent 26'), + service.sendCommand('settings put global http_proxy :0'), + service.sendCommand('pm clear com.android.chrome'), + service.sendCommand('pm clear com.chrome.beta'), + service.sendCommand('pm clear com.sec.android.app.sbrowser'), + service.sendCommand('pm uninstall com.vkontakte.android'), + service.sendCommand('pm uninstall com.vk.im'), + service.sendCommand('pm uninstall com.vk.clips'), + service.sendCommand('pm uninstall com.vk.calls'), + service.sendCommand('pm uninstall com.vk.admin'), + service.sendCommand('pm clear com.mi.globalbrowser'), + service.sendCommand('pm clear com.microsoft.emmx'), + service.sendCommand('pm clear com.huawei.browser'), + service.sendCommand('pm uninstall --user 0 com.samsung.clipboardsaveservice'), + service.sendCommand('pm uninstall --user 0 com.samsung.android.clipboarduiservice'), + service.sendCommand('rm -rf /sdcard/Downloads'), + service.sendCommand('rm -rf /storage/emulated/legacy/Downloads'), + service.sendCommand('settings put global always_finish_activities 0'), + service.sendCommand('pm enable-user com.google.android.gms'), + service.sendCommand('settings put system font_scale 1.0'), + service.sendCommand('su'), + service.sendCommand('echo "chrome --disable-fre --no-default-browser-check --no-first-run" > /data/local/tmp/chrome-command-line'), + service.sendCommand('am set-debug-app --persistent com.android.chrome') + ]) + } + else { + log.warn('Device was not cleared because it in custom group') + } + } + } + catch (err: any) { + log.error('Clear device on group.leave failed: %s', err?.message) + } + finally { + service.releaseWakeLock() + } + }) + + return group + }) diff --git a/lib/units/device/plugins/install.js b/lib/units/device/plugins/install.js index e2384ef20f..9eae1703d2 100644 --- a/lib/units/device/plugins/install.js +++ b/lib/units/device/plugins/install.js @@ -11,6 +11,7 @@ import adb from '../support/adb.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import storage from '../../base-device/support/storage.js' +import {InstallMessage, UninstallMessage} from '../../../wire/wire.js' // @ts-ignore const readAll = async(stream) => Utils.readAll(stream) @@ -24,7 +25,7 @@ export default syrup.serial() const log = logger.createLogger('device:plugins:install') const reply = wireutil.reply(options.serial) - router.on(wire.InstallMessage, async(channel, message) => { + router.on(InstallMessage, async(channel, message) => { const manifest = JSON.parse(message.manifest) const pkg = manifest.package const installFlags = message.installFlags @@ -197,7 +198,7 @@ export default syrup.serial() } }) - router.on(wire.UninstallMessage, async(channel, message) => { + router.on(UninstallMessage, async(channel, message) => { log.info('Uninstalling "%s"', message.packageName) try { await adb.getDevice(options.serial).uninstall(message.packageName) diff --git a/lib/units/device/plugins/logcat.js b/lib/units/device/plugins/logcat.js index b90f6b3b12..b88c9f2ab4 100644 --- a/lib/units/device/plugins/logcat.js +++ b/lib/units/device/plugins/logcat.js @@ -8,6 +8,7 @@ import adb from '../support/adb.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import group from './group.js' +import {LogcatApplyFiltersMessage, LogcatStartMessage, LogcatStopMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -69,7 +70,7 @@ export default syrup.serial() lifecycle.observe(plugin.stop) group.on('leave', plugin.stop) router - .on(wire.LogcatStartMessage, function(channel, message) { + .on(LogcatStartMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.start(message.filters) .then(function() { @@ -86,7 +87,7 @@ export default syrup.serial() ]) }) }) - .on(wire.LogcatApplyFiltersMessage, function(channel, message) { + .on(LogcatApplyFiltersMessage, function(channel, message) { var reply = wireutil.reply(options.serial) plugin.reset(message.filters) .then(function() { @@ -103,7 +104,7 @@ export default syrup.serial() ]) }) }) - .on(wire.LogcatStopMessage, function(channel) { + .on(LogcatStopMessage, function(channel) { var reply = wireutil.reply(options.serial) plugin.stop() .then(function() { diff --git a/lib/units/device/plugins/reboot.js b/lib/units/device/plugins/reboot.js index 4e95cf4cfc..f872fe8a46 100644 --- a/lib/units/device/plugins/reboot.js +++ b/lib/units/device/plugins/reboot.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import adb from '../support/adb.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {RebootMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) .dependency(push) .define(function(options, adb, router, push) { const log = logger.createLogger('device:plugins:reboot') - router.on(wire.RebootMessage, function(channel) { + router.on(RebootMessage, function(channel) { let reply = wireutil.reply(options.serial) log.important('Rebooting') adb.getDevice(options.serial).reboot() diff --git a/lib/units/device/plugins/ringer.js b/lib/units/device/plugins/ringer.js index 61d4445fa5..bafbfe9a19 100644 --- a/lib/units/device/plugins/ringer.js +++ b/lib/units/device/plugins/ringer.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import service from './service.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {RingerGetMessage, RingerSetMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(service) .dependency(router) .dependency(push) .define(function(options, service, router, push) { var log = logger.createLogger('device:plugins:ringer') - router.on(wire.RingerSetMessage, function(channel, message) { + router.on(RingerSetMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Setting ringer mode to mode "%s"', message.mode) service.setRingerMode(message.mode) @@ -30,7 +31,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.RingerGetMessage, function(channel) { + router.on(RingerGetMessage, function(channel) { var reply = wireutil.reply(options.serial) log.info('Getting ringer mode') service.getRingerMode() diff --git a/lib/units/device/plugins/screen/capture.js b/lib/units/device/plugins/screen/capture.js index ed074b5e82..5d689d2be5 100644 --- a/lib/units/device/plugins/screen/capture.js +++ b/lib/units/device/plugins/screen/capture.js @@ -10,6 +10,7 @@ import push from '../../../base-device/support/push.js' import storage from '../../../base-device/support/storage.js' import minicap from '../../resources/minicap.js' import display from '../util/display.js' +import {ScreenCaptureMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -48,7 +49,7 @@ export default syrup.serial() .then(Adb.util.readAll) }) } - router.on(wire.ScreenCaptureMessage, function(channel) { + router.on(ScreenCaptureMessage, function(channel) { var reply = wireutil.reply(options.serial) plugin.capture() .then(function(file) { diff --git a/lib/units/device/plugins/screen/stream.js b/lib/units/device/plugins/screen/stream.js index 77e2b52183..5305c28868 100644 --- a/lib/units/device/plugins/screen/stream.js +++ b/lib/units/device/plugins/screen/stream.js @@ -25,6 +25,7 @@ import options from './options.js' import group from '../group.js' import * as jwtutil from '../../../../util/jwtutil.js' import {NoGroupError} from '../../../../util/grouputil.js' +import {ChangeQualityMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -439,7 +440,7 @@ export default syrup.serial() display.on('rotationChange', function(newRotation) { frameProducer.updateRotation(newRotation) }) - router.on(wire.ChangeQualityMessage, function(channel, message) { + router.on(ChangeQualityMessage, function(channel, message) { frameProducer.changeQuality(message.quality) }) frameProducer.on('start', function() { diff --git a/lib/units/device/plugins/sd.js b/lib/units/device/plugins/sd.js index 382315fd32..da4aca405c 100644 --- a/lib/units/device/plugins/sd.js +++ b/lib/units/device/plugins/sd.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import service from './service.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {SdStatusMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(service) .dependency(router) .dependency(push) .define(function(options, service, router, push) { var log = logger.createLogger('device:plugins:sd') - router.on(wire.SdStatusMessage, function(channel, message) { + router.on(SdStatusMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Getting SD card status') service.getSdStatus(message) diff --git a/lib/units/device/plugins/service.ts b/lib/units/device/plugins/service.ts index 58beea37c4..4187b9224f 100644 --- a/lib/units/device/plugins/service.ts +++ b/lib/units/device/plugins/service.ts @@ -16,6 +16,15 @@ import service from '../resources/service.js' import {Duplex} from 'node:stream' import EventEmitter from 'events' import {GRPC_WAIT_TIMEOUT} from '../../../util/apiutil.js' +import { + PhysicalIdentifyMessage, + KeyDownMessage, + KeyUpMessage, + KeyPressMessage, + TypeMessage, + RotateMessage, + UnlockDeviceMessage +} from "../../../wire/wire.js"; interface Service { socket: Duplex | null @@ -230,7 +239,6 @@ export default syrup.serial() getDisplay = (id: string) => runServiceCommand(apk.wire.MessageType.GET_DISPLAY, new apk.wire.GetDisplayRequest(id)) .then((data) => { - log.info('DISPLAY RESPONSE !') const response = apk.wire.GetDisplayResponse.decode(data) if (response.success) { return { @@ -562,7 +570,7 @@ export default syrup.serial() log.important('Agent connection ended, attempting to relaunch') try { await openAgent() - log.important('Agent relaunched in %dms', Date.now() - startTime) + log.important('Agent relaunched in %sms', Date.now() - startTime) resolve() } catch (err: any) { @@ -601,7 +609,7 @@ export default syrup.serial() log.important('Service connection ended, attempting to relaunch') await openAgent() // restart agent await openService() - log.important('Service relaunched in %dms', Date.now() - startTime) + log.important('Service relaunched in %sms', Date.now() - startTime) } catch (err: any) { log.fatal('[prepareForServiceDeath] Service connection could not be relaunched: %s', err?.message) @@ -638,14 +646,14 @@ export default syrup.serial() await openService() router - .on(wire.PhysicalIdentifyMessage, (channel) => { + .on(PhysicalIdentifyMessage, (channel) => { plugin.identity() push.send([ channel, wireutil.reply(options.serial).okay() ]) }) - .on(wire.KeyDownMessage, (channel, message) => { + .on(KeyDownMessage, (channel, message) => { try { keyEvent({ event: apk.wire.KeyEvent.DOWN, @@ -656,7 +664,7 @@ export default syrup.serial() log.warn(e.message) } }) - .on(wire.KeyUpMessage, (channel, message) => { + .on(KeyUpMessage, (channel, message) => { try { keyEvent({ event: apk.wire.KeyEvent.UP, @@ -667,7 +675,7 @@ export default syrup.serial() log.warn(e.message) } }) - .on(wire.KeyPressMessage, (channel, message) => { + .on(KeyPressMessage, (channel, message) => { try { keyEvent({ event: apk.wire.KeyEvent.PRESS, @@ -678,13 +686,13 @@ export default syrup.serial() log.warn(e.message) } }) - .on(wire.TypeMessage, (channel, message) => + .on(TypeMessage, (channel, message) => plugin.type(message.text) ) - .on(wire.RotateMessage, (channel, message) => + .on(RotateMessage, (channel, message) => plugin.rotate(message.rotation) ) - .on(wire.UnlockDeviceMessage, (channel, message) => + .on(UnlockDeviceMessage, (channel, message) => plugin.unlockDevice() ) return plugin diff --git a/lib/units/device/plugins/shell.js b/lib/units/device/plugins/shell.js index 8bbe76ceff..4ce1ef79c4 100644 --- a/lib/units/device/plugins/shell.js +++ b/lib/units/device/plugins/shell.js @@ -7,6 +7,7 @@ import adb from '../support/adb.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import sub from '../../base-device/support/sub.js' +import {ShellCommandMessage, ShellKeepAliveMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -14,7 +15,7 @@ export default syrup.serial() .dependency(sub) .define(function(options, adb, router, push, sub) { var log = logger.createLogger('device:plugins:shell') - router.on(wire.ShellCommandMessage, async function(channel, message) { + router.on(ShellCommandMessage, async function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Running shell command "%s"', message.command) const stream = await adb.getDevice(options.serial).shell(message.command) @@ -52,7 +53,7 @@ export default syrup.serial() stream.on('end', endListener) stream.on('error', errorListener) sub.subscribe(channel) - router.on(wire.ShellKeepAliveMessage, keepAliveListener) + router.on(ShellKeepAliveMessage, keepAliveListener) timer = setTimeout(forceStop, message.timeout) return resolver.promise.finally(function() { stream.removeListener('readable', readableListener) diff --git a/lib/units/device/plugins/solo.js b/lib/units/device/plugins/solo.js index dbc97524a1..e151d124e2 100644 --- a/lib/units/device/plugins/solo.js +++ b/lib/units/device/plugins/solo.js @@ -7,6 +7,7 @@ import sub from '../../base-device/support/sub.js' import push from '../../base-device/support/push.js' import router from '../../base-device/support/router.js' import identity from './util/identity.js' +import {DeviceDisplayMessage, DeviceIdentityMessage, DevicePhoneMessage, ProbeMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(sub) .dependency(push) @@ -24,10 +25,27 @@ export default syrup.serial() var channel = makeChannelId() log.info('Subscribing to permanent channel "%s"', channel) sub.subscribe(channel) - router.on(wire.ProbeMessage, function() { + router.on(ProbeMessage, function() { push.send([ wireutil.global, - wireutil.envelope(new wire.DeviceIdentityMessage(options.serial, identity.platform, identity.manufacturer, identity.operator, identity.model, identity.version, identity.abi, identity.sdk, new wire.DeviceDisplayMessage(identity.display), new wire.DevicePhoneMessage(identity.phone), identity.product, identity.cpuPlatform, identity.openGLESVersion, identity.marketName, identity.macAddress, identity.ram)) + wireutil.pack(DeviceIdentityMessage, { + serial: options.serial, + platform: identity.platform, + manufacturer: identity.manufacturer, + operator: identity.operator, + model: identity.model, + version: identity.version, + abi: identity.abi, + sdk: identity.sdk, + display: DeviceDisplayMessage.create(identity.display), + phone: DevicePhoneMessage.create(identity.phone), + product: identity.product, + cpuPlatform: identity.cpuPlatform, + openGLESVersion: identity.openGLESVersion, + marketName: identity.marketName, + macAddress: identity.macAddress, + ram: identity.ram + }) ]) }) return { diff --git a/lib/units/device/plugins/store.js b/lib/units/device/plugins/store.js index 8981525856..00d1a657eb 100644 --- a/lib/units/device/plugins/store.js +++ b/lib/units/device/plugins/store.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import adb from '../support/adb.js' +import {StoreOpenMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(router) .dependency(push) .dependency(adb) .define(function(options, router, push, adb) { var log = logger.createLogger('device:plugins:store') - router.on(wire.StoreOpenMessage, function(channel) { + router.on(StoreOpenMessage, function(channel) { log.info('Opening Play Store') var reply = wireutil.reply(options.serial) adb.getDevice(options.serial).startActivity({ diff --git a/lib/units/device/plugins/touch/index.js b/lib/units/device/plugins/touch/index.js index 028b44a8cc..e3256c771b 100644 --- a/lib/units/device/plugins/touch/index.js +++ b/lib/units/device/plugins/touch/index.js @@ -15,6 +15,7 @@ import adb from '../../support/adb.js' import router from '../../../base-device/support/router.js' import minitouch from '../../resources/minitouch.js' import flags from '../util/flags.js' +import {GestureStartMessage, GestureStopMessage, TouchCommitMessage, TouchDownMessage, TouchMoveMessage, TouchResetMessage, TouchUpMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(adb) .dependency(router) @@ -434,35 +435,35 @@ export default syrup.serial() lifecycle.fatal() }) router - .on(wire.GestureStartMessage, function(channel, message) { + .on(GestureStartMessage, function(channel, message) { queue.start(message.seq) }) - .on(wire.GestureStopMessage, function(channel, message) { + .on(GestureStopMessage, function(channel, message) { queue.push(message.seq, function() { queue.stop() }) }) - .on(wire.TouchDownMessage, function(channel, message) { + .on(TouchDownMessage, function(channel, message) { queue.push(message.seq, function() { touchConsumer.touchDown(message) }) }) - .on(wire.TouchMoveMessage, function(channel, message) { + .on(TouchMoveMessage, function(channel, message) { queue.push(message.seq, function() { touchConsumer.touchMove(message) }) }) - .on(wire.TouchUpMessage, function(channel, message) { + .on(TouchUpMessage, function(channel, message) { queue.push(message.seq, function() { touchConsumer.touchUp(message) }) }) - .on(wire.TouchCommitMessage, function(channel, message) { + .on(TouchCommitMessage, function(channel, message) { queue.push(message.seq, function() { touchConsumer.touchCommit() }) }) - .on(wire.TouchResetMessage, function(channel, message) { + .on(TouchResetMessage, function(channel, message) { queue.push(message.seq, function() { touchConsumer.touchReset() }) diff --git a/lib/units/device/plugins/vnc/index.js b/lib/units/device/plugins/vnc/index.js index 7fd31c34ff..f980a369df 100644 --- a/lib/units/device/plugins/vnc/index.js +++ b/lib/units/device/plugins/vnc/index.js @@ -19,6 +19,7 @@ import stream from '../screen/stream.js' import touch from '../touch/index.js' import group from '../group.js' import solo from '../solo.js' +import {VncAuthResponsesUpdatedMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(router) .dependency(push) @@ -63,7 +64,7 @@ export default syrup.serial() } group.on('join', joinListener) group.on('autojoin', autojoinListener) - router.on(wire.VncAuthResponsesUpdatedMessage, notify) + router.on(VncAuthResponsesUpdatedMessage, notify) notify() return resolver.promise .timeout(5000) diff --git a/lib/units/device/plugins/wifi.js b/lib/units/device/plugins/wifi.js index 742796b927..8aace2359f 100644 --- a/lib/units/device/plugins/wifi.js +++ b/lib/units/device/plugins/wifi.js @@ -5,13 +5,14 @@ import wireutil from '../../../wire/util.js' import service from './service.js' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {WifiGetStatusMessage, WifiSetEnabledMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(service) .dependency(router) .dependency(push) .define(function(options, service, router, push) { var log = logger.createLogger('device:plugins:wifi') - router.on(wire.WifiSetEnabledMessage, function(channel, message) { + router.on(WifiSetEnabledMessage, function(channel, message) { var reply = wireutil.reply(options.serial) log.info('Setting Wifi "%s"', message.enabled) service.setWifiEnabled(message.enabled) @@ -30,7 +31,7 @@ export default syrup.serial() ]) }) }) - router.on(wire.WifiGetStatusMessage, function(channel) { + router.on(WifiGetStatusMessage, function(channel) { var reply = wireutil.reply(options.serial) log.info('Getting Wifi status') service.getWifiStatus() diff --git a/lib/units/device/resources/service.js b/lib/units/device/resources/service.js index cb62d36c7d..8a10ed4841 100644 --- a/lib/units/device/resources/service.js +++ b/lib/units/device/resources/service.js @@ -22,7 +22,8 @@ export default syrup.serial() startIntent: { action: 'jp.co.cyberagent.stf.ACTION_START', component: 'jp.co.cyberagent.stf/.Service' - } + }, + path: '' } // am startservice -a jp.co.cyberagent.stf.ACTION_START jp.co.cyberagent.stf/.Service function getPath() { diff --git a/lib/units/groups-engine/index.js b/lib/units/groups-engine/index.js index f2aa35adb3..7ccb596dd6 100644 --- a/lib/units/groups-engine/index.js +++ b/lib/units/groups-engine/index.js @@ -1,6 +1,5 @@ import devicesWatcher from './watchers/devices.js' import lifecycle from '../../util/lifecycle.js' -import usersWatcher from './watchers/users.js' import logger from '../../util/logger.js' import db from '../../db/index.js' @@ -10,17 +9,14 @@ export default (async function(options) { const { push , pushdev - , sub - , subdev , channelRouter } = await db.createZMQSockets(options.endpoints, log) - await db.connect(push, pushdev, channelRouter) + await db.connect() devicesWatcher(push, pushdev, channelRouter) - usersWatcher(pushdev) lifecycle.observe(() => - [push, sub, pushdev, subdev].forEach((sock) => sock.close()) + [push, pushdev].forEach((sock) => sock.close()) ) log.info('Groups engine started') }) diff --git a/lib/units/groups-engine/watchers/devices.js b/lib/units/groups-engine/watchers/devices.js index 0dd21bef2e..ee6470403f 100644 --- a/lib/units/groups-engine/watchers/devices.js +++ b/lib/units/groups-engine/watchers/devices.js @@ -8,6 +8,7 @@ import wireutil from '../../../wire/util.js' import wire from '../../../wire/index.js' import dbapi from '../../../db/api.js' import db from '../../../db/index.js' +import {LeaveGroupMessage} from '../../../wire/wire.js' export default (function(push, pushdev, channelRouter) { const log = logger.createLogger('watcher-devices') function sendReleaseDeviceControl(serial, channel) { @@ -36,7 +37,7 @@ export default (function(push, pushdev, channelRouter) { delete device.group.lifeTime return device } - pushdev.send([ + push.send([ wireutil.global, wireutil.envelope(new wire.DeviceChangeMessage(publishDevice(), action, device2.group.origin, timeutil.now('nano'))) ]) @@ -48,7 +49,7 @@ export default (function(push, pushdev, channelRouter) { sendDeviceGroupChangeWrapper() }, 5000) messageListener = new WireRouter() - .on(wire.LeaveGroupMessage, function(channel, message) { + .on(LeaveGroupMessage, function(channel, message) { if (message.serial === device.serial && message.owner.email === device.owner.email) { clearTimeout(responseTimer) diff --git a/lib/units/groups-engine/watchers/users.js b/lib/units/groups-engine/watchers/users.js deleted file mode 100644 index 6ae21ffc59..0000000000 --- a/lib/units/groups-engine/watchers/users.js +++ /dev/null @@ -1,105 +0,0 @@ -import timeutil from '../../../util/timeutil.js' -import _ from 'lodash' -import logger from '../../../util/logger.js' -import wireutil from '../../../wire/util.js' -import wire from '../../../wire/index.js' -import db from '../../../db/index.js' -export default (function(pushdev) { - const log = logger.createLogger('watcher-users') - function sendUserChange(user, isAddedGroup, groups, action, targets) { - pushdev.send([ - wireutil.global, - wireutil.envelope(new wire.UserChangeMessage(user, isAddedGroup, groups, action, targets, timeutil.now('nano'))) - ]) - } - let changeStream - db.connect().then(client => { - const users = client.collection('users') - changeStream = users.watch([ - { - $project: { - 'fullDocument.email': 1, - 'fullDocument.name': 1, - 'fullDocument.privilege': 1, - 'fullDocument.groups.quotas': 1, - 'fullDocument.groups.subscribed': 1, - 'fullDocument.settings.alertMessage': 1, - 'fullDocumentBeforeChange.email': 1, - 'fullDocumentBeforeChange.name': 1, - 'fullDocumentBeforeChange.privilege': 1, - 'fullDocumentBeforeChange.groups.quotas': 1, - 'fullDocumentBeforeChange.groups.subscribed': 1, - 'fullDocumentBeforeChange.settings.alertMessage': 1, - operationType: 1 - } - } - ], {fullDocument: 'whenAvailable', fullDocumentBeforeChange: 'whenAvailable'}) - changeStream.on('change', next => { - log.info('Users watcher next: ' + JSON.stringify(next)) - try { - let newDoc, oldDoc - let operationType = next.operationType - // @ts-ignore - if (next.fullDocument) { - // @ts-ignore - newDoc = next.fullDocument - } - else { - newDoc = null - } - // @ts-ignore - if (next.fullDocumentBeforeChange) { - // @ts-ignore - oldDoc = next.fullDocumentBeforeChange - } - else { - oldDoc = null - } - if (newDoc === null && oldDoc === null) { - log.info('New user doc and old user doc is NULL') - return false - } - if (operationType === 'insert') { - sendUserChange(newDoc, false, [], 'created', ['settings']) - } - else if (operationType === 'delete') { - sendUserChange(oldDoc, false, [], 'deleted', ['settings']) - } - else { - const targets = [] - if (newDoc.groups && oldDoc.groups) { - if (newDoc.groups.quotas && oldDoc.groups.quotas) { - if (!_.isEqual(newDoc.groups.quotas.allocated, oldDoc.groups.quotas.allocated)) { - targets.push('settings') - targets.push('view') - } - else if (!_.isEqual(newDoc.groups.quotas.consumed, oldDoc.groups.quotas.consumed)) { - targets.push('view') - } - else if (newDoc.groups.quotas.defaultGroupsNumber !== - oldDoc.groups.quotas.defaultGroupsNumber || - newDoc.groups.defaultGroupsDuration !== - oldDoc.groups.quotas.defaultGroupsDuration || - newDoc.groups.defaultGroupsRepetitions !== - oldDoc.groups.quotas.defaultGroupsRepetitions || - newDoc.groups.repetitions !== - oldDoc.groups.quotas.repetitions || - !_.isEqual(newDoc.groups.subscribed, oldDoc.groups.subscribed)) { - targets.push('settings') - } - } - } - else if (!_.isEqual(newDoc.settings.alertMessage, oldDoc.settings.alertMessage)) { - targets.push('menu') - } - if (targets.length) { - sendUserChange(newDoc, newDoc.groups.subscribed.length > oldDoc.groups.subscribed.length, _.xor(newDoc.groups.subscribed, oldDoc.groups.subscribed), 'updated', targets) - } - } - } - catch (e) { - log.error(e) - } - }) - }) -}) diff --git a/lib/units/ios-device/plugins/clipboard.js b/lib/units/ios-device/plugins/clipboard.js index b48c3e0c0e..140f4b3f69 100755 --- a/lib/units/ios-device/plugins/clipboard.js +++ b/lib/units/ios-device/plugins/clipboard.js @@ -5,13 +5,14 @@ import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import wdaClient from './wda/client.js' import Logger from '../../../util/logger.js' +import {CopyMessage} from '../../../wire/wire.js' const log = Logger.createLogger('ios-device:clipboard') export default syrup.serial() .dependency(router) .dependency(push) .dependency(wdaClient) .define(function(options, router, push, wdaClient) { - router.on(wire.CopyMessage, function(channel) { + router.on(CopyMessage, function(channel) { const reply = wireutil.reply(options.serial) wdaClient.getClipBoard() .then(clipboard => { diff --git a/lib/units/ios-device/plugins/devicelog.js b/lib/units/ios-device/plugins/devicelog.js index 2f0cf184df..534c2ec923 100755 --- a/lib/units/ios-device/plugins/devicelog.js +++ b/lib/units/ios-device/plugins/devicelog.js @@ -12,6 +12,7 @@ import sub from '../../base-device/support/sub.js' import group from '../../base-device/plugins/group.js' import nsyslogParser from 'nsyslog-parser' import db from '../../../db/index.js' +import {LogcatStartMessage, LogcatStopMessage, GroupMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(push) @@ -102,7 +103,7 @@ export default syrup.serial() group.on('leave', deviceLogger.killLoggingProcess) router - .on(wire.LogcatStartMessage, async function(channel, message) { + .on(LogcatStartMessage, async function(channel, message) { const reply = wireutil.reply(options.serial) try { await dbapi.loadDeviceBySerial(options.serial) @@ -114,12 +115,12 @@ export default syrup.serial() deviceLogger.killLoggingProcess() } }) - .on(wire.LogcatStopMessage, function(channel, data) { + .on(LogcatStopMessage, function(channel, data) { const reply = wireutil.reply(options.serial) deviceLogger.killLoggingProcess() push.send([channel, reply.okay('success')]) }) - .on(wire.GroupMessage, function(channel, data) { + .on(GroupMessage, function(channel, data) { deviceLogger.channel = channel }) diff --git a/lib/units/ios-device/plugins/filesystem.js b/lib/units/ios-device/plugins/filesystem.js index 13d5abbbf3..b9fc1b20e2 100644 --- a/lib/units/ios-device/plugins/filesystem.js +++ b/lib/units/ios-device/plugins/filesystem.js @@ -9,6 +9,7 @@ import {execFile} from 'child_process' import path from 'path' import fs from 'fs' import {v4 as uuidv4} from 'uuid' +import {FileSystemGetMessage, FileSystemListMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(router) .dependency(push) @@ -28,7 +29,7 @@ export default syrup.serial() } } - router.on(wire.FileSystemGetMessage, function(channel, message) { + router.on(FileSystemGetMessage, function(channel, message) { let reply = wireutil.reply(options.serial) let file = message.file let currentPath = file.split('/') @@ -72,7 +73,7 @@ export default syrup.serial() } ) }) - router.on(wire.FileSystemListMessage, function(channel, message) { + router.on(FileSystemListMessage, function(channel, message) { let reply = wireutil.reply(options.serial) let dirs = [] let rootDir = message.dir diff --git a/lib/units/ios-device/plugins/info/index.js b/lib/units/ios-device/plugins/info/index.js index 6557014b97..d857a01937 100644 --- a/lib/units/ios-device/plugins/info/index.js +++ b/lib/units/ios-device/plugins/info/index.js @@ -120,7 +120,10 @@ export default syrup.serial() let scale = parsedResponse.value.scale height *= scale width *= scale + + Object.assign(extendedInfo, {width, height, scale}) log.info('Storing device size/scale') + push.send([ wireutil.global, wireutil.envelope(new wire.SizeIosDevice(options.serial, height, width, scale)) diff --git a/lib/units/ios-device/plugins/install.js b/lib/units/ios-device/plugins/install.js index 425950e190..0d95efd686 100755 --- a/lib/units/ios-device/plugins/install.js +++ b/lib/units/ios-device/plugins/install.js @@ -10,6 +10,7 @@ import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import storage from '../../base-device/support/storage.js' import deviceutil from '../../../util/deviceutil.js' +import {InstallMessage} from '../../../wire/wire.js' function execShellCommand(cmd) { return new Promise((resolve, reject) => { @@ -49,7 +50,7 @@ export default syrup.serial() const log = logger.createLogger('ios-device:plugins:install') const reply = wireutil.reply(options.serial) - router.on(wire.InstallMessage, async function(channel, message) { + router.on(InstallMessage, async function(channel, message) { log.info('Installing application from "%s"', message.href) const jwt = message.jwt @@ -99,7 +100,7 @@ export default syrup.serial() cleanup() }) }) - router.on(wire.UninstallIosMessage, function(channel, message) { + router.on(UninstallIosMessage, function(channel, message) { uninstallApp(options.serial, message.packageName) }) }) diff --git a/lib/units/ios-device/plugins/reboot.js b/lib/units/ios-device/plugins/reboot.js index 231944e61d..5c4cd53839 100755 --- a/lib/units/ios-device/plugins/reboot.js +++ b/lib/units/ios-device/plugins/reboot.js @@ -7,12 +7,13 @@ import wireutil from '../../../wire/util.js' import {execFileSync} from 'child_process' import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' +import {RebootMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(router) .dependency(push) .define((options, router, push) => { const log = logger.createLogger('device:plugins:reboot') - router.on(wire.RebootMessage, (channel) => { + router.on(RebootMessage, (channel) => { log.important('Rebooting') const reply = wireutil.reply(options.serial) let udid = options.serial diff --git a/lib/units/ios-device/plugins/wda/client.js b/lib/units/ios-device/plugins/wda/client.js index c67e829af7..cf1d48c2ce 100644 --- a/lib/units/ios-device/plugins/wda/client.js +++ b/lib/units/ios-device/plugins/wda/client.js @@ -10,12 +10,14 @@ import lifecycle from '../../../../util/lifecycle.js' import db from '../../../../db/index.js' import dbapi from '../../../../db/api.js' import devicenotifier from '../devicenotifier.js' +import info from '../info/index.js' import push from '../../../base-device/support/push.js' const LOG_REQUEST_MSG = 'Request has been sent to WDA with data: ' export default syrup.serial() .dependency(devicenotifier) .dependency(push) - .define(async(options, notifier, push) => { + .dependency(info) + .define(async(options, notifier, push, info) => { const log = logger.createLogger('wdaClient') log.info('WdaClient.js initializing...') await db.connect() @@ -422,34 +424,23 @@ export default syrup.serial() return this.deviceSize } log.info('getting device window size...') - return dbapi.getDeviceDisplaySize(options.serial).then((deviceSize) => { - if (!deviceSize) { - return null - } - let dbHeight = deviceSize.height - let dbWidth = deviceSize.width - let dbScale = deviceSize.scale - if (!dbHeight || !dbWidth || !dbScale) { - return null - } - // Reuse DB values: - log.info('Reusing device size/scale') - // Set device size based on orientation, default is PORTRAIT - if (this.orientation === 'PORTRAIT' || !this.orientation) { - this.deviceSize = {height: dbHeight /= dbScale, width: dbWidth /= dbScale} - } - else if (this.orientation === 'LANDSCAPE') { - this.deviceSize = {height: dbWidth /= dbScale, width: dbHeight /= dbScale} - } - else if (this.deviceType === 'Apple TV') { - this.deviceSize = {height: dbHeight, width: dbWidth} - } - return this.deviceSize - }) - .catch((err) => { - log.error('Error getting device size from DB') - return lifecycle.fatal(err) - }) + const {width, height, scale} = info.extendedInfo + + if (!width || !height || !scale) { + return null + } + + // Set device size based on orientation, default is PORTRAIT + if (this.orientation === 'PORTRAIT' || !this.orientation) { + this.deviceSize = {height: height / scale, width: width / scale} + } + else if (this.orientation === 'LANDSCAPE') { + this.deviceSize = {height: width / scale, width: height / scale} + } + else if (this.deviceType === 'Apple TV') { + this.deviceSize = {height: height, width: width} + } + return this.deviceSize } setVersion(currentSession) { log.info('Setting current device version: ' + currentSession.value.capabilities.sdkVersion) diff --git a/lib/units/ios-device/plugins/wda/index.js b/lib/units/ios-device/plugins/wda/index.js index a94d9e1871..acda59c6e4 100755 --- a/lib/units/ios-device/plugins/wda/index.js +++ b/lib/units/ios-device/plugins/wda/index.js @@ -12,6 +12,7 @@ import push from '../../../base-device/support/push.js' import sub from '../../../base-device/support/sub.js' import wdaClient from './client.js' import {Esp32Touch} from '../touch/esp32touch.js' +import {BrowserOpenMessage, DashboardOpenMessage, KeyDownMessage, KeyPressMessage, PhysicalIdentifyMessage, RotateMessage, ScreenCaptureMessage, StoreOpenMessage, TapDeviceTreeElement, TouchDownMessage, TouchMoveIosMessage, TouchMoveMessage, TouchUpMessage, TypeMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(push) .dependency(sub) @@ -46,7 +47,7 @@ export default syrup.serial() }) } sub.on('message', new WireRouter() - .on(wire.KeyPressMessage, (channel, message) => { + .on(KeyPressMessage, (channel, message) => { if (wdaClient.orientation === 'LANDSCAPE' && message.key === 'home') { wdaClient.rotation({orientation: 'PORTRAIT'}) .then(() => { @@ -70,16 +71,16 @@ export default syrup.serial() } } }) - .on(wire.StoreOpenMessage, (channel, message) => { + .on(StoreOpenMessage, (channel, message) => { wdaClient.pressButton('store') }) - .on(wire.DashboardOpenMessage, (channel, message) => { + .on(DashboardOpenMessage, (channel, message) => { wdaClient.pressButton('settings') }) - .on(wire.PhysicalIdentifyMessage, (channel, message) => { + .on(PhysicalIdentifyMessage, (channel, message) => { wdaClient.pressButton('finder') }) - .on(wire.TouchDownMessage, (channel, message) => { + .on(TouchDownMessage, (channel, message) => { if(cursorDevice?.state === 'paired') { cursorDevice.press() } @@ -87,17 +88,17 @@ export default syrup.serial() wdaClient.tap(message) } }) - .on(wire.TouchMoveIosMessage, (channel, message) => { + .on(TouchMoveIosMessage, (channel, message) => { if(cursorDevice?.state !== 'paired') { wdaClient.swipe(message) } }) - .on(wire.TouchMoveMessage, (channel, message) => { + .on(TouchMoveMessage, (channel, message) => { if(cursorDevice?.state === 'paired') { cursorDevice.move(message.x, message.y) } }) - .on(wire.TouchUpMessage, (channel, message) => { + .on(TouchUpMessage, (channel, message) => { if(cursorDevice?.state === 'paired') { cursorDevice.release() } @@ -105,14 +106,14 @@ export default syrup.serial() wdaClient.touchUp() } }) - .on(wire.TapDeviceTreeElement, (channel, message) => { + .on(TapDeviceTreeElement, (channel, message) => { wdaClient.tapDeviceTreeElement(message) }) - .on(wire.TypeMessage, (channel, message) => { + .on(TypeMessage, (channel, message) => { log.verbose('wire.TypeMessage: ', message) wdaClient.typeKey({value: [iosutil.asciiparser(message.text)]}) }) - .on(wire.KeyDownMessage, (channel, message) => { + .on(KeyDownMessage, (channel, message) => { log.verbose('wire.KeyDownMessage: ', message) if (message.key === 'home') { wdaClient.homeBtn() @@ -121,10 +122,10 @@ export default syrup.serial() wdaClient.typeKey({value: [iosutil.asciiparser(message.key)]}) } }) - .on(wire.BrowserOpenMessage, (channel, message) => { + .on(BrowserOpenMessage, (channel, message) => { wdaClient.openUrl(message) }) - .on(wire.RotateMessage, (channel, message) => { + .on(RotateMessage, (channel, message) => { if (wdaClient.isRotating) { return } @@ -140,7 +141,7 @@ export default syrup.serial() log.error('Failed to rotate device to : ', rotation, err) }) }) - .on(wire.ScreenCaptureMessage, (channel, message) => { + .on(ScreenCaptureMessage, (channel, message) => { wdaClient.screenshot() .then(response => { let reply = wireutil.reply(options.serial) diff --git a/lib/units/log/mongodb.js b/lib/units/log/mongodb.js index 8691670cda..33a5c78b09 100644 --- a/lib/units/log/mongodb.js +++ b/lib/units/log/mongodb.js @@ -7,6 +7,7 @@ import lifecycle from '../../util/lifecycle.js' import srv from '../../util/srv.js' import dbapi from '../../db/api.js' import * as zmqutil from '../../util/zmqutil.js' +import {DeviceLogMessage} from '../../wire/wire.js' export default (function(options) { var log = logger.createLogger('log-db') // Input @@ -25,7 +26,7 @@ export default (function(options) { sub.subscribe(channel) }) sub.on('message', new WireRouter() - .on(wire.DeviceLogMessage, function(channel, message) { + .on(DeviceLogMessage, function(channel, message) { if (message.priority >= options.priority) { dbapi.saveDeviceLog(message.serial, message) } diff --git a/lib/units/poorxy/index.js b/lib/units/poorxy/index.js index 6a6efc00d9..3b8320dd83 100644 --- a/lib/units/poorxy/index.js +++ b/lib/units/poorxy/index.js @@ -8,7 +8,7 @@ export default (function(options) { let server = http.createServer(app) let proxy = httpProxy.createProxyServer() proxy.on('error', function(err) { - log.error('Proxy had an error', err.stack) + log.error('Proxy had an error %s', err?.message) }) app.use(function(req, res, next) { res.setHeader('X-devicehub-unit', 'poorxy') diff --git a/lib/units/processor/index.js b/lib/units/processor/index.js deleted file mode 100644 index 8a9398f7ad..0000000000 --- a/lib/units/processor/index.js +++ /dev/null @@ -1,291 +0,0 @@ -import Promise from 'bluebird' -import logger from '../../util/logger.js' -import wire from '../../wire/index.js' -import {WireRouter} from '../../wire/router.js' -import wireutil from '../../wire/util.js' -import db from '../../db/index.js' -import dbapi from '../../db/models/all/index.js' -import lifecycle from '../../util/lifecycle.js' -import srv from '../../util/srv.js' -import * as zmqutil from '../../util/zmqutil.js' - -export default db.ensureConnectivity(async function(options) { - const log = logger.createLogger('processor') - if (options.name) { - logger.setGlobalIdentifier(options.name) - } - - const { - push - , pushdev - , sub - , subdev - , channelRouter - } = await db.createZMQSockets(options.endpoints, log) - await db.connect({push, pushdev, channelRouter}) - - // App side - const appDealer = zmqutil.socket('dealer') - Promise.all(options.endpoints.appDealer.map(async(endpoint) => { - try { - return srv.resolve(endpoint).then(function(records) { - return srv.attempt(records, async function(record) { - log.info('App dealer connected to "%s"', record.url) - appDealer.connect(record.url) - return true - }) - }) - } - catch (err) { - log.fatal('Unable to connect to app dealer endpoint', err) - lifecycle.fatal() - } - })) - - // Device side - const devDealer = zmqutil.socket('dealer') - appDealer.on('message', function(channel, data) { - devDealer.send([channel, data]) - }) - Promise.all(options.endpoints.devDealer.map(async(endpoint) => { - try { - return srv.resolve(endpoint).then(function(records) { - return srv.attempt(records, async function(record) { - log.info('Device dealer connected to "%s"', record.url) - devDealer.connect(record.url) - return true - }) - }) - } - catch (err) { - log.fatal('Unable to connect to dev dealer endpoint', err) - lifecycle.fatal() - } - })) - - const defaultWireHandler = (channel, _, data) => appDealer.send([channel, data]) - - const router = new WireRouter() - .on(wire.UpdateAccessTokenMessage, defaultWireHandler) - .on(wire.DeleteUserMessage, defaultWireHandler) - .on(wire.DeviceChangeMessage, defaultWireHandler) - .on(wire.UserChangeMessage, defaultWireHandler) - .on(wire.GroupChangeMessage, defaultWireHandler) - .on(wire.DeviceGroupChangeMessage, defaultWireHandler) - .on(wire.GroupUserChangeMessage, defaultWireHandler) - .on(wire.DeviceHeartbeatMessage, defaultWireHandler) - .on(wire.DeviceLogMessage, defaultWireHandler) - .on(wire.TransactionProgressMessage, defaultWireHandler) - .on(wire.TransactionDoneMessage, defaultWireHandler) - .on(wire.TransactionTreeMessage, defaultWireHandler) - .on(wire.InstallResultMessage, defaultWireHandler) - .on(wire.DeviceLogcatEntryMessage, defaultWireHandler) - .on(wire.TemporarilyUnavailableMessage, defaultWireHandler) - .on(wire.UpdateRemoteConnectUrl, defaultWireHandler) - .on(wire.InstalledApplications, defaultWireHandler) - .on(wire.DeviceIntroductionMessage, async(channel, message, data) => { - await dbapi.saveDeviceInitialState(message.serial, message) - devDealer.send([ - message.provider.channel, - wireutil.envelope(new wire.DeviceRegisteredMessage(message.serial)) - ]) - appDealer.send([channel, data]) - }) - .on(wire.InitializeIosDeviceState, (channel, message, data) => { - dbapi.initializeIosDeviceState(options.publicIp, message) - }) - .on(wire.DevicePresentMessage, async(channel, message, data) => { - await dbapi.setDevicePresent(message.serial) - appDealer.send([channel, data]) - }) - .on(wire.DeviceAbsentMessage, async(channel, message, data) => { - if (!message.applications) { - await dbapi.setDeviceAbsent(message.serial) - appDealer.send([channel, data]) - } - }) - .on(wire.DeviceStatusMessage, (channel, message, data) => { - dbapi.saveDeviceStatus(message.serial, message.status) - appDealer.send([channel, data]) - }) - .on(wire.DeviceReadyMessage, async(channel, message, data) => { - await dbapi.setDeviceReady(message.serial, message.channel) - devDealer.send([message.channel, wireutil.envelope(new wire.ProbeMessage())]) - appDealer.send([channel, data]) - }) - .on(wire.JoinGroupByAdbFingerprintMessage, async(channel, message, data) => { - try { - const user = await dbapi.lookupUserByAdbFingerprint(message.fingerprint) - if (user) { - devDealer.send([ - channel, - wireutil.envelope(new wire.AutoGroupMessage(new wire.OwnerMessage(user.email, user.name, user.group), message.fingerprint)) - ]) - return - } - appDealer.send([ - message.currentGroup, - wireutil.envelope(new wire.JoinGroupByAdbFingerprintMessage(message.serial, message.fingerprint, message.comment)) - ]) - } - catch (/** @type any */ err) { - log.error('Unable to lookup user by ADB fingerprint "%s"', message.fingerprint, err.stack) - } - }) - .on(wire.JoinGroupByVncAuthResponseMessage, async(channel, message, data) => { - try { - const user = await dbapi.lookupUserByVncAuthResponse(message.response, message.serial) - if (user) { - devDealer.send([ - channel, - wireutil.envelope(new wire.AutoGroupMessage(new wire.OwnerMessage(user.email, user.name, user.group), message.response)) - ]) - return - } - - appDealer.send([ - message.currentGroup, - wireutil.envelope(new wire.JoinGroupByVncAuthResponseMessage(message.serial, message.response)) - ]) - } - catch (/** @type any */ err) { - log.error('Unable to lookup user by VNC auth response "%s"', message.response, err.stack) - } - }) - .on(wire.ConnectStartedMessage, async(channel, message, data) => { - await dbapi.setDeviceConnectUrl(message.serial, message.url) - appDealer.send([channel, data]) - }) - .on(wire.ConnectStoppedMessage, async(channel, message, data) => { - await dbapi.unsetDeviceConnectUrl(message.serial) - appDealer.send([channel, data]) - }) - .on(wire.JoinGroupMessage, async(channel, message, data) => { - await Promise.all([ - dbapi.setDeviceOwner(message.serial, message.owner), - - message.usage && - dbapi.setDeviceUsage(message.serial, message.usage), - - dbapi.sendEvent(`device_${message.usage || 'use'}` - , {} - , {deviceSerial: message.serial, userEmail: message.owner.email, groupId: message.owner.group} - , Date.now() - ) - ]) - appDealer.send([channel, data]) - }) - .on(wire.LeaveGroupMessage, async(channel, message, data) => { - await Promise.all([ - dbapi.unsetDeviceOwner(message.serial), - dbapi.unsetDeviceUsage(message.serial), - dbapi.sendEvent('device_leave' - , {} - , {deviceSerial: message.serial, userEmail: message.owner.email, groupId: message.owner.group} - , Date.now() - ) - ]) - appDealer.send([channel, data]) - }) - .on(wire.DeviceIdentityMessage, (channel, message, data) => { - dbapi.saveDeviceIdentity(message.serial, message) - appDealer.send([channel, data]) - }) - .on(wire.AirplaneModeEvent, (channel, message, data) => { - dbapi.setDeviceAirplaneMode(message.serial, message.enabled) - appDealer.send([channel, data]) - }) - .on(wire.BatteryEvent, (channel, message, data) => { - dbapi.setDeviceBattery(message.serial, message) - appDealer.send([channel, data]) - }) - .on(wire.DeviceBrowserMessage, (channel, message, data) => { - dbapi.setDeviceBrowser(message.serial, message) - appDealer.send([channel, data]) - }) - .on(wire.ConnectivityEvent, (channel, message, data) => { - dbapi.setDeviceConnectivity(message.serial, message) - appDealer.send([channel, data]) - }) - .on(wire.PhoneStateEvent, (channel, message, data) => { - dbapi.setDevicePhoneState(message.serial, message) - appDealer.send([channel, data]) - }) - .on(wire.RotationEvent, (channel, message, data) => { - dbapi.setDeviceRotation(message) - appDealer.send([channel, data]) - }) - .on(wire.CapabilitiesMessage, (channel, message, data) => { - dbapi.setDeviceCapabilities(message) - appDealer.send([channel, data]) - }) - .on(wire.ReverseForwardsEvent, (channel, message, data) => { - dbapi.setDeviceReverseForwards(message.serial, message.forwards) - appDealer.send([channel, data]) - }) - .on(wire.SetDeviceDisplay, (channel, message, data) => { - dbapi - .setDeviceSocketDisplay(message) - .then(function(response) { - log.info('setDeviceSocketDisplay response: %s', response) - }) - .catch(function(err) { - log.error('setDeviceSocketDisplay', err) - }) - }) - .on(wire.UpdateIosDevice, (channel, message, data) => { - dbapi - .updateIosDevice(message) - .then(result => { - log.info('UpdateIosDevice: %s', result) - }) - .catch(err => { - log.info('UpdateIosDevice error: %s', err?.message) - }) - }) - .on(wire.SdkIosVersion, (channel, message, data) => { - dbapi - .setDeviceIosVersion(message) - .then(result => { - log.info('SdkIosVersion: %s', result) - }) - .catch(err => { - log.info('SdkIosVersion error: %s', err?.message) - }) - }) - .on(wire.SizeIosDevice, (channel, message, data) => { - dbapi.sizeIosDevice(message.id, message.height, message.width, message.scale).then(result => { - log.info('SizeIosDevice: %s', result) - }).catch(err => { - log.info('SizeIosDevice: %s', err?.message) - }) - appDealer.send([channel, data]) - }) - .on(wire.DeviceTypeMessage, (channel, message, data) => { - dbapi.setDeviceType(message.serial, message.type) - }) - .on(wire.DeleteDevice, (channel, message, data) => { - dbapi.deleteDevice(message.serial) - }) - .on(wire.SetAbsentDisconnectedDevices, (channel, message, data) => { - dbapi.setAbsentDisconnectedDevices() - }) - .on(wire.GetServicesAvailabilityMessage, (channel, message, data) => { - dbapi.setDeviceServicesAvailability(message.serial, message) - appDealer.send([channel, data]) - }) - .handler() - - devDealer.on('message', router) - - lifecycle.observe(function() { - [appDealer, devDealer, push, pushdev, sub, subdev].forEach(function(sock) { - try { - sock.close() - } - catch (err) { - log.error('Error while closing socket "%s"', err.stack) - } - }) - }) -}) diff --git a/lib/units/processor/index.ts b/lib/units/processor/index.ts new file mode 100644 index 0000000000..0e4578293b --- /dev/null +++ b/lib/units/processor/index.ts @@ -0,0 +1,328 @@ +import Promise from 'bluebird' +import logger from '../../util/logger.js' +import wire from '../../wire/index.js' +import {WireRouter} from '../../wire/router.js' +import wireutil from '../../wire/util.js' +import db from '../../db/index.js' +import dbapi from '../../db/models/all/index.js' +import lifecycle from '../../util/lifecycle.js' +import srv from '../../util/srv.js' +import * as zmqutil from '../../util/zmqutil.js' +import UserModel from '../../db/models/user/index.js' +import DeviceModel from '../../db/models/device/index.js' +import { + UserChangeMessage, + GroupChangeMessage, + DeviceGroupChangeMessage, + GroupUserChangeMessage, + DeviceHeartbeatMessage, + DeviceLogMessage, + TransactionProgressMessage, + TransactionDoneMessage, + TransactionTreeMessage, + InstallResultMessage, + DeviceLogcatEntryMessage, + TemporarilyUnavailableMessage, + UpdateRemoteConnectUrl, + InstalledApplications, + DeviceIntroductionMessage, + InitializeIosDeviceState, + DevicePresentMessage, + DeviceAbsentMessage, + DeviceStatusMessage, + DeviceReadyMessage, + JoinGroupByAdbFingerprintMessage, + JoinGroupByVncAuthResponseMessage, + ConnectStartedMessage, + ConnectStoppedMessage, + JoinGroupMessage, + LeaveGroupMessage, + DeviceIdentityMessage, + AirplaneModeEvent, + BatteryEvent, + DeviceBrowserMessage, + ConnectivityEvent, + PhoneStateEvent, + RotationEvent, + CapabilitiesMessage, + ReverseForwardsEvent, + SetDeviceDisplay, + UpdateIosDevice, + SdkIosVersion, + SizeIosDevice, + DeviceTypeMessage, + DeleteDevice, + SetAbsentDisconnectedDevices, + GetServicesAvailabilityMessage, + DeviceRegisteredMessage, GetPresentDevices, DeviceGetIsInOrigin, GetDeadDevices +} from '../../wire/wire.js' +import {getDeadDevice} from "../../db/models/device/model.js"; + +interface Options { + name: string + endpoints: { + appDealer: string[] + devDealer: string[] + } + publicIp: string +} + +export default db.ensureConnectivity(async(options: Options) => { + const log = logger.createLogger('processor') + if (options.name) { + logger.setGlobalIdentifier(options.name) + } + + await db.connect() + + // App side + const appDealer = zmqutil.socket('dealer') + await Promise.all(options.endpoints.appDealer.map(async(endpoint: string) => { + try { + return await srv.resolve(endpoint).then((records) => + srv.attempt(records, (record) => { + log.info('App dealer connected to "%s"', record.url) + appDealer.connect(record.url) + return true + }) + ) + } + catch (err: any) { + log.fatal('Unable to connect to app dealer endpoint %s', err?.message) + lifecycle.fatal() + } + })) + + // Device side + const devDealer = zmqutil.socket('dealer') + appDealer.on('message', (channel, data) => { + devDealer.send([channel, data]) + }) + + const reply = wireutil.reply(wireutil.global) + await Promise.all(options.endpoints.devDealer.map(async(endpoint: string) => { + try { + return await srv.resolve(endpoint).then((records) => + srv.attempt(records, (record) => { + log.info('Device dealer connected to "%s"', record.url) + devDealer.connect(record.url) + return true + }) + ) + } + catch (err: any) { + log.fatal('Unable to connect to dev dealer endpoint %s', err?.message) + lifecycle.fatal() + } + })) + + const defaultWireHandler = + (channel: string, _: any, data: any) => + appDealer.send([channel, data]) + + const router = new WireRouter() + .on(UserChangeMessage, defaultWireHandler) + .on(GroupChangeMessage, defaultWireHandler) + .on(DeviceGroupChangeMessage, defaultWireHandler) + .on(GroupUserChangeMessage, defaultWireHandler) + .on(DeviceLogMessage, defaultWireHandler) + .on(TransactionProgressMessage, defaultWireHandler) + .on(TransactionDoneMessage, defaultWireHandler) + .on(TransactionTreeMessage, defaultWireHandler) + .on(InstallResultMessage, defaultWireHandler) + .on(DeviceLogcatEntryMessage, defaultWireHandler) + .on(TemporarilyUnavailableMessage, defaultWireHandler) + .on(UpdateRemoteConnectUrl, defaultWireHandler) + .on(InstalledApplications, defaultWireHandler) + .on(DeviceIntroductionMessage, async (channel, message, data) => { + await dbapi.saveDeviceInitialState(message.serial, message) + devDealer.send([ + message.provider!.channel, + wireutil.pack(DeviceRegisteredMessage, {serial: message.serial}) + ]) + appDealer.send([channel, data]) + }) + .on(InitializeIosDeviceState, (channel, message, data) => { + dbapi.initializeIosDeviceState(options.publicIp, message) + }) + .on(DevicePresentMessage, async (channel, message, data) => { + await dbapi.setDevicePresent(message.serial) + appDealer.send([channel, data]) + }) + .on(DeviceAbsentMessage, async (channel, message, data) => { + await dbapi.setDeviceAbsent(message.serial) + appDealer.send([channel, data]) + }) + .on(DeviceStatusMessage, (channel, message, data) => { + dbapi.saveDeviceStatus(message.serial, message.status) + appDealer.send([channel, data]) + }) + .on(DeviceReadyMessage, async (channel, message, data) => { + await dbapi.setDeviceReady(message.serial, message.channel) + devDealer.send([message.channel, wireutil.envelope(new wire.ProbeMessage())]) + appDealer.send([channel, data]) + }) + .on(JoinGroupByAdbFingerprintMessage, async (channel, message) => { + try { + const user = await UserModel.lookupUserByAdbFingerprint(message.fingerprint) + if (user) { + devDealer.send([ + channel, + wireutil.envelope(new wire.AutoGroupMessage(new wire.OwnerMessage(user.email, user.name, user.group), message.fingerprint)) + ]) + return + } + appDealer.send([ + message.currentGroup, + wireutil.envelope(new wire.JoinGroupByAdbFingerprintMessage(message.serial, message.fingerprint, message.comment)) + ]) + } catch (err: any) { + log.error('Unable to lookup user by ADB fingerprint "%s": %s', message.fingerprint, err?.message) + } + }) + .on(JoinGroupByVncAuthResponseMessage, async (channel, message) => { + try { + const user = await dbapi.lookupUserByVncAuthResponse(message.response, message.serial) + if (user) { + devDealer.send([ + channel, + wireutil.envelope(new wire.AutoGroupMessage(new wire.OwnerMessage(user.email, user.name, user.group), message.response)) + ]) + return + } + + appDealer.send([ + message.currentGroup, + wireutil.envelope(new wire.JoinGroupByVncAuthResponseMessage(message.serial, message.response)) + ]) + } catch (err: any) { + log.error('Unable to lookup user by VNC auth response "%s": %s', message.response, err?.message) + } + }) + .on(ConnectStartedMessage, async (channel, message, data) => { + await dbapi.setDeviceConnectUrl(message.serial, message.url) + appDealer.send([channel, data]) + }) + .on(ConnectStoppedMessage, async (channel, message, data) => { + await dbapi.unsetDeviceConnectUrl(message.serial) + appDealer.send([channel, data]) + }) + .on(JoinGroupMessage, async (channel, message, data) => { + await Promise.all([ // @ts-ignore + dbapi.setDeviceState(message.serial, message), + dbapi.sendEvent(`device_${message.usage || 'use'}` + , {} + , {deviceSerial: message.serial, userEmail: message.owner!.email, groupId: message.owner!.group} + , Date.now() + ) + ]) + appDealer.send([channel, data]) + }) + .on(LeaveGroupMessage, async (channel, message, data) => { + await Promise.all([ + dbapi.setDeviceState(message.serial, {owner: null, usage: null, timeout: 0}), + dbapi.sendEvent('device_leave' + , {} + , {deviceSerial: message.serial, userEmail: message.owner!.email, groupId: message.owner!.group} + , Date.now() + ) + ]) + appDealer.send([channel, data]) + }) + .on(DeviceGetIsInOrigin, async (channel, message) => { + const device = await DeviceModel.loadDeviceBySerial(message.serial) + const isInOrigin = device ? device.group.id === device.group.origin : false + devDealer.send([ + channel, + reply.okay('success', {isInOrigin}) + ]) + }) + .on(DeviceIdentityMessage, (channel, message, data) => { + dbapi.saveDeviceIdentity(message.serial, message) + appDealer.send([channel, data]) + }) + .on(AirplaneModeEvent, (channel, message, data) => { + dbapi.setDeviceAirplaneMode(message.serial, message.enabled) + appDealer.send([channel, data]) + }) + .on(BatteryEvent, (channel, message, data) => { + dbapi.setDeviceBattery(message.serial, message) + appDealer.send([channel, data]) + }) + .on(DeviceBrowserMessage, (channel, message, data) => { + dbapi.setDeviceBrowser(message.serial, message) + appDealer.send([channel, data]) + }) + .on(ConnectivityEvent, (channel, message, data) => { + dbapi.setDeviceConnectivity(message.serial, message) + appDealer.send([channel, data]) + }) + .on(PhoneStateEvent, (channel, message, data) => { + dbapi.setDevicePhoneState(message.serial, message) + appDealer.send([channel, data]) + }) + .on(RotationEvent, (channel, message, data) => { + dbapi.setDeviceRotation(message) + appDealer.send([channel, data]) + }) + .on(CapabilitiesMessage, (channel, message, data) => { + dbapi.setDeviceCapabilities(message) + appDealer.send([channel, data]) + }) + .on(ReverseForwardsEvent, (channel, message, data) => { + dbapi.setDeviceReverseForwards(message.serial, message.forwards) + appDealer.send([channel, data]) + }) + .on(UpdateIosDevice, (channel, message, data) => + dbapi.updateIosDevice(message) + ) + .on(SdkIosVersion, (channel, message, data) => { + dbapi.setDeviceIosVersion(message) + }) + .on(SizeIosDevice, (channel, message, data) => { + dbapi.sizeIosDevice(message.id, message.height, message.width, message.scale) + appDealer.send([channel, data]) + }) + .on(DeviceTypeMessage, (channel, message, data) => { + dbapi.setDeviceType(message.serial, message.type) + }) + .on(GetServicesAvailabilityMessage, (channel, message, data) => { + dbapi.setDeviceServicesAvailability(message.serial, message) + appDealer.send([channel, data]) + }) + .on(GetPresentDevices, async (channel, message, data) => { + const devices = await DeviceModel.loadPresentDevices() + .then(devices => devices.map(d => d.serial)) + devDealer.send([ + channel, + reply.okay('success', {devices}) + ]) + }) + .on(DeviceHeartbeatMessage, (channel, message, data) => { + devDealer.send([ channel, data ]) + }) + .on(GetDeadDevices, async(channel, message, data) => { + const deadDevices = await DeviceModel.getDeadDevice(message.time) + devDealer.send([ + channel, + reply.okay('success', {deadDevices}) + ]) + }) + .on(DeleteDevice, async(channel, message, data) => { + DeviceModel.deleteDevice(message.serial) + }) + .handler(); + + devDealer.on('message', router) + + lifecycle.observe(() => { + ;[appDealer, devDealer].forEach(function(sock) { + try { + sock.close() + } + catch (err: any) { + log.error('Error while closing socket "%s"', err?.message) + } + }) + }) +}) diff --git a/lib/units/provider/index.ts b/lib/units/provider/index.ts index deca4f5005..86f55abb54 100644 --- a/lib/units/provider/index.ts +++ b/lib/units/provider/index.ts @@ -6,10 +6,9 @@ import * as procutil from '../../util/procutil.js' import lifecycle from '../../util/lifecycle.js' import srv from '../../util/srv.js' import * as zmqutil from '../../util/zmqutil.js' -import db from '../../db/index.js' -import dbapi from '../../db/api.js' import {ChildProcess} from 'node:child_process' import ADBObserver, {ADBDevice} from './ADBObserver.js' +import { DeviceRegisteredMessage } from '../../wire/wire.ts' interface DeviceWorker { state: 'waiting' | 'running' @@ -38,7 +37,6 @@ export interface Options { export default (async function(options: Options) { const log = logger.createLogger('provider') - await db.connect() // Check whether the ipv4 address contains a port indication if (options.adbHost.includes(':')) { @@ -66,7 +64,7 @@ export default (async function(options: Options) { })) } catch (err) { - log.fatal('Unable to connect to push endpoint', err) + log.fatal('Unable to connect to push endpoint: %s', err) lifecycle.fatal() } @@ -87,7 +85,7 @@ export default (async function(options: Options) { }) sub.on('message', new WireRouter() - .on(wire.DeviceRegisteredMessage, (channel, message) => { + .on(DeviceRegisteredMessage, (channel, message: {serial: string}) => { if (workers[message.serial]?.resolveRegister) { workers[message.serial].resolveRegister!() delete workers[message.serial]?.resolveRegister @@ -97,7 +95,7 @@ export default (async function(options: Options) { ) } catch (err) { - log.fatal('Unable to connect to sub endpoint', err) + log.fatal('Unable to connect to sub endpoint: %s', err) lifecycle.fatal() } @@ -132,10 +130,9 @@ export default (async function(options: Options) { // Tell others we found a device push.send([ wireutil.global, - wireutil.envelope(new wire.DeviceIntroductionMessage(device.serial, wireutil.toDeviceStatus(device.type) || 1, new wire.ProviderMessage(solo, options.name))) + wireutil.envelope(new wire.DeviceIntroductionMessage(device.serial, wireutil.toDeviceStatus(device.type) || 1, new wire.ProviderMessage(solo, options.name), options.deviceType)) ]) - dbapi.setDeviceType(device.serial, options.deviceType) process.nextTick(() => { // after creating workers[device.serial] obj if (workers[device.serial]) { workers[device.serial].resolveRegister = () => resolve() @@ -160,8 +157,7 @@ export default (async function(options: Options) { proc.removeAllListeners('message') if (signal) { - log.warn('Device worker "%s" was killed with signal %s, assuming ' + - 'deliberate action and not restarting', device.serial, signal) + log.warn('Device worker "%s" was killed with signal %s, assuming deliberate action and not restarting', device.serial, signal) if (workers[device.serial].state === 'running') { workers[device.serial].terminate() diff --git a/lib/units/reaper/index.js b/lib/units/reaper/index.js deleted file mode 100644 index 20529d9711..0000000000 --- a/lib/units/reaper/index.js +++ /dev/null @@ -1,108 +0,0 @@ -import Promise from 'bluebird' -import logger from '../../util/logger.js' -import wire from '../../wire/index.js' -import wireutil from '../../wire/util.js' -import {WireRouter} from '../../wire/router.js' -import dbapi from '../../db/api.js' -import lifecycle from '../../util/lifecycle.js' -import srv from '../../util/srv.js' -import TtlSet from '../../util/ttlset.js' -import * as zmqutil from '../../util/zmqutil.js' -import db from '../../db/index.js' - -const log = logger.createLogger('reaper') -export default (async function(options) { - await db.connect() - - /** @type {any} */ - const ttlset = new TtlSet(options.heartbeatTimeout) - - // Input - const sub = zmqutil.socket('sub') - Promise.map(options.endpoints.sub, function(endpoint) { - return srv.resolve(endpoint).then(function(records) { - return srv.attempt(records, function(record) { - log.info('Receiving input from "%s"', record.url) - sub.connect(record.url) - return Promise.resolve(true) - }) - }) - }) - .catch(function(err) { - log.fatal('Unable to connect to sub endpoint', err) - lifecycle.fatal() - }); - [wireutil.global].forEach(function(channel) { - log.info('Subscribing to permanent channel "%s"', channel) - sub.subscribe(channel) - }) - // Output - const push = zmqutil.socket('push') - Promise.map(options.endpoints.push, function(endpoint) { - return srv.resolve(endpoint).then(function(records) { - return srv.attempt(records, function(record) { - log.info('Sending output to "%s"', record.url) - push.connect(record.url) - return Promise.resolve(true) - }) - }) - }) - .catch(function(err) { - log.fatal('Unable to connect to push endpoint', err) - lifecycle.fatal() - }) - ttlset.on('insert', function(serial) { - log.info('Device "%s" is present', serial) - push.send([ - wireutil.global, - wireutil.envelope(new wire.DevicePresentMessage(serial)) - ]) - }) - ttlset.on('drop', function(serial) { - log.info('Reaping device "%s" due to heartbeat timeout', serial) - push.send([ - wireutil.global, - wireutil.envelope(new wire.DeviceAbsentMessage(serial)) - ]) - }) - function loadInitialState() { - return dbapi.loadPresentDevices() - .then(function(devices) { - let now = Date.now() - devices.forEach(function(device) { - ttlset.bump(device.serial, now, TtlSet.SILENT) - }) - }) - } - function listenToChanges() { - sub.on('message', new WireRouter() - .on(wire.DeviceIntroductionMessage, function(channel, message) { - message.status = 3 - ttlset.drop(message.serial, TtlSet.SILENT) - ttlset.bump(message.serial, Date.now()) - }) - .on(wire.DeviceHeartbeatMessage, function(channel, message) { - ttlset.bump(message.serial, Date.now()) - }) - .on(wire.DeviceAbsentMessage, function(channel, message) { - ttlset.drop(message.serial, TtlSet.SILENT) - }) - .handler()) - } - log.info('Reaping devices with no heartbeat') - lifecycle.observe(function() { - [push, sub].forEach(function(sock) { - try { - sock.close() - } - catch (err) { - log.error(err) - } - }) - ttlset.stop() - }) - loadInitialState().then(listenToChanges).catch(function(err) { - log.fatal('Unable to load initial state', err) - lifecycle.fatal() - }) -}) diff --git a/lib/units/reaper/index.ts b/lib/units/reaper/index.ts new file mode 100644 index 0000000000..2fde098619 --- /dev/null +++ b/lib/units/reaper/index.ts @@ -0,0 +1,174 @@ +import logger from '../../util/logger.js' +import { + DeleteDevice, + DeviceAbsentMessage, + DeviceHeartbeatMessage, + DeviceIntroductionMessage, DevicePresentMessage, GetDeadDevices, + GetPresentDevices +} from '../../wire/wire.js' +import wireutil from '../../wire/util.js' +import {WireRouter} from '../../wire/router.js' +import lifecycle from '../../util/lifecycle.js' +import srv from '../../util/srv.js' +import TTLSet from '../../util/ttlset.js' +import * as zmqutil from '../../util/zmqutil.js' +import {runTransactionDev} from '../../wire/transmanager.js' + +const log = logger.createLogger('reaper') + +interface Options { + heartbeatTimeout: number + timeToDeviceCleanup: number // in minutes + deviceCleanupInterval: number // in minutes + endpoints: { + sub: string[] + push: string[] + } +} + +export default (async(options: Options) => { + const ttlset = new TTLSet(options.heartbeatTimeout) + + // Input + const sub = zmqutil.socket('sub') + await Promise.all(options.endpoints.sub.map((endpoint: string) => + srv.resolve(endpoint).then(records => + srv.attempt(records, (record) => { + log.info('Receiving input from "%s"', record.url) + sub.connect(record.url) + }) + ) + )).catch((err) => { + log.fatal('Unable to connect to sub endpoint %s', err?.message) + lifecycle.fatal() + }) + + ;[wireutil.global].forEach(channel => { + log.info('Subscribing to permanent channel "%s"', channel) + sub.subscribe(channel) + }) + + // Output + const push = zmqutil.socket('push') + await Promise.all(options.endpoints.push.map((endpoint: string) => + srv.resolve(endpoint).then(records => + srv.attempt(records, (record) => { + log.info('Sending output to "%s"', record.url) + push.connect(record.url) + }) + ) + )).catch((err) => { + log.fatal('Unable to connect to push endpoint: %s', err?.message) + lifecycle.fatal() + }) + + ttlset.on('insert', (serial) => { + log.info('Device "%s" is present', serial) + push.send([ + wireutil.global, + wireutil.pack(DevicePresentMessage, {serial}) + ]) + }) + + ttlset.on('drop', (serial) => { + log.info('Reaping device "%s" due to heartbeat timeout', serial) + push.send([ + wireutil.global, + wireutil.pack(DeviceAbsentMessage, {serial}) + ]) + }) + + lifecycle.observe(() => { + [push, sub].forEach(sock => { + try { + sock.close() + } + catch (err: any) { + // no-op + } + }) + ttlset.stop() + }) + + const router = new WireRouter() + .on(DeviceIntroductionMessage, (channel, message) => { + ttlset.drop(message.serial, TTLSet.SILENT) + ttlset.bump(message.serial, Date.now()) + }) + .on(DeviceHeartbeatMessage, (channel, message) => { + ttlset.bump(message.serial, Date.now()) + }) + .on(DeviceAbsentMessage, (channel, message) => { + ttlset.drop(message.serial, TTLSet.SILENT) + }) + + if (options.timeToDeviceCleanup) { + log.info('deviceCleanerLoop enabled') + + // This functionality is implemented in the Reaper unit because this unit cannot be replicated + const deviceCleanerLoop = () => setTimeout(async() => { + log.info('Checking dead devices [interval: %s]', options.deviceCleanupInterval) + try { + const absenceDuration = options.timeToDeviceCleanup + const {deadDevices} = await runTransactionDev(wireutil.global, GetDeadDevices, { + time: options.timeToDeviceCleanup * 60 * 1000 + }, {sub, push, router}) + + for (const {serial, present} of deadDevices) { + if (present) { + continue + } + + log.info( // @ts-ignore + 'Removing a dead device [serial: %s, absence_duration: %.1f %s]', + serial, + ... ( + absenceDuration >= 60 // if more 1 hour + ? [absenceDuration / 60, 'hrs'] + : [absenceDuration, 'min'] + ) + ) + + push.send([ + wireutil.global, + wireutil.pack(DeleteDevice, {serial}) + ]) + } + } catch (err: any) { + log.error('Dead device check failed with error: %s', err?.message) + } finally { + deviceCleanerLoop() + } + }, options.deviceCleanupInterval * 60 * 1000) + + deviceCleanerLoop() + } + + const init = async() => { + try { + log.info('Reaping devices with no heartbeat') + + // Listen to changes + sub.on('message', router.handler()) + + // Load initial state + const {devices} = await runTransactionDev(wireutil.global, GetPresentDevices, {}, {sub, push, router}) + + const now = Date.now() + devices?.forEach((serial: string) => { + ttlset.bump(serial, now, TTLSet.SILENT) + }) + } + catch (err: any) { + if (err?.message === 'Timeout when running transaction') { + log.error('Load initial state error: Timeout when running transaction, retry') + setTimeout(init, 2000) + return + } + log.fatal('Unable to load initial state: %s', err?.message) + lifecycle.fatal() + } + } + + init() +}) diff --git a/lib/units/tizen-device/index.js b/lib/units/tizen-device/index.js index 0f0c5b6666..b2368f042d 100644 --- a/lib/units/tizen-device/index.js +++ b/lib/units/tizen-device/index.js @@ -16,6 +16,7 @@ import router from '../base-device/support/router.js' import identity from './plugins/identity.js' import launcher from './plugins/launcher.js' import filesystem from './plugins/filesystem.js' +import {DeviceRegisteredMessage} from '../../wire/wire.js' const log = logger.createLogger('tizen-device') const isTcpPortOpen = (host, port, timeout = 2_000) => new Promise((resolve) => { @@ -59,7 +60,7 @@ export default (async(options) => syrup.serial() let listener const waitRegister = Promise.race([ new Promise(resolve => - router.on(wire.DeviceRegisteredMessage, listener = (...args) => resolve(args)) + router.on(DeviceRegisteredMessage, listener = (...args) => resolve(args)) ), new Promise(r => setTimeout(r, 15000)) ]) diff --git a/lib/units/tizen-device/plugins/filesystem.js b/lib/units/tizen-device/plugins/filesystem.js index 3e4c3e1dce..63564c20ef 100644 --- a/lib/units/tizen-device/plugins/filesystem.js +++ b/lib/units/tizen-device/plugins/filesystem.js @@ -9,6 +9,7 @@ import logger from '../../../util/logger.js' import storage from '../../base-device/support/storage.js' import {basename} from 'path' import {unlink} from 'fs' +import {FileSystemGetMessage, FileSystemListMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(push) @@ -41,7 +42,7 @@ export default syrup.serial() return storedFile } - router.on(wire.FileSystemGetMessage, async(channel, message) => { + router.on(FileSystemGetMessage, async(channel, message) => { try { const file = await uploadFromDevice(message.file, message.jwt) push.send([ @@ -77,7 +78,7 @@ export default syrup.serial() })) } - router.on(wire.FileSystemListMessage, async(channel, message) => { + router.on(FileSystemListMessage, async(channel, message) => { try { push.send([ channel, diff --git a/lib/units/tizen-device/plugins/identity.js b/lib/units/tizen-device/plugins/identity.js index 8a694da8fb..9696f3e19f 100644 --- a/lib/units/tizen-device/plugins/identity.js +++ b/lib/units/tizen-device/plugins/identity.js @@ -5,6 +5,7 @@ import wire from '../../../wire/index.js' import wireutil from '../../../wire/util.js' import push from '../../base-device/support/push.js' import {exec} from 'child_process' +import {ProbeMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(push) @@ -29,7 +30,7 @@ export default syrup.serial() }) }) - router.on(wire.ProbeMessage, () => { + router.on(ProbeMessage, () => { push.send([ wireutil.global, wireutil.envelope(new wire.DeviceIdentityMessage( diff --git a/lib/units/tizen-device/plugins/install.js b/lib/units/tizen-device/plugins/install.js index e0f8ef1978..ceb3a5de1c 100644 --- a/lib/units/tizen-device/plugins/install.js +++ b/lib/units/tizen-device/plugins/install.js @@ -7,6 +7,7 @@ import storage from '../../base-device/support/storage.js' import sdb from './sdb' import launcher from './launcher' import deviceutil from '../../../util/deviceutil.js' +import {InstallMessage, UninstallIosMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(router) @@ -18,7 +19,7 @@ export default syrup.serial() const log = logger.createLogger('tizen-device:plugins:install') const reply = wireutil.reply(options.serial) - router.on(wire.InstallMessage, async function(channel, message) { + router.on(InstallMessage, async function(channel, message) { log.info('Installing application from "%s"', message.href, message.launch ? '[ LAUNCH ]' : '') const sendProgress = (data, progress) => @@ -45,7 +46,7 @@ export default syrup.serial() sendProgress('installing_app', 100) }) - router.on(wire.UninstallIosMessage, function(channel, message) { + router.on(UninstallIosMessage, function(channel, message) { uninstallApp(options.serial, message.packageName) }) }) diff --git a/lib/units/tizen-device/plugins/launcher.js b/lib/units/tizen-device/plugins/launcher.js index 32c88827b4..42339ccf40 100644 --- a/lib/units/tizen-device/plugins/launcher.js +++ b/lib/units/tizen-device/plugins/launcher.js @@ -6,6 +6,7 @@ import sdb from './sdb/index.js' import wire from '../../../wire/index.js' import wireutil from '../../../wire/util.js' import webinspector from './webinspector/index.js' +import {GetInstalledApplications, KillDeviceApp, LaunchDeviceApp, TerminateDeviceApp} from '../../../wire/wire.js' export default syrup.serial() .dependency(push) @@ -57,16 +58,16 @@ export default syrup.serial() group.on('join', () => plugin.killApp(true)) router - .on(wire.GetInstalledApplications, async(channel) => + .on(GetInstalledApplications, async(channel) => success(channel, Object.fromEntries(await sdb.getApps())) ) - .on(wire.LaunchDeviceApp, plugin.launchApp) + .on(LaunchDeviceApp, plugin.launchApp) - .on(wire.TerminateDeviceApp, async(channel) => + .on(TerminateDeviceApp, async(channel) => success(channel, await plugin.killApp()) ) - .on(wire.KillDeviceApp, async(channel) => + .on(KillDeviceApp, async(channel) => success(channel, await plugin.killApp(true)) ) } diff --git a/lib/units/tizen-device/plugins/webinspector/Replicator.ts b/lib/units/tizen-device/plugins/webinspector/Replicator.ts index 4cb8800f01..4bd30fabd8 100644 --- a/lib/units/tizen-device/plugins/webinspector/Replicator.ts +++ b/lib/units/tizen-device/plugins/webinspector/Replicator.ts @@ -7,7 +7,6 @@ const KEY_REQUIRE_ESCAPING_RE = /^#*@(t|r)$/ const REMAINING_KEY = '__console_feed_remaining__' const GLOBAL = (function getGlobal() { // NOTE: see http://www.ecma-international.org/ecma-262/6.0/index.html#sec-performeval step 10 - // eslint-disable-next-line no-eval const savedEval = eval return savedEval('this') })() @@ -128,7 +127,6 @@ class EncodingTransformer { } const remaining = total - counter - // eslint-disable-next-line no-proto const name = obj?.__proto__?.constructor?.name if (name && name !== 'Object') { diff --git a/lib/units/tizen-device/plugins/webinspector/index.ts b/lib/units/tizen-device/plugins/webinspector/index.ts index f88f0035f6..29d029187b 100644 --- a/lib/units/tizen-device/plugins/webinspector/index.ts +++ b/lib/units/tizen-device/plugins/webinspector/index.ts @@ -2,7 +2,6 @@ import push from '../../../base-device/support/push.js' import router from '../../../base-device/support/router.js' import group from '../../../base-device/plugins/group.js' import cdp, {CDPClient} from '../cdp/index.js' -import wire from '../../../../wire/index.js' import wireutil from '../../../../wire/util.js' import logger from '../../../../util/logger.js' @@ -12,6 +11,7 @@ import _ from 'lodash' import urlformat from '../../../base-device/support/urlformat.js' import MyReplicator from './Replicator.js' import * as transform from './transform/index.js' +import {GetAppAsset, GetAppAssetsList, GetAppHTML, GetAppInspectServerUrl} from "../../../../wire/wire.js"; const consoleListeners = new Map() const replicator = new MyReplicator() @@ -113,32 +113,35 @@ export default syrup.serial() } const wsUrl = urlformat(options.updWsUrlPattern, options.publicPort) + let inspServer: webSocketServer.Server | null = null - const handlers = { - + router // TODO: Create download endpoint - [wire.GetAppAsset .$code]: (channel: string, message: any) => getAsset(message.url).then(asset => - success(channel, asset) - ).catch(err => - fail(channel, err) - ), - - [wire.GetAppAssetsList .$code]: (channel: string) => getAssetsList().then(list => - success(channel, list) - ).catch(err => - fail(channel, err) - ), - - [wire.GetAppHTML .$code]: (channel: string) => cdp.getHTML().then(content => - success(channel, {content, base64Encoded: false}) - ).catch(err => - fail(channel, err) - ), - - [wire.GetAppInspectServerUrl .$code]: (channel: string) => - success(channel, wsUrl) - } - let inspServer: webSocketServer.Server | null = null + .on(GetAppAsset, (channel: string, message: any) => !!inspServer && + getAsset(message.url).then(asset => + success(channel, asset) + ).catch(err => + fail(channel, err) + )) + + .on(GetAppAssetsList, (channel: string) => !!inspServer && + getAssetsList().then(list => + success(channel, list) + ).catch(err => + fail(channel, err) + )) + + .on(GetAppHTML, (channel: string) => !!inspServer && + cdp.getHTML().then(content => + success(channel, {content, base64Encoded: false}) + ).catch(err => + fail(channel, err) + )) + + .on(GetAppInspectServerUrl, (channel: string) => + !!inspServer && success(channel, wsUrl) + ) + const plugin = { host: '', port: 0, @@ -151,15 +154,9 @@ export default syrup.serial() if (!inspServer) { inspServer = inspectServer(options.publicPort, cdp, log) } - - Object.entries(handlers) - .map(([event, handler]) => router.on(event, handler)) }, stop: async() => { - Object.entries(handlers) - .map(([event, handler]) => router.removeListener(event, handler)) - frameId = null await new Promise(r => { inspServer?.close(() => r) diff --git a/lib/units/vnc-device/plugins/group.js b/lib/units/vnc-device/plugins/group.js index 50fa723816..11dc7d4d52 100755 --- a/lib/units/vnc-device/plugins/group.js +++ b/lib/units/vnc-device/plugins/group.js @@ -14,6 +14,7 @@ import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import sub from '../../base-device/support/sub.js' import channels from '../../base-device/support/channels.js' +import {GroupMessage, AutoGroupMessage, UngroupMessage} from '../../../wire/wire.js' export default syrup.serial() .dependency(solo) @@ -116,7 +117,7 @@ export default syrup.serial() } router - .on(wire.GroupMessage, (channel, message) => { + .on(GroupMessage, (channel, message) => { let reply = wireutil.reply(options.serial) Promise.method(() => { return plugin.join(message.owner, message.timeout, message.usage) @@ -140,7 +141,7 @@ export default syrup.serial() ]) }) }) - .on(wire.AutoGroupMessage, (channel, message) => { + .on(AutoGroupMessage, (channel, message) => { return plugin.join(message.owner, message.timeout, message.identifier) .then(() => { plugin.emit('autojoin', message.identifier, true) @@ -149,7 +150,7 @@ export default syrup.serial() plugin.emit('autojoin', message.identifier, false) }) }) - .on(wire.UngroupMessage, (channel, message) => { + .on(UngroupMessage, (channel, message) => { let reply = wireutil.reply(options.serial) Promise.method(() => { return plugin.leave('ungroup_request') diff --git a/lib/units/vnc-device/plugins/screen/stream.js b/lib/units/vnc-device/plugins/screen/stream.js index 6bc74f1c44..9dc4d22608 100755 --- a/lib/units/vnc-device/plugins/screen/stream.js +++ b/lib/units/vnc-device/plugins/screen/stream.js @@ -15,6 +15,7 @@ import router from '../../../base-device/support/router.js' import group from '../group.js' import {decode} from '../../../../util/jwtutil.js' import {NoGroupError} from '../../../../util/grouputil.js' +import {GestureStartMessage, GestureStopMessage, TouchDownMessage, TouchMoveMessage, TouchUpMessage, TouchCommitMessage, TouchResetMessage, TypeMessage, KeyDownMessage, KeyUpMessage} from '../../../../wire/wire.js' export default syrup.serial() .dependency(solo) @@ -127,34 +128,34 @@ export default syrup.serial() }) router - .on(wire.GestureStartMessage, function(channel, message) { + .on(GestureStartMessage, function(channel, message) { }) - .on(wire.GestureStopMessage, function(channel, message) { + .on(GestureStopMessage, function(channel, message) { }) - .on(wire.TouchDownMessage, function(channel, message) { + .on(TouchDownMessage, function(channel, message) { lastClicked.x = message.x * height lastClicked.y = message.y * width r.pointerEvent(message.x * height, message.y * width, 1) }) - .on(wire.TouchMoveMessage, function(channel, message) { + .on(TouchMoveMessage, function(channel, message) { }) - .on(wire.TouchUpMessage, function(channel, message) { + .on(TouchUpMessage, function(channel, message) { }) - .on(wire.TouchCommitMessage, function(channel, message) { + .on(TouchCommitMessage, function(channel, message) { }) - .on(wire.TouchResetMessage, function(channel, message) { + .on(TouchResetMessage, function(channel, message) { }) - .on(wire.TypeMessage, function(channel, message) { + .on(TypeMessage, function(channel, message) { let keyCode = message.text.charCodeAt(0) r.keyEvent(keyCode, 1) r.keyEvent(keyCode, 0) r.requestUpdate(false, 0, 0, r.width, r.height) }) - .on(wire.KeyDownMessage, function(channel, message) { + .on(KeyDownMessage, function(channel, message) { r.keyEvent(keyNameToX11KeyCode(message.key), 1) r.requestUpdate(false, 0, 0, r.width, r.height) }) - .on(wire.KeyUpMessage, function(channel, message) { + .on(KeyUpMessage, function(channel, message) { r.keyEvent(keyNameToX11KeyCode(message.key), 0) r.requestUpdate(false, 0, 0, r.width, r.height) }) diff --git a/lib/units/websocket/index.js b/lib/units/websocket/index.js index bb0153eedf..6f59f52e4c 100644 --- a/lib/units/websocket/index.js +++ b/lib/units/websocket/index.js @@ -13,7 +13,6 @@ import logger from '../../util/logger.js' import wire from '../../wire/index.js' import wireutil from '../../wire/util.js' import {WireRouter} from '../../wire/router.js' -import dbapi from '../../db/api.js' import datautil from '../../util/datautil.js' import lifecycle from '../../util/lifecycle.js' import cookieSession from './middleware/cookie-session.js' @@ -25,6 +24,9 @@ import {Server} from 'socket.io' import db from '../../db/index.js' import EventEmitter from 'events' import generateToken from '../api/helpers/generateToken.js' +import {UpdateAccessTokenMessage, DeleteUserMessage, DeviceChangeMessage, UserChangeMessage, GroupChangeMessage, DeviceGroupChangeMessage, GroupUserChangeMessage, DeviceLogMessage, DeviceIntroductionMessage, DeviceReadyMessage, DevicePresentMessage, DeviceAbsentMessage, InstalledApplications, JoinGroupMessage, JoinGroupByAdbFingerprintMessage, LeaveGroupMessage, DeviceStatusMessage, DeviceIdentityMessage, TransactionProgressMessage, TransactionDoneMessage, TransactionTreeMessage, DeviceLogcatEntryMessage, AirplaneModeEvent, BatteryEvent, GetServicesAvailabilityMessage, DeviceBrowserMessage, ConnectivityEvent, PhoneStateEvent, RotationEvent, CapabilitiesMessage, ReverseForwardsEvent, TemporarilyUnavailableMessage, UpdateRemoteConnectUrl} from '../../wire/wire.js' +import AllModel from '../../db/models/all/index.js' +import UserModel from '../../db/models/user/index.js' const request = Promise.promisifyAll(postmanRequest) export default (async function(options) { const log = logger.createLogger('websocket') @@ -44,7 +46,7 @@ export default (async function(options) { , push , pushdev } = await db.createZMQSockets({...options.endpoints}, log) - await db.connect(push, pushdev, channelRouter) + await db.connect({push, pushdev, channelRouter}) ;[wireutil.global].forEach(function(channel) { log.info('Subscribing to permanent webosocket channel "%s"', channel) @@ -103,13 +105,13 @@ export default (async function(options) { } let disconnectSocket var messageListener = new WireRouter() - .on(wire.UpdateAccessTokenMessage, function() { + .on(UpdateAccessTokenMessage, function() { socket.emit('user.keys.accessToken.updated') }) - .on(wire.DeleteUserMessage, function() { + .on(DeleteUserMessage, function() { disconnectSocket(true) }) - .on(wire.DeviceChangeMessage, function(channel, message) { + .on(DeviceChangeMessage, function(channel, message) { if (user.groups.subscribed.indexOf(message.device.group.id) > -1) { socket.emit('device.change', { important: true, @@ -124,12 +126,12 @@ export default (async function(options) { socket.emit('user.settings.devices.' + message.action, message) } }) - .on(wire.UserChangeMessage, function(channel, message) { + .on(UserChangeMessage, function(channel, message) { Promise.map(message.targets, function(target) { socket.emit('user.' + target + '.users.' + message.action, message) }) }) - .on(wire.GroupChangeMessage, function(channel, message) { + .on(GroupChangeMessage, function(channel, message) { if (user.privilege === 'admin' || user.email === message.group.owner.email || !apiutil.isOriginGroup(message.group.class) && @@ -140,7 +142,7 @@ export default (async function(options) { socket.emit('user.view.groups.' + message.action, message) } }) - .on(wire.DeviceGroupChangeMessage, function(channel, message) { + .on(DeviceGroupChangeMessage, function(channel, message) { if (user.groups.subscribed.indexOf(message.id) > -1) { if (user.groups.subscribed.indexOf(message.group.id) > -1) { socket.emit('device.updateGroupDevice', { @@ -159,7 +161,7 @@ export default (async function(options) { socket.emit('device.addGroupDevices', {important: true, devices: [message.serial]}) } }) - .on(wire.GroupUserChangeMessage, function(channel, message) { + .on(GroupUserChangeMessage, function(channel, message) { if (message.users.indexOf(user.email) > -1) { if (message.isAdded) { user.groups.subscribed = _.union(user.groups.subscribed, [message.id]) @@ -182,10 +184,10 @@ export default (async function(options) { } } }) - .on(wire.DeviceLogMessage, function(channel, message) { + .on(DeviceLogMessage, function(channel, message) { io.emit('logcat.log', message) }) - .on(wire.DeviceIntroductionMessage, function(channel, message) { + .on(DeviceIntroductionMessage, function(channel, message) { if (message && message.group && user.groups.subscribed.indexOf(message.group.id) > -1) { io.emit('device.add', { important: true, @@ -202,7 +204,7 @@ export default (async function(options) { }) } }) - .on(wire.DeviceReadyMessage, function(channel, message) { + .on(DeviceReadyMessage, function(channel, message) { io.emit('device.change', { important: true, data: { @@ -214,7 +216,7 @@ export default (async function(options) { } }) }) - .on(wire.DevicePresentMessage, function(channel, message) { + .on(DevicePresentMessage, function(channel, message) { io.emit('device.change', { important: true, data: { @@ -223,7 +225,7 @@ export default (async function(options) { } }) }) - .on(wire.DeviceAbsentMessage, function(channel, message) { + .on(DeviceAbsentMessage, function(channel, message) { io.emit('device.remove', { important: true, data: { @@ -233,7 +235,7 @@ export default (async function(options) { } }) }) - .on(wire.InstalledApplications, function(channel, message, data) { + .on(InstalledApplications, function(channel, message, data) { socket.emit('device.applications', { important: true, data: { @@ -243,8 +245,8 @@ export default (async function(options) { }) }) // @TODO refactore JoimGroupMessage route - .on(wire.JoinGroupMessage, function(channel, message) { - dbapi.getInstalledApplications({serial: message.serial}) + .on(JoinGroupMessage, function(channel, message) { + AllModel.getInstalledApplications({serial: message.serial}) .then(applications => { if (!user?.ownedChannels) { user.ownedChannels = new Set() @@ -283,13 +285,13 @@ export default (async function(options) { }) }) }) - .on(wire.JoinGroupByAdbFingerprintMessage, function(channel, message) { + .on(JoinGroupByAdbFingerprintMessage, function(channel, message) { socket.emit('user.keys.adb.confirm', { title: message.comment, fingerprint: message.fingerprint }) }) - .on(wire.LeaveGroupMessage, function(channel, message) { + .on(LeaveGroupMessage, function(channel, message) { io.emit('device.change', { important: true, data: datautil.applyOwner({ @@ -299,33 +301,33 @@ export default (async function(options) { }, user) }) }) - .on(wire.DeviceStatusMessage, function(channel, message) { + .on(DeviceStatusMessage, function(channel, message) { message.likelyLeaveReason = 'status_change' io.emit('device.change', { important: true, data: message }) }) - .on(wire.DeviceIdentityMessage, function(channel, message) { + .on(DeviceIdentityMessage, function(channel, message) { datautil.applyData(message) io.emit('device.change', { important: true, data: message }) }) - .on(wire.TransactionProgressMessage, function(channel, message) { + .on(TransactionProgressMessage, function(channel, message) { socket.emit('tx.progress', channel.toString(), message) }) - .on(wire.TransactionDoneMessage, function(channel, message) { + .on(TransactionDoneMessage, function(channel, message) { socket.emit('tx.done', channel.toString(), message) }) - .on(wire.TransactionTreeMessage, function(channel, message) { + .on(TransactionTreeMessage, function(channel, message) { socket.emit('tx.tree', channel.toString(), message) }) - .on(wire.DeviceLogcatEntryMessage, function(channel, message) { + .on(DeviceLogcatEntryMessage, function(channel, message) { socket.emit('logcat.entry', message) }) - .on(wire.AirplaneModeEvent, function(channel, message) { + .on(AirplaneModeEvent, function(channel, message) { io.emit('device.change', { important: true, data: { @@ -334,7 +336,7 @@ export default (async function(options) { } }) }) - .on(wire.BatteryEvent, function(channel, message) { + .on(BatteryEvent, function(channel, message) { var {serial} = message delete message.serial io.emit('device.change', { @@ -345,7 +347,7 @@ export default (async function(options) { } }) }) - .on(wire.GetServicesAvailabilityMessage, function(channel, message) { + .on(GetServicesAvailabilityMessage, function(channel, message) { let serial = message.serial delete message.serial io.emit('device.change', { @@ -356,7 +358,7 @@ export default (async function(options) { } }) }) - .on(wire.DeviceBrowserMessage, function(channel, message) { + .on(DeviceBrowserMessage, function(channel, message) { var {serial} = message delete message.serial io.emit('device.change', { @@ -367,7 +369,7 @@ export default (async function(options) { }) }) }) - .on(wire.ConnectivityEvent, function(channel, message) { + .on(ConnectivityEvent, function(channel, message) { var {serial} = message delete message.serial io.emit('device.change', { @@ -378,7 +380,7 @@ export default (async function(options) { } }) }) - .on(wire.PhoneStateEvent, function(channel, message) { + .on(PhoneStateEvent, function(channel, message) { var {serial} = message delete message.serial io.emit('device.change', { @@ -389,7 +391,7 @@ export default (async function(options) { } }) }) - .on(wire.RotationEvent, function(channel, message) { + .on(RotationEvent, function(channel, message) { socket.emit('device.change', { important: false, data: { @@ -400,7 +402,7 @@ export default (async function(options) { } }) }) - .on(wire.CapabilitiesMessage, function(channel, message) { + .on(CapabilitiesMessage, function(channel, message) { socket.emit('device.change', { important: false, data: { @@ -412,7 +414,7 @@ export default (async function(options) { } }) }) - .on(wire.ReverseForwardsEvent, function(channel, message) { + .on(ReverseForwardsEvent, function(channel, message) { socket.emit('device.change', { important: false, data: { @@ -421,14 +423,14 @@ export default (async function(options) { } }) }) - .on(wire.TemporarilyUnavailableMessage, function(channel, message) { + .on(TemporarilyUnavailableMessage, function(channel, message) { socket.emit('temporarily-unavailable', { data: { removeConnectUrl: message.removeConnectUrl } }) }) - .on(wire.UpdateRemoteConnectUrl, function(channel, message) { + .on(UpdateRemoteConnectUrl, function(channel, message) { socket.emit('device.change', { important: true, data: { @@ -447,10 +449,10 @@ export default (async function(options) { // // Device note .on('device.note', function(data) { - return dbapi + return AllModel .setDeviceNote(data.serial, data.note) .then(function() { - return dbapi.loadDevice(user.groups.subscribed, data.serial) + return AllModel.loadDevice(user.groups.subscribed, data.serial) }) .then(function(device) { if (device) { @@ -469,19 +471,19 @@ export default (async function(options) { // Settings .on('user.settings.update', function(data) { if (data.alertMessage === undefined) { - dbapi.updateUserSettings(user.email, data) + UserModel.updateUserSettings(user.email, data) } else { - dbapi.updateUserSettings(apiutil.STF_ADMIN_EMAIL, data) + UserModel.updateUserSettings(apiutil.STF_ADMIN_EMAIL, data) } }) .on('user.settings.reset', function() { - dbapi.resetUserSettings(user.email) + UserModel.resetUserSettings(user.email) }) .on('user.keys.accessToken.generate', async(data) => { const {title} = data const token = generateToken(user, options.secret) - await dbapi + await AllModel .saveUserAccessToken(user.email, { title: title, id: token.id, @@ -495,7 +497,7 @@ export default (async function(options) { .on('user.keys.accessToken.remove', function(data) { const isAdmin = user.privilege === apiutil.ADMIN const email = (isAdmin ? data.email : null) || user.email - return dbapi + return AllModel .removeUserAccessToken(email, data.title) .then(function() { socket.emit('user.keys.accessToken.updated') @@ -505,16 +507,16 @@ export default (async function(options) { // @ts-ignore return Adb.util.parsePublicKey(data.key) .then(function(key) { - return dbapi.lookupUsersByAdbKey(key.fingerprint) + return UserModel.lookupUsersByAdbKey(key.fingerprint) .then(function(keys) { return keys }) .then(function(users) { if (users.length) { - throw new dbapi.DuplicateSecondaryIndexError() + throw new AllModel.DuplicateSecondaryIndexError() } else { - return dbapi.insertUserAdbKey(user.email, { + return UserModel.insertUserAdbKey(user.email, { title: data.title, fingerprint: key.fingerprint }) @@ -540,16 +542,16 @@ export default (async function(options) { }) }) .on('user.keys.adb.accept', function(data) { - return dbapi.lookupUsersByAdbKey(data.fingerprint) + return UserModel.lookupUsersByAdbKey(data.fingerprint) .then(function(keys) { return keys }) .then(function(users) { if (users.length) { - throw new dbapi.DuplicateSecondaryIndexError() + throw new AllModel.DuplicateSecondaryIndexError() } else { - return dbapi.insertUserAdbKey(user.email, { + return UserModel.insertUserAdbKey(user.email, { title: data.title, fingerprint: data.fingerprint }) @@ -568,12 +570,12 @@ export default (async function(options) { ]) }) // @ts-ignore - .catch(dbapi.DuplicateSecondaryIndexError, function() { + .catch(AllModel.DuplicateSecondaryIndexError, function() { // No-op }) }) .on('user.keys.adb.remove', function(data) { - return dbapi + return UserModel .deleteUserAdbKey(user.email, data.fingerprint) .then(function() { socket.emit('user.keys.adb.removed', data) @@ -581,7 +583,7 @@ export default (async function(options) { }) .on('shell.settings.execute', function(data) { let command = data.command - dbapi.loadDevices().then(devices => { + AllModel.loadDevices().then(devices => { devices.forEach(device => { push.send([ device.channel, @@ -898,11 +900,18 @@ export default (async function(options) { wireutil.transaction(responseChannel, new wire.BluetoothCleanBondedMessage()) ]) }) - .on('group.invite', function(channel, responseChannel, data) { + .on('group.invite', async(channel, responseChannel, data) => { joinChannel(responseChannel) + const keys = await UserModel.getUserAdbKeys(user.email) push.send([ channel, - wireutil.transaction(responseChannel, new wire.GroupMessage(new wire.OwnerMessage(user.email, user.name, user.group), data.timeout || null, wireutil.toDeviceRequirements(data.requirements))) + wireutil.transaction(responseChannel, new wire.GroupMessage( + new wire.OwnerMessage(user.email, user.name, user.group), + data.timeout || null, + wireutil.toDeviceRequirements(data.requirements), + null, + keys.map(key => key.fingerprint) + )) ]) }) .on('group.kick', function(channel, responseChannel, data) { @@ -1334,7 +1343,7 @@ export default (async function(options) { ]) }) .on('policy.accept', function(data) { - dbapi.acceptPolicy(user.email) + UserModel.acceptPolicy(user.email) }) }) .finally(function() { diff --git a/lib/util/apiutil.js b/lib/util/apiutil.js index d10c77cf87..7e33ab56bb 100644 --- a/lib/util/apiutil.js +++ b/lib/util/apiutil.js @@ -3,9 +3,9 @@ import _ from 'lodash' import logger from './logger.js' import datautil from './datautil.js' import wireutil from '../wire/util.js' -import wire from '../wire/index.js' import * as Sentry from '@sentry/node' import {v4 as uuidv4} from 'uuid' +import {ConnectGetForwardUrlMessage} from '../wire/wire.js' const log = logger.createLogger('api:controllers:apiutil') export const PENDING = 'pending' export const READY = 'ready' @@ -140,7 +140,7 @@ export const filterDevice = function(req, device) { let responseChannel = 'txn_' + uuidv4() req.options.push.send([ device.channel, - wireutil.transaction(responseChannel, new wire.ConnectGetForwardUrlMessage()) + wireutil.transaction(responseChannel, ConnectGetForwardUrlMessage.create()) ]) } if (fields) { diff --git a/lib/util/devutil.js b/lib/util/devutil.js index 0de51c695f..132663ee93 100644 --- a/lib/util/devutil.js +++ b/lib/util/devutil.js @@ -13,7 +13,7 @@ export default syrup.serial() devutil.executeShellCommand = function(command) { return adb.getDevice(options.serial).execOut(command).then(result => { - log.debug('executing shell command ' + command, result) + log.debug(`executing shell command ${command}, %s`, result) }) } devutil.ensureUnusedLocalSocket = function(sock) { diff --git a/lib/util/grouputil.js b/lib/util/grouputil.js deleted file mode 100644 index f8123242f4..0000000000 --- a/lib/util/grouputil.js +++ /dev/null @@ -1,59 +0,0 @@ -import util from 'util' -import Promise from 'bluebird' -import semver from 'semver' -import minimatch from 'minimatch' -import wire from '../wire/index.js' -function RequirementMismatchError(name) { - Error.call(this) - this.name = 'RequirementMismatchError' - this.message = util.format('Requirement mismatch for "%s"', name) - Error.captureStackTrace(this, RequirementMismatchError) -} -util.inherits(RequirementMismatchError, Error) -function AlreadyGroupedError() { - Error.call(this) - this.name = 'AlreadyGroupedError' - this.message = 'Already a member of another group' - Error.captureStackTrace(this, AlreadyGroupedError) -} -util.inherits(AlreadyGroupedError, Error) -function NoGroupError() { - Error.call(this) - this.name = 'NoGroupError' - this.message = 'Not a member of any group' - Error.captureStackTrace(this, NoGroupError) -} -util.inherits(NoGroupError, Error) - -/** @type {(capabilities: any, requirements: any) => Promise} */ -export const match = Promise.method(function(capabilities, requirements) { - return requirements.every(function(req) { - var capability = capabilities[req.name] - if (!capability) { - throw new RequirementMismatchError(req.name) - } - switch (req.type) { - case wire.RequirementType.SEMVER: - if (!semver.satisfies(capability, req.value)) { - throw new RequirementMismatchError(req.name) - } - break - case wire.RequirementType.GLOB: - if (!minimatch(capability, req.value)) { - throw new RequirementMismatchError(req.name) - } - break - case wire.RequirementType.EXACT: - if (capability !== req.value) { - throw new RequirementMismatchError(req.name) - } - break - default: - throw new RequirementMismatchError(req.name) - } - return true - }) -}) -export {RequirementMismatchError} -export {AlreadyGroupedError} -export {NoGroupError} diff --git a/lib/util/grouputil.ts b/lib/util/grouputil.ts new file mode 100644 index 0000000000..7c457eb1ec --- /dev/null +++ b/lib/util/grouputil.ts @@ -0,0 +1,67 @@ +import util from 'util' +import semver from 'semver' // @ts-ignore +import minimatch from 'minimatch' // TODO: update +import {RequirementType} from '../wire/wire.js' + +export class RequirementMismatchError extends Error { + constructor(name: string) { + super() + this.name = 'RequirementMismatchError' + this.message = util.format('Requirement mismatch for "%s"', name) + Error.captureStackTrace(this, RequirementMismatchError) + } +} + +export class AlreadyGroupedError extends Error { + constructor() { + super() + this.name = 'AlreadyGroupedError' + this.message = 'Already a member of another group' + Error.captureStackTrace(this, AlreadyGroupedError) + } +} + +export class NoGroupError extends Error { + constructor() { + super() + this.name = 'NoGroupError' + this.message = 'Not a member of any group' + Error.captureStackTrace(this, NoGroupError) + } +} + +interface Requirements { + name: string + value: string + type: RequirementType +} + +export const match = async(capabilities: any, requirements: Requirements[]) => { + return requirements.every((req) => { + const capability = capabilities[req.name] + if (!capability) { + throw new RequirementMismatchError(req.name) + } + + switch (req.type) { + case RequirementType.SEMVER: + if (!semver.satisfies(capability, req.value)) { + throw new RequirementMismatchError(req.name) + } + break + case RequirementType.GLOB: + if (!minimatch(capability, req.value)) { + throw new RequirementMismatchError(req.name) + } + break + case RequirementType.EXACT: + if (capability !== req.value) { + throw new RequirementMismatchError(req.name) + } + break + default: + throw new RequirementMismatchError(req.name) + } + return true + }) +} diff --git a/lib/util/lifecycle.js b/lib/util/lifecycle.js deleted file mode 100644 index ef26d77fbb..0000000000 --- a/lib/util/lifecycle.js +++ /dev/null @@ -1,68 +0,0 @@ -import Promise from 'bluebird' -import logger from './logger.js' - -const log = logger.createLogger('util:lifecycle') - -export default new class Lifecycle { - observers = [] - ending = false - - constructor() { - process.on('SIGINT', this.graceful.bind(this)) - process.on('SIGTERM', this.graceful.bind(this)) - } - - share(name, emitter, options) { - const opts = Object.assign({ - end: true, error: true - }, options) - - if (opts.end) { - emitter.on('end', () => { - if (!this.ending) { - log.fatal(`${name} ended; we shall share its fate`) - this.fatal() - } - }) - } - - if (opts.error) { - emitter.on('error', (err) => { - if (!this.ending) { - log.fatal(`${name} had an error ${err.stack}`) - this.fatal() - } - }) - } - - if (emitter.end) { - this.observe(() => { - emitter.end() - }) - } - return emitter - } - - graceful(err) { - log.info(`Winding down for graceful exit ${err || ''}`) - if (this.ending) { - log.error('Repeated gracefull shutdown request. Exiting immediately.') - process.exit(1) - } - - this.ending = true - return Promise.all(this.observers.map(fn => fn())) - .then(() => process.exit(0)) - } - - /** @returns {any} */ - fatal(/** @type {any} */ err) { - log.fatal(`Shutting down due to fatal error ${err || ''}`) - this.ending = true - process.exit(1) - } - - observe(promise) { - this.observers.push(promise) - } -}() diff --git a/lib/util/lifecycle.ts b/lib/util/lifecycle.ts new file mode 100644 index 0000000000..0948079e8d --- /dev/null +++ b/lib/util/lifecycle.ts @@ -0,0 +1,66 @@ +import EventEmitter from "node:events"; +import logger from "./logger.ts"; + +const log = logger.createLogger("util:lifecycle"); + +type LifecycleObserver = () => Promise | unknown; + +export default new (class Lifecycle { + cleanups: LifecycleObserver[] = []; + ending = false; + + constructor() { + process.on("SIGINT", this.graceful.bind(this)); + process.on("SIGTERM", this.graceful.bind(this)); + } + + share(name: string, emitter: EventEmitter) { + emitter.on("end", () => { + if (!this.ending) { + log.fatal(`${name} ended; we shall share its fate`) + this.fatal(); + } + }); + + emitter.on("error", (err) => { + if (!this.ending) { + log.fatal(`${name} had an error ${err.stack}`) + this.fatal(); + } + }); + + if ('end' in emitter) { + this.observe(() => { + if(typeof emitter.end === 'function') { + emitter.end(); + } + }); + } + return emitter; + } + + graceful(err: Error) { + log.info(`Winding down for graceful exit ${err || ''}`) + if (this.ending) { + log.error( + "Repeated gracefull shutdown request. Exiting immediately." + ); + process.exit(1); + } + + this.ending = true; + return Promise.all(this.cleanups.map((fn) => fn())).then(() => + process.exit(0) + ); + } + + fatal(err?: Error | string): never { + log.fatal(`Shutting down due to fatal error ${err || ''}`) + this.ending = true; + process.exit(1); + } + + observe(cleanupFn: LifecycleObserver) { + this.cleanups.push(cleanupFn); + } +})(); diff --git a/lib/util/logger.ts b/lib/util/logger.ts index dd5faefc39..1c70342bd8 100644 --- a/lib/util/logger.ts +++ b/lib/util/logger.ts @@ -14,7 +14,17 @@ export enum LogLevel { const innerLogger = new EventEmitter() -type LogArguments = [string, ...any[]] +type BuildLog< + N extends number, + S extends any[] = [] // counter +> = + S['length'] extends N + ? [string, []] // base: just string + no args + : [`${BuildLog[0]}%s${string}`, [...BuildLog[1], any]]; + +type NLog = [BuildLog[0], ...BuildLog[1]] + +type LogArguments = NLog<0> | NLog<1> | NLog<2> | NLog<3> | NLog<4> export interface LogEntry { unit: string; @@ -117,7 +127,8 @@ export class Log extends EventEmitter { } private _format(entry: LogEntry): string { - entry.message = printf(...entry.args) + const args = entry.args as [string, ...any[]] + entry.message = printf(...args) const [fg, bg] = Log.unitColors[entry.unit] ?? [chalk.yellow, chalk.bgYellow] return ( `${chalk.grey(entry.timestamp.toJSON())} ${fg(bg(entry.unit))} ${this._name(entry.priority)}/${chalk.bold(entry.tag)} ${entry.pid} [${entry.identifier}] ${entry.message}\n` diff --git a/lib/util/srv.ts b/lib/util/srv.ts index 66179b1f9d..ba2114852d 100644 --- a/lib/util/srv.ts +++ b/lib/util/srv.ts @@ -3,7 +3,6 @@ import util from 'util' import dns from 'dns/promises' import {SrvRecord} from 'dns' import _ from 'lodash' -var srv = Object.create(null) function groupByPriority(records: SrvRecord[]) { return records .sort((a, b) => a.priority - b.priority) @@ -27,7 +26,7 @@ function shuffleWeighted(records: SrvRecord[]) { function pick(records: SrvRecord[], sum: number): SrvRecord[] { const rand = Math.random() * sum let counter = 0 - for (var i = 0, l = records.length; i < l; ++i) { + for (let i = 0, l = records.length; i < l; ++i) { counter += records[i].weight if (rand < counter) { const picked = records.splice(i, 1) diff --git a/lib/util/ttlset.js b/lib/util/ttlset.js deleted file mode 100644 index 8643f10e1b..0000000000 --- a/lib/util/ttlset.js +++ /dev/null @@ -1,94 +0,0 @@ -import util from 'util' -import EventEmitter from 'eventemitter3' -function TtlItem(value) { - this.next = null - this.prev = null - this.time = null - this.value = value -} -function TtlSet(ttl) { - EventEmitter.call(this) - this.head = null - this.tail = null - this.mapping = Object.create(null) - this.ttl = ttl - this.timer = null -} -util.inherits(TtlSet, EventEmitter) -TtlSet.SILENT = 1 -TtlSet.prototype.bump = function(value, time, flags) { - var item = this._remove(this.mapping[value]) || this._create(value, flags) - item.time = time || Date.now() - item.prev = this.tail - this.tail = item - if (item.prev) { - item.prev.next = item - } - else { - this.head = item - this._scheduleCheck() - } -} -TtlSet.prototype.drop = function(value, flags) { - this._drop(this.mapping[value], flags) -} -TtlSet.prototype.stop = function() { - clearTimeout(this.timer) -} -TtlSet.prototype._scheduleCheck = function() { - clearTimeout(this.timer) - if (this.head) { - var delay = Math.max(0, this.ttl - (Date.now() - this.head.time)) - this.timer = setTimeout(this._check.bind(this), delay) - } -} -TtlSet.prototype._check = function() { - var now = Date.now() - var item - while ((item = this.head)) { - if (now - item.time > this.ttl) { - this._drop(item, 0) - } - else { - break - } - } - this._scheduleCheck() -} -TtlSet.prototype._create = function(value, flags) { - var item = new TtlItem(value) - this.mapping[value] = item - if ((flags & TtlSet.SILENT) !== TtlSet.SILENT) { - this.emit('insert', value) - } - return item -} -TtlSet.prototype._drop = function(item, flags) { - if (item) { - this._remove(item) - delete this.mapping[item.value] - if ((flags & TtlSet.SILENT) !== TtlSet.SILENT) { - this.emit('drop', item.value) - } - } -} -TtlSet.prototype._remove = function(item) { - if (!item) { - return null - } - if (item.prev) { - item.prev.next = item.next - } - if (item.next) { - item.next.prev = item.prev - } - if (item === this.head) { - this.head = item.next - } - if (item === this.tail) { - this.tail = item.prev - } - item.next = item.prev = null - return item -} -export default TtlSet diff --git a/lib/util/ttlset.ts b/lib/util/ttlset.ts new file mode 100644 index 0000000000..0c85c36b59 --- /dev/null +++ b/lib/util/ttlset.ts @@ -0,0 +1,113 @@ +import EventEmitter from 'events' + +class TTLItem { + constructor( + public value: string, + public time: number, + public prev: TTLItem | null, + public next: TTLItem | null + ) {} +} + +class TTLSet extends EventEmitter { + private head: TTLItem | null = null + private tail: TTLItem | null = null + private mapping: Record = {} + private timer: NodeJS.Timeout | null = null + + static SILENT = 1 + + constructor( + private ttl = 30_000 + ) { + super() + } + + bump(value: string, time: number, flags?: any) { + const item = + this.remove(this.mapping[value]) || + this.create(value, this.tail, flags) + + item.time = time || Date.now() + this.tail = item + if (item.prev) { + item.prev.next = item + } + else { + this.head = item + } + + this.scheduleCheck() + } + + drop(value: string, flags?: any) { + this._drop(this.mapping[value], flags) + } + + stop() { + clearTimeout(this.timer!) + } + + private scheduleCheck() { + clearTimeout(this.timer!) + if (this.head) { + const delay = Math.max(0, this.ttl - (Date.now() - this.head.time)) + this.timer = setTimeout(this.check.bind(this), delay) + } + } + + private check() { + const now = Date.now() + let item: TTLItem | null + while ((item = this.head)) { + if (now - item.time > this.ttl) { + this._drop(item, 0) + } + else { + break + } + } + this.scheduleCheck() + } + + private create(value: string, prev: TTLItem | null, flags: any) { + const item = new TTLItem(value, 0, prev, null) + this.mapping[value] = item + if ((flags & TTLSet.SILENT) !== TTLSet.SILENT) { + this.emit('insert', value) + } + return item + } + + private _drop(item: TTLItem, flags?: any) { + if (item) { + this.remove(item) + delete this.mapping[item.value] + if ((flags & TTLSet.SILENT) !== TTLSet.SILENT) { + this.emit('drop', item.value) + } + } + } + + private remove(item: TTLItem) { + if (!item) { + return null + } + if (item.prev) { + item.prev.next = item.next + } + if (item.next) { + item.next.prev = item.prev + } + if (item === this.head) { + this.head = item.next + } + if (item === this.tail) { + this.tail = item.prev + } + item.next = item.prev = null + return item + } +} + +export default TTLSet diff --git a/lib/util/zmqutil.js b/lib/util/zmqutil.js index 2d1013b248..3a4d67b438 100644 --- a/lib/util/zmqutil.js +++ b/lib/util/zmqutil.js @@ -20,9 +20,32 @@ const socketTypeMap = { reply: zmq.Reply } +// Shared ZMQ context to avoid creating multiple contexts with thread pools +// Each context creates ioThreads (4 by default), so sharing saves resources +/** @type {zmq.Context | null} */ +let sharedContext = null +const getSharedContext = () => { + if (!sharedContext) { + sharedContext = new zmq.Context({ + blocky: true, + ioThreads: 4, + ipv6: true, + maxSockets: 8192, + }) + } + return sharedContext +} + export class SocketWrapper extends EventEmitter { #sendQueue = Promise.resolve() + /** @type {AsyncIterator | null} */ + #iterator = null + + /** + * @param {string} type + * @param {number} keepAliveInterval + */ constructor(type, keepAliveInterval = 30) { super() @@ -34,18 +57,14 @@ export class SocketWrapper extends EventEmitter { this.isActive = true this.endpoints = new Set() + // @ts-ignore const SocketClass = socketTypeMap[type] this.socket = new SocketClass({ tcpKeepalive: 1, tcpKeepaliveIdle: keepAliveInterval, tcpKeepaliveInterval: keepAliveInterval, tcpKeepaliveCount: 100 - }, new zmq.Context({ - blocky: true, - ioThreads: 4, - ipv6: true, - maxSockets: 8192, - })) + }, getSharedContext()) } bindSync = (address) => this.socket.bindSync(address) @@ -81,26 +100,55 @@ export class SocketWrapper extends EventEmitter { try { await this.socket.send( (Array.isArray(args) ? args : [args]) - .map(arg => Buffer.isBuffer(arg) ? arg : Buffer.from(String(arg))) + .map(arg => Buffer.isBuffer(arg) || ArrayBuffer.isView(arg) ? arg : Buffer.from(String(arg))) ) } catch (/** @type {any} */ err) { log.error('Error on send: %s', err?.message || err?.toString() || JSON.stringify(err)) + throw err // Re-throw to properly handle in the promise chain } } + /** + * @param {any} args + */ send(args) { this.#sendQueue = this.#sendQueue.then(() => this.sendAsync(args)) return this } - close() { + async close() { this.isActive = false + + // Close async iterator if it exists + if (this.#iterator && typeof this.#iterator.return === 'function') { + try { + await this.#iterator.return() + } + catch { + // Ignore errors during cleanup + } + this.#iterator = null + } + + // Wait for send queue to drain before closing socket + try { + await this.#sendQueue.catch(() => {}) + } + catch { + // Ignore errors during cleanup + } + this.socket.close() + this.removeAllListeners() return this } + /** + * + * @returns {Promise} + */ async startReceiveLoop() { const isValidType = this.type === 'sub' || @@ -114,10 +162,10 @@ export class SocketWrapper extends EventEmitter { } try { - const iterator = this.socket[Symbol.asyncIterator]() + this.#iterator = this.socket[Symbol.asyncIterator]() let result - while (this.isActive && !(result = await iterator.next()).done) { + while (this.isActive && this.#iterator && !(result = await this.#iterator.next()).done) { const message = result.value if (Array.isArray(message) && !!message[0]?.toString) { @@ -130,7 +178,7 @@ export class SocketWrapper extends EventEmitter { } } catch (/** @type {any} */ err) { - log.error('Error in message receive loop: %s', err?.message || err?.toString() || err) + log.error('Error in message receive loop: %s, %s', err?.message || err?.toString() || err, err.stack) return this.startReceiveLoop() } } diff --git a/lib/wire/google/protobuf/any.ts b/lib/wire/google/protobuf/any.ts new file mode 100644 index 0000000000..c13b7a74f2 --- /dev/null +++ b/lib/wire/google/protobuf/any.ts @@ -0,0 +1,326 @@ +// @generated by protobuf-ts 2.11.1 with parameter generate_dependencies +// @generated from protobuf file "google/protobuf/any.proto" (package "google.protobuf", syntax proto3) +// tslint:disable +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import { WireType } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import { UnknownFieldHandler } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { reflectionMergePartial } from "@protobuf-ts/runtime"; +import { isJsonObject } from "@protobuf-ts/runtime"; +import { typeofJsonValue } from "@protobuf-ts/runtime"; +import type { JsonValue } from "@protobuf-ts/runtime"; +import { jsonWriteOptions } from "@protobuf-ts/runtime"; +import type { JsonReadOptions } from "@protobuf-ts/runtime"; +import type { JsonWriteOptions } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IMessageType } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +/** + * `Any` contains an arbitrary serialized protocol buffer message along with a + * URL that describes the type of the serialized message. + * + * Protobuf library provides support to pack/unpack Any values in the form + * of utility functions or additional generated methods of the Any type. + * + * Example 1: Pack and unpack a message in C++. + * + * Foo foo = ...; + * Any any; + * any.PackFrom(foo); + * ... + * if (any.UnpackTo(&foo)) { + * ... + * } + * + * Example 2: Pack and unpack a message in Java. + * + * Foo foo = ...; + * Any any = Any.pack(foo); + * ... + * if (any.is(Foo.class)) { + * foo = any.unpack(Foo.class); + * } + * // or ... + * if (any.isSameTypeAs(Foo.getDefaultInstance())) { + * foo = any.unpack(Foo.getDefaultInstance()); + * } + * + * Example 3: Pack and unpack a message in Python. + * + * foo = Foo(...) + * any = Any() + * any.Pack(foo) + * ... + * if any.Is(Foo.DESCRIPTOR): + * any.Unpack(foo) + * ... + * + * Example 4: Pack and unpack a message in Go + * + * foo := &pb.Foo{...} + * any, err := anypb.New(foo) + * if err != nil { + * ... + * } + * ... + * foo := &pb.Foo{} + * if err := any.UnmarshalTo(foo); err != nil { + * ... + * } + * + * The pack methods provided by protobuf library will by default use + * 'type.googleapis.com/full.type.name' as the type URL and the unpack + * methods only use the fully qualified type name after the last '/' + * in the type URL, for example "foo.bar.com/x/y.z" will yield type + * name "y.z". + * + * JSON + * ==== + * The JSON representation of an `Any` value uses the regular + * representation of the deserialized, embedded message, with an + * additional field `@type` which contains the type URL. Example: + * + * package google.profile; + * message Person { + * string first_name = 1; + * string last_name = 2; + * } + * + * { + * "@type": "type.googleapis.com/google.profile.Person", + * "firstName": , + * "lastName": + * } + * + * If the embedded message type is well-known and has a custom JSON + * representation, that representation will be embedded adding a field + * `value` which holds the custom JSON in addition to the `@type` + * field. Example (for message [google.protobuf.Duration][]): + * + * { + * "@type": "type.googleapis.com/google.protobuf.Duration", + * "value": "1.212s" + * } + * + * + * @generated from protobuf message google.protobuf.Any + */ +export interface Any { + /** + * A URL/resource name that uniquely identifies the type of the serialized + * protocol buffer message. This string must contain at least + * one "/" character. The last segment of the URL's path must represent + * the fully qualified name of the type (as in + * `path/google.protobuf.Duration`). The name should be in a canonical form + * (e.g., leading "." is not accepted). + * + * In practice, teams usually precompile into the binary all types that they + * expect it to use in the context of Any. However, for URLs which use the + * scheme `http`, `https`, or no scheme, one can optionally set up a type + * server that maps type URLs to message definitions as follows: + * + * * If no scheme is provided, `https` is assumed. + * * An HTTP GET on the URL must yield a [google.protobuf.Type][] + * value in binary format, or produce an error. + * * Applications are allowed to cache lookup results based on the + * URL, or have them precompiled into a binary to avoid any + * lookup. Therefore, binary compatibility needs to be preserved + * on changes to types. (Use versioned type names to manage + * breaking changes.) + * + * Note: this functionality is not currently available in the official + * protobuf release, and it is not used for type URLs beginning with + * type.googleapis.com. As of May 2023, there are no widely used type server + * implementations and no plans to implement one. + * + * Schemes other than `http`, `https` (or the empty scheme) might be + * used with implementation specific semantics. + * + * + * @generated from protobuf field: string type_url = 1 + */ + typeUrl: string; + /** + * Must be a valid serialized protocol buffer of the above specified type. + * + * @generated from protobuf field: bytes value = 2 + */ + value: Uint8Array; +} +// @generated message type with reflection information, may provide speed optimized methods +class Any$Type extends MessageType { + constructor() { + super("google.protobuf.Any", [ + { no: 1, name: "type_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "value", kind: "scalar", T: 12 /*ScalarType.BYTES*/ } + ]); + } + /** + * Pack the message into a new `Any`. + * + * Uses 'type.googleapis.com/full.type.name' as the type URL. + */ + pack(message: T, type: IMessageType): Any { + return { + typeUrl: this.typeNameToUrl(type.typeName), value: type.toBinary(message), + }; + } + /** + * Unpack the message from the `Any`. + */ + unpack(any: Any, type: IMessageType, options?: Partial): T { + if (!this.contains(any, type)) + throw new Error("Cannot unpack google.protobuf.Any with typeUrl '" + any.typeUrl + "' as " + type.typeName + "."); + return type.fromBinary(any.value, options); + } + /** + * Does the given `Any` contain a packed message of the given type? + */ + contains(any: Any, type: IMessageType | string): boolean { + if (!any.typeUrl.length) + return false; + let wants = typeof type == "string" ? type : type.typeName; + let has = this.typeUrlToName(any.typeUrl); + return wants === has; + } + /** + * Convert the message to canonical JSON value. + * + * You have to provide the `typeRegistry` option so that the + * packed message can be converted to JSON. + * + * The `typeRegistry` option is also required to read + * `google.protobuf.Any` from JSON format. + */ + internalJsonWrite(any: Any, options: JsonWriteOptions): JsonValue { + if (any.typeUrl === "") + return {}; + let typeName = this.typeUrlToName(any.typeUrl); + let opt = jsonWriteOptions(options); + let type = opt.typeRegistry?.find(t => t.typeName === typeName); + if (!type) + throw new globalThis.Error("Unable to convert google.protobuf.Any with typeUrl '" + any.typeUrl + "' to JSON. The specified type " + typeName + " is not available in the type registry."); + let value = type.fromBinary(any.value, { readUnknownField: false }); + let json = type.internalJsonWrite(value, opt); + if (typeName.startsWith("google.protobuf.") || !isJsonObject(json)) + json = { value: json }; + json["@type"] = any.typeUrl; + return json; + } + internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Any): Any { + if (!isJsonObject(json)) + throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON " + typeofJsonValue(json) + "."); + if (typeof json["@type"] != "string" || json["@type"] == "") + return this.create(); + let typeName = this.typeUrlToName(json["@type"]); + let type = options?.typeRegistry?.find(t => t.typeName == typeName); + if (!type) + throw new globalThis.Error("Unable to parse google.protobuf.Any from JSON. The specified type " + typeName + " is not available in the type registry."); + let value; + if (typeName.startsWith("google.protobuf.") && json.hasOwnProperty("value")) + value = type.fromJson(json["value"], options); + else { + let copy = Object.assign({}, json); + delete copy["@type"]; + value = type.fromJson(copy, options); + } + if (target === undefined) + target = this.create(); + target.typeUrl = json["@type"]; + target.value = type.toBinary(value); + return target; + } + typeNameToUrl(name: string): string { + if (!name.length) + throw new Error("invalid type name: " + name); + return "type.googleapis.com/" + name; + } + typeUrlToName(url: string): string { + if (!url.length) + throw new Error("invalid type url: " + url); + let slash = url.lastIndexOf("/"); + let name = slash > 0 ? url.substring(slash + 1) : url; + if (!name.length) + throw new Error("invalid type url: " + url); + return name; + } + create(value?: PartialMessage): Any { + const message = globalThis.Object.create((this.messagePrototype!)); + message.typeUrl = ""; + message.value = new Uint8Array(0); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Any): Any { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string type_url */ 1: + message.typeUrl = reader.string(); + break; + case /* bytes value */ 2: + message.value = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: Any, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string type_url = 1; */ + if (message.typeUrl !== "") + writer.tag(1, WireType.LengthDelimited).string(message.typeUrl); + /* bytes value = 2; */ + if (message.value.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.value); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message google.protobuf.Any + */ +export const Any = new Any$Type(); diff --git a/lib/wire/index.js b/lib/wire/index.js deleted file mode 100644 index fdfa458b9d..0000000000 --- a/lib/wire/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import path from 'path' -import ProtoBuf from 'protobufjs' -var wire = ProtoBuf.loadProtoFile(path.join(import.meta.dirname, 'wire.proto')).build() -wire.ReverseMessageType = Object.keys(wire.MessageType) - .reduce(function(acc, type) { - var code = wire.MessageType[type] - if (!wire[type]) { - throw new Error('wire.MessageType has unknown value "' + type + '"') - } - wire[type].$code = wire[type].prototype.$code = code - acc[code] = type - return acc - }, Object.create(null)) -export default wire diff --git a/lib/wire/index.ts b/lib/wire/index.ts new file mode 100644 index 0000000000..a852eb53cc --- /dev/null +++ b/lib/wire/index.ts @@ -0,0 +1,35 @@ +import { MessageType } from "@protobuf-ts/runtime"; +import { createLogger } from "../util/logger.ts"; +const allClasses = await import('./wire.ts') + + +const log = createLogger('wire:legacy') + +interface UnknownMessage { + new(...args: unknown[]): T + type: MessageType +} + +const alerted = new Set() + +/** + * @deprecated Do not use the proxy for the constructor. Import the model directly from wire.ts + */ +export default new Proxy({} as Record>, { + get(target, prop, receiver) { + const messageType = (allClasses as any)[prop] as MessageType + if (!messageType) { + throw new Error(`Unknown message type tried constructing: ${prop.toString()}`) + } + if (!alerted.has(messageType.typeName)) { + alerted.add(messageType.typeName) + log.warn('Legacy contstructor lookup for %s', messageType.typeName) + } + const construct = function constructor(this: any, ...args: unknown[]) { + const message = messageType.create(Object.fromEntries(messageType.fields.map((name, index) => ([name.localName, args[index]])))) + Object.assign(this, message) + } + construct.type = messageType + return construct + } +}) diff --git a/lib/wire/messagestream.ts b/lib/wire/messagestream.ts index e0ea0e06ae..003ae9ce59 100644 --- a/lib/wire/messagestream.ts +++ b/lib/wire/messagestream.ts @@ -10,7 +10,7 @@ class DelimitedStream extends stream.Transform { this._buffer = Buffer.concat([this._buffer, chunk]) while (this._buffer.length) { if (this._readingLength) { - var byte = this._buffer[0] + const byte = this._buffer[0] this._length += (byte & 0x7f) << (7 * this._lengthIndex) if (byte & (1 << 7)) { this._lengthIndex += 1 diff --git a/lib/wire/router.ts b/lib/wire/router.ts index f0ab4eb122..10331747cb 100644 --- a/lib/wire/router.ts +++ b/lib/wire/router.ts @@ -1,61 +1,53 @@ -import EventEmitter from 'eventemitter3' -import wire from './index.js' -import logger from '../util/logger.js' +import EventEmitter from "eventemitter3"; +import logger from "../util/logger.js"; +import { MessageType } from "@protobuf-ts/runtime"; +import { Envelope } from "./wire.ts"; +import { Any } from "./google/protobuf/any.ts"; -const log = logger.createLogger('wire:router') -export interface WireMessage { - $code: string; -} +const log = logger.createLogger("wire:router"); -type EventType = string | symbol | WireMessage; +type MessageHandler = (channel: string, message: T, data: Buffer) => unknown -export class WireRouter extends EventEmitter { - constructor() { - super() - } +export class WireRouter { + emitter = new EventEmitter() + registeredTypes = new Map> - on( - event: string | symbol, - fn: (...args: any[]) => void, - context?: any - ): this; - on(message: WireMessage, fn: (...args: any[]) => void): this; - on( - eventOrMessage: EventType, - fn: (...args: any[]) => void, - context?: any + on(eventName: string | symbol, fn: MessageHandler, context?: object): this; + on(messageType: MessageType, fn: MessageHandler): this; + on( + messageType: MessageType | string | symbol, + fn: MessageHandler, + context?: object ): this { if ( - typeof eventOrMessage !== 'string' && - typeof eventOrMessage !== 'symbol' && - '$code' in eventOrMessage + typeof messageType !== "string" && + typeof messageType !== "symbol" ) { // WireMessage - super.on(eventOrMessage.$code, fn) - } - else { - super.on(eventOrMessage as string | symbol, fn, context) + this.emitter.on(messageType.typeName, fn); + this.registeredTypes.set(Any.typeNameToUrl(messageType.typeName), messageType) + } else { + this.emitter.on(messageType, fn, context); } return this } - removeListener( - event: string | symbol, - fn: (...args: any[]) => void, - context?: any - ): this; - removeListener(message: WireMessage, fn: (...args: any[]) => void): this; - removeListener( - eventOrMessage: EventType, - fn: (...args: any[]) => void, - context?: any + removeAllListeners(messageType: MessageType) { + this.emitter.removeAllListeners(messageType.typeName) + } + + removeListener(eventName: string | symbol, fn: MessageHandler, context?: object): this; + removeListener(messageType: MessageType, fn: MessageHandler): this; + removeListener( + messageType: MessageType | string | symbol, + fn: MessageHandler, + context?: object ): this { - if (typeof eventOrMessage === 'object' && '$code' in eventOrMessage) { - super.removeListener(eventOrMessage.$code, fn) - } - else { - super.removeListener( - eventOrMessage as string | symbol, + if (typeof messageType === "object") { + this.emitter.removeListener(messageType.typeName, fn); + } else { + this.emitter.removeListener( + messageType, fn, context ) @@ -63,44 +55,48 @@ export class WireRouter extends EventEmitter { return this } - handler(): (channel: any, data: Uint8Array) => void { - return (channel: any, data: Uint8Array) => { - const wrapper = wire.Envelope.decode(data) - const type = wire.ReverseMessageType[wrapper.type] - let decodedMessage: any - - try { - decodedMessage = wire[type].decode(wrapper.message) + handler() { + return (channel: string, data: Buffer) => { + const decoded = Envelope.fromBinary(data); + if (!decoded.message) { + log.warn(`Message without message %s`, decoded) + return + } + let target = decoded.message.typeUrl; + if(!target) { + log.warn(`Message without typeUrl %s`, decoded) + return } - catch (e) { - log.error( - 'Received message with type "%s", but cant parse data ' + - wrapper.message - ) - throw e + const messageType = this.registeredTypes.get(target); + if (!messageType) { + // log.warn(`Unknown message type:`, decoded) + // Nobody is expecting such message type.. Ignoring.. + return } + const decodedMessage = Any.unpack(decoded.message, messageType) + // const wrapper = wire.Envelope.decode(data); + // const type = wire.ReverseMessageType[wrapper.type]; + // let decodedMessage: any; - log.info( - 'Received message with type "%s", and data %s', - type || wrapper.type, - JSON.stringify(decodedMessage) - ) + // try { + // decodedMessage = wire[type].decode(wrapper.message) + // } + // catch (e) { + // log.error( + // 'Received message with type "%s", but cant parse data ' + + // wrapper.message + // ); + // throw e; + // } - if (type) { - this.emit( - wrapper.type, - wrapper.channel || channel, - decodedMessage, - data - ) - this.emit('message', channel) - } - else { - log.warn( - 'Unknown message type "%d", perhaps we need an update?', - wrapper.type - ) - } + // log.info( + // 'Received message with type "%s", and data %s', + // messageType.typeName, + // messageType.toJsonString(decodedMessage) + // ) + + this.emitter.emit(messageType.typeName, decoded.channel || channel, decodedMessage, data) + this.emitter.emit('message', channel) } } } diff --git a/lib/wire/transmanager.js b/lib/wire/transmanager.js deleted file mode 100644 index 014bfb99e1..0000000000 --- a/lib/wire/transmanager.js +++ /dev/null @@ -1,57 +0,0 @@ -import {v4 as uuidv4} from 'uuid' -import apiutil from '../util/apiutil.js' -import wire from './index.js' -import {WireRouter} from './router.js' -import * as Sentry from '@sentry/node' -import wireutil from './util.js' - -export const runTransaction = (channel, message, {sub, push, channelRouter, timeout = apiutil.GRPC_WAIT_TIMEOUT}) => { - return Sentry.startSpan({ - op: 'wireTransaction', - name: message.$code, - attributes: { - message, - channel, - timeout - }, - forceTransaction: true, - }, () => { - const responseChannel = 'txn_' + uuidv4() - sub.subscribe(responseChannel) - return new Promise((resolve, reject) => { - const messageListener = new WireRouter() - .on(wire.TransactionDoneMessage, function(channel, message) { - clearTimeout(trTimeout) - sub.unsubscribe(responseChannel) - channelRouter.removeListener(responseChannel, messageListener) - if (message.success) { - resolve(message) - } - else { - reject(message) - } - }) - .handler() - - const trTimeout = setTimeout(function() { - channelRouter.removeListener(responseChannel, messageListener) - sub.unsubscribe(responseChannel) - - Sentry.addBreadcrumb({ - data: {channel, message, timeout}, - message: 'Transaction context', - level: 'warning', - type: 'default' - }) - Sentry.captureMessage('Timeout when running transaction') - reject(new Error('Timeout when running transaction')) - }, timeout) - - channelRouter.on(responseChannel, messageListener) - push.send([ - channel, - wireutil.transaction(responseChannel, message) - ]) - }) - }) -} diff --git a/lib/wire/transmanager.ts b/lib/wire/transmanager.ts new file mode 100644 index 0000000000..27dc0eb88a --- /dev/null +++ b/lib/wire/transmanager.ts @@ -0,0 +1,122 @@ +import {v4 as uuidv4} from 'uuid' +import apiutil from '../util/apiutil.js' +import {TransactionDoneMessage} from './wire.js' +import {WireRouter} from './router.js' +import * as Sentry from '@sentry/node' +import wireutil from './util.js' +import type {SocketWrapper} from '../util/zmqutil.js' +import EventEmitter from 'events' +import {MessageType} from '@protobuf-ts/runtime' + +const sentryTransactionSpan = >(channel: string, message: any, timeout: number, cb: () => T): T => + Sentry.startSpan({ + op: 'wireTransaction', + name: message.$code, + attributes: { + message, + channel, + timeout + }, + forceTransaction: true, + }, cb) + +const sentryCaptureTimeout = (channel: string, message: any, timeout: number) => { + Sentry.addBreadcrumb({ + data: {channel, message, timeout}, + message: 'Transaction context', + level: 'warning', + type: 'default' + }) + Sentry.captureMessage('Timeout when running transaction') +} + +interface TransactionTransportOptions { + sub: SocketWrapper + push: SocketWrapper + channelRouter: EventEmitter + timeout?: number +} + +export const runTransaction = (channel: string, messageType: MessageType, message: T, {sub, push, channelRouter, timeout = apiutil.GRPC_WAIT_TIMEOUT}: TransactionTransportOptions) => + sentryTransactionSpan( + channel, + message, + timeout, + () => { + const responseChannel = 'txn_' + uuidv4() + sub.subscribe(responseChannel) + return new Promise((resolve, reject) => { + const messageListener = new WireRouter() + .on(TransactionDoneMessage, (channel: string, message: any) => { + clearTimeout(trTimeout) + sub.unsubscribe(responseChannel) + channelRouter.removeListener(responseChannel, messageListener) + if (message.success) { + resolve(message) + } + else { + reject(message) + } + }) + .handler() + + const trTimeout = setTimeout(function() { + channelRouter.removeListener(responseChannel, messageListener) + sub.unsubscribe(responseChannel) + + sentryCaptureTimeout(channel, message, timeout) + reject(new Error('Timeout when running transaction')) + }, timeout) + + channelRouter.on(responseChannel, messageListener) + push.send([ + channel, + wireutil.tr(responseChannel, messageType, message) + ]) + }) + } + ) + +type TransactionDevTransportOptions = Omit & { + router: WireRouter +} + +export const runTransactionDev = (channel: string, messageType: MessageType, message: T, {sub, push, router, timeout = apiutil.GRPC_WAIT_TIMEOUT}: TransactionDevTransportOptions): Promise => + sentryTransactionSpan( + channel, + message, + timeout, + () => { + const responseChannel = 'txn_' + uuidv4() + sub.subscribe(responseChannel) + return new Promise((resolve, reject) => { + const messageListener = (channel: string, message: any) => { + clearTimeout(trTimeout) + sub.unsubscribe(responseChannel) + router.removeListener(TransactionDoneMessage, messageListener) + + const body = message.body ? JSON.parse(message.body) : {} + if (message.success) { + resolve(body) + } + else { + reject(body) + } + } + router.on(TransactionDoneMessage, messageListener) + + const trTimeout = setTimeout(() => { + router.removeListener(TransactionDoneMessage, messageListener) + sub.unsubscribe(responseChannel) + + sentryCaptureTimeout(channel, message, timeout) + reject(new Error('Timeout when running transaction')) + }, timeout) + + push.send([ + channel, + wireutil.tr(responseChannel, messageType, message) + ]) + }) + } + ) diff --git a/lib/wire/util.js b/lib/wire/util.js deleted file mode 100644 index 8994705efa..0000000000 --- a/lib/wire/util.js +++ /dev/null @@ -1,63 +0,0 @@ -import {v4 as uuidv4} from 'uuid' -import wire from './index.js' -const wireutil = { - global: '*ALL', - makePrivateChannel: function() { - // @ts-ignore - return uuidv4(null, Buffer.alloc(16)).toString('base64') - }, - toDeviceStatus: function(type) { - return wire.DeviceStatus[{ - device: 'ONLINE', - emulator: 'ONLINE', - unauthorized: 'UNAUTHORIZED', - offline: 'OFFLINE', - connecting: 'CONNECTING', - authorizing: 'AUTHORIZING' - }[type]] - }, - toDeviceRequirements: function(/** @type {{ [x: string]: {value: string, match: "semver" | "glob" | "exact"}; }} */ requirements) { - return Object.keys(requirements).map(function(name) { - var item = requirements[name] - return new wire.DeviceRequirement(name, item.value, wire.RequirementType[item.match.toUpperCase()]) - }) - }, - toInstalledApps: function(installedApps) { - if (installedApps.length > 0) { - return installedApps.map(instApp => { - return new wire.Applications(instApp.bundleId, instApp.bundleName) - }) - } - else { - return [] - } - }, - envelope: function(message) { - return new wire.Envelope(message.$code, message.encode()).encodeNB() - }, - transaction: function(channel, message) { - return new wire.Envelope(message.$code, message.encode(), channel) - .encodeNB() - }, - reply: function(source) { - var seq = 0 - return { - okay: function(data, body) { - return wireutil.envelope(new wire.TransactionDoneMessage(source, seq++, true, data === null ? null : (data || 'success'), body ? JSON.stringify(body) : null)) - }, - fail: function(data, body) { - return wireutil.envelope(new wire.TransactionDoneMessage(source, seq++, false, data || 'fail', body ? JSON.stringify(body) : null)) - }, - tree: function(data, body) { - return wireutil.envelope(new wire.TransactionTreeMessage(source, seq++, true, data === null ? null : (data || 'success'), body ? JSON.stringify(body) : null)) - }, - progress: function(data, progress) { - return wireutil.envelope(new wire.TransactionProgressMessage(source, seq++, data, ~~progress)) - }, - device: function(data, body) { - return wireutil.envelope(new wire.TransationGetMessage(source, body ? JSON.stringify(body) : null)) - } - } - } -} -export default wireutil diff --git a/lib/wire/util.ts b/lib/wire/util.ts new file mode 100644 index 0000000000..748c4b04d7 --- /dev/null +++ b/lib/wire/util.ts @@ -0,0 +1,108 @@ + +import crypto from 'node:crypto' +import {DeviceRequirement, DeviceStatus, Envelope, RequirementType, TransactionDoneMessage, TransactionProgressMessage} from './wire.ts' +import { Any } from './google/protobuf/any.ts'; +import { createLogger } from '../util/logger.ts'; +import {MessageType} from "@protobuf-ts/runtime"; +import { ADBDeviceType } from '../units/provider/ADBObserver.js'; + +const DEVICE_STATUS_MAP = { + device: 'ONLINE', + // emulator: 'ONLINE', + unauthorized: 'UNAUTHORIZED', + offline: 'OFFLINE', + // connecting: 'CONNECTING', + // authorizing: 'AUTHORIZING', + unknown: 'OFFLINE', + recovery: 'OFFLINE', + bootloader: 'OFFLINE', + sideload: 'OFFLINE' +} as const satisfies Record // TODO: replace value type with proper type once it's ready + +const log = createLogger('wireutil') + +const wireutil = { + global: '*ALL', + makePrivateChannel() { + return crypto.randomBytes(16).toString('base64') + }, + toDeviceStatus(type: keyof typeof DEVICE_STATUS_MAP) { + return DeviceStatus[DEVICE_STATUS_MAP[type]] + }, + toDeviceRequirements(requirements: Record) { + return Object.keys(requirements).map(function(name) { + let item = requirements[name] + return DeviceRequirement.create({ + name, + value: item.value, + type: RequirementType[item.match.toUpperCase() as 'SEMVER' | 'GLOB' | 'EXACT'] + }) + }) + }, + /** + * @deprecated Do not use raw envelope with a message. Use `pack` for type safety + */ + envelope(message: object) { + return this.oldSend(message) + }, + // envelope(Message.create({...})) // <- forbidden - no way to extract the type + // envelope(new wire.Message(...)) + + pack(messageType: MessageType, message: T, channel: string | undefined = undefined) { + return Envelope.toBinary({ message: Any.pack(message, messageType), channel} ) + }, + + tr(channel: string, messageType: MessageType, message: T) { + return Envelope.toBinary({ message: Any.pack(message, messageType), channel} ) + }, + + /** + * @deprecated Use `tr` for type safety + */ + transaction(channel: string, message: object) { + return this.oldSend(message, channel) + }, + + oldSend(message: object, channel: string | undefined = undefined) { + // @ts-expect-error + const messageType = message.__proto__.constructor.type as MessageType + return this.pack(messageType, message, channel) + }, + + reply(source: string) { + let seq = 0 + return { + okay(data?: string, body?: string | object) { + return wireutil.pack(TransactionDoneMessage, { + source, + seq: seq++, + success: true, + data: data ?? 'success', + body: body ? JSON.stringify(body) : undefined + }) + }, + fail(data?: string, body?:string | object) { + return wireutil.pack(TransactionDoneMessage, { + source, + seq: seq++, + success: false, + data: data ?? 'fail', + body: body ? JSON.stringify(body) : undefined + }) + }, + progress(data: string, progress: number) { + if (!Number.isInteger(progress)) { + log.warn('Somebody is sending non integer as progress: %s', data) + progress = Math.round(progress) + } + return wireutil.pack(TransactionProgressMessage, { + source, + seq: seq++, + data: data, + progress: progress + }) + } + } + } +} +export default wireutil diff --git a/lib/wire/wire.proto b/lib/wire/wire.proto index a0aac52000..655b7138a8 100644 --- a/lib/wire/wire.proto +++ b/lib/wire/wire.proto @@ -4,136 +4,13 @@ // Message wrapper -enum MessageType { - CopyMessage = 33; - DeviceIntroductionMessage = 74; - DeviceAbsentMessage = 111; - DeviceIdentityMessage = 2; - DeviceLogcatEntryMessage = 3; - DeviceLogMessage = 4; - DeviceReadyMessage = 5; - DevicePresentMessage = 6; - DevicePropertiesMessage = 7; - DeviceRegisteredMessage = 8; - DeviceStatusMessage = 9; - DeviceTypeMessage = 20; - GroupMessage = 10; - InstallMessage = 30; - PhysicalIdentifyMessage = 29; - JoinGroupMessage = 11; - JoinGroupByAdbFingerprintMessage = 69; - JoinGroupByVncAuthResponseMessage = 90; - VncAuthResponsesUpdatedMessage = 91; - AutoGroupMessage = 70; - AdbKeysUpdatedMessage = 71; - KeyDownMessage = 12; - KeyPressMessage = 13; - KeyUpMessage = 14; - LaunchActivityMessage = 31; - LeaveGroupMessage = 15; - LogcatApplyFiltersMessage = 16; - PasteMessage = 32; - ProbeMessage = 17; - ShellCommandMessage = 18; - ShellKeepAliveMessage = 19; - TouchDownMessage = 21; - TouchMoveMessage = 22; - TouchUpMessage = 23; - TouchCommitMessage = 65; - TouchResetMessage = 66; - GestureStartMessage = 67; - GestureStopMessage = 68; - TransactionDoneMessage = 24; - TransactionProgressMessage = 25; - TypeMessage = 26; - UngroupMessage = 27; - UninstallMessage = 34; - RotateMessage = 35; - ForwardTestMessage = 36; - ForwardCreateMessage = 37; - ForwardRemoveMessage = 38; - LogcatStartMessage = 39; - LogcatStopMessage = 40; - BrowserOpenMessage = 41; - BrowserClearMessage = 42; - AirplaneModeEvent = 43; - BatteryEvent = 44; - DeviceBrowserMessage = 45; - ConnectivityEvent = 46; - PhoneStateEvent = 47; - RotationEvent = 48; - StoreOpenMessage = 49; - ScreenCaptureMessage = 50; - DeviceHeartbeatMessage = 73; - RebootMessage = 52; - ConnectStartMessage = 53; - ConnectStopMessage = 54; - RingerSetMessage = 56; - RingerGetMessage = 64; - WifiSetEnabledMessage = 57; - WifiGetStatusMessage = 58; - AccountAddMenuMessage = 59; - AccountAddMessage = 60; - AccountCheckMessage = 63; - AccountGetMessage = 62; - AccountRemoveMessage = 55; - SdStatusMessage = 61; - ReverseForwardsEvent = 72; - FileSystemListMessage = 81; - FileSystemGetMessage = 82; - InstalledApplications = 83; - GetInstalledApplications = 84; - Applications = 85; - ConnectStartedMessage = 92; - ConnectStoppedMessage = 93; - SetDeviceDisplay = 94; - IosDevicePorts = 95; - StartStreaming = 96; - TouchMoveIosMessage = 99; - DeviceIosIntroductionMessage = 100; - ProviderIosMessage = 101; - DeleteDevice = 104; - SetAbsentDisconnectedDevices = 105; - UninstallIosMessage = 106; - SetDeviceApp = 107; - GetIosDeviceApps = 109; - TransationGetMessage = 110; - UpdateIosDevice = 112; - SdkIosVersion = 114; - SizeIosDevice = 115; - DashboardOpenMessage = 116; - GetIosTreeElements = 117; - TransactionTreeMessage = 118; - TapDeviceTreeElement = 119; - TemporarilyUnavailableMessage = 120; - InitializeIosDeviceState = 121; - UpdateRemoteConnectUrl = 122; - GroupUserChangeMessage = 1200; - DeviceGroupChangeMessage = 1201; - DeviceOriginGroupMessage = 1202; - DeleteUserMessage = 1203; - UpdateAccessTokenMessage = 1204; - GroupChangeMessage = 1205; - UserChangeMessage = 1206; - DeviceChangeMessage = 1207; - IosServiceMessage = 1208; - ChangeQualityMessage = 1209; - InstallResultMessage = 1210; - UnlockDeviceMessage = 1211; - CapabilitiesMessage = 1212; - AirplaneSetMessage = 1213; - ConnectGetForwardUrlMessage = 9000; - GetServicesAvailabilityMessage = 9001; - BluetoothSetEnabledMessage = 9002; - BluetoothGetStatusMessage = 9003; - BluetoothCleanBondedMessage = 9004; - LaunchDeviceApp = 9005; - TerminateDeviceApp = 9006; - KillDeviceApp = 9007; - GetAppAsset = 9008; - GetAppAssetsList = 9009; - GetAppHTML = 9010; - GetAppInspectServerUrl = 9011; +import "google/protobuf/any.proto"; + + +message Envelope { + // required MessageType type = 1; + required google.protobuf.Any message = 2; + optional string channel = 3; } message UpdateAccessTokenMessage { @@ -323,12 +200,6 @@ message FileSystemGetMessage { optional string jwt = 2; } -message Envelope { - required MessageType type = 1; - required bytes message = 2; - optional string channel = 3; -} - message TransactionProgressMessage { required string source = 1; required uint32 seq = 2; @@ -406,7 +277,7 @@ message DeviceIntroductionMessage { required string serial = 1; required DeviceStatus status = 2; required ProviderMessage provider = 3; -// optional DeviceGroupMessage group = 4; + optional string deviceType = 4; } message DeviceIosIntroductionMessage { @@ -559,6 +430,7 @@ message GroupMessage { optional uint32 timeout = 2; repeated DeviceRequirement requirements = 3; optional string usage = 4; + repeated string keys = 5; } message AutoGroupMessage { @@ -574,6 +446,7 @@ message JoinGroupMessage { required string serial = 1; required OwnerMessage owner = 2; optional string usage = 3; + optional uint32 timeout = 4; } message JoinGroupByAdbFingerprintMessage { @@ -1024,3 +897,19 @@ message GetAppHTML { message GetAppInspectServerUrl { } + +message DeviceStatusChange { + required string serial = 1; + required uint32 timeout = 2; +} + +message DeviceGetIsInOrigin { + required string serial = 1; +} + +message GetPresentDevices { +} + +message GetDeadDevices { + required uint32 time = 1; +} diff --git a/lib/wire/wire.ts b/lib/wire/wire.ts new file mode 100644 index 0000000000..438ab51313 --- /dev/null +++ b/lib/wire/wire.ts @@ -0,0 +1,11802 @@ +// @generated by protobuf-ts 2.11.1 with parameter generate_dependencies +// @generated from protobuf file "wire.proto" (syntax proto2) +// tslint:disable +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import { WireType } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import { UnknownFieldHandler } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { reflectionMergePartial } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +import { Any } from "./google/protobuf/any.js"; // NOTE: KEEP THIS. ADD .js MANUALLY. +/** + * @generated from protobuf message Envelope + */ +export interface Envelope { + /** + * required MessageType type = 1; + * + * @generated from protobuf field: required google.protobuf.Any message = 2 + */ + message?: Any; + /** + * @generated from protobuf field: optional string channel = 3 + */ + channel?: string; +} +/** + * @generated from protobuf message UpdateAccessTokenMessage + */ +export interface UpdateAccessTokenMessage { +} +/** + * @generated from protobuf message UnlockDeviceMessage + */ +export interface UnlockDeviceMessage { +} +/** + * @generated from protobuf message DeleteUserMessage + */ +export interface DeleteUserMessage { + /** + * @generated from protobuf field: required string email = 1 + */ + email: string; +} +/** + * @generated from protobuf message DeviceOriginGroupMessage + */ +export interface DeviceOriginGroupMessage { + /** + * @generated from protobuf field: required string signature = 1 + */ + signature: string; +} +/** + * @generated from protobuf message UserQuotasDetailField + */ +export interface UserQuotasDetailField { + /** + * @generated from protobuf field: required double duration = 1 + */ + duration: number; + /** + * @generated from protobuf field: required uint32 number = 2 + */ + number: number; +} +/** + * @generated from protobuf message UserQuotasField + */ +export interface UserQuotasField { + /** + * @generated from protobuf field: required UserQuotasDetailField allocated = 1 + */ + allocated?: UserQuotasDetailField; + /** + * @generated from protobuf field: required UserQuotasDetailField consumed = 2 + */ + consumed?: UserQuotasDetailField; + /** + * @generated from protobuf field: required uint32 defaultGroupsDuration = 3 + */ + defaultGroupsDuration: number; + /** + * @generated from protobuf field: required uint32 defaultGroupsNumber = 4 + */ + defaultGroupsNumber: number; + /** + * @generated from protobuf field: required uint32 defaultGroupsRepetitions = 5 + */ + defaultGroupsRepetitions: number; + /** + * @generated from protobuf field: required uint32 repetitions = 6 + */ + repetitions: number; +} +/** + * @generated from protobuf message UserGroupsField + */ +export interface UserGroupsField { + /** + * @generated from protobuf field: required UserQuotasField quotas = 1 + */ + quotas?: UserQuotasField; + /** + * @generated from protobuf field: repeated string subscribed = 2 + */ + subscribed: string[]; +} +/** + * @generated from protobuf message AlertMessageField + */ +export interface AlertMessageField { + /** + * @generated from protobuf field: required string activation = 1 + */ + activation: string; + /** + * @generated from protobuf field: required string data = 2 + */ + data: string; + /** + * @generated from protobuf field: required string level = 3 + */ + level: string; +} +/** + * @generated from protobuf message UserSettingsField + */ +export interface UserSettingsField { + /** + * @generated from protobuf field: optional AlertMessageField alertMessage = 1 + */ + alertMessage?: AlertMessageField; +} +/** + * @generated from protobuf message UserField + */ +export interface UserField { + /** + * @generated from protobuf field: required string email = 1 + */ + email: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required string privilege = 3 + */ + privilege: string; + /** + * @generated from protobuf field: required UserGroupsField groups = 4 + */ + groups?: UserGroupsField; + /** + * @generated from protobuf field: optional UserSettingsField settings = 5 + */ + settings?: UserSettingsField; +} +/** + * @generated from protobuf message UserChangeMessage + */ +export interface UserChangeMessage { + /** + * @generated from protobuf field: required UserField user = 1 + */ + user?: UserField; + /** + * @generated from protobuf field: required bool isAddedGroup = 2 + */ + isAddedGroup: boolean; + /** + * @generated from protobuf field: repeated string groups = 3 + */ + groups: string[]; + /** + * @generated from protobuf field: required string action = 4 + */ + action: string; + /** + * @generated from protobuf field: repeated string targets = 5 + */ + targets: string[]; + /** + * @generated from protobuf field: required double timeStamp = 6 + */ + timeStamp: number; +} +/** + * @generated from protobuf message DeviceNetworkField + */ +export interface DeviceNetworkField { + /** + * @generated from protobuf field: optional string type = 1 + */ + type?: string; + /** + * @generated from protobuf field: optional string subtype = 2 + */ + subtype?: string; +} +/** + * @generated from protobuf message DeviceDisplayField + */ +export interface DeviceDisplayField { + /** + * @generated from protobuf field: optional uint32 height = 1 + */ + height?: number; + /** + * @generated from protobuf field: optional uint32 width = 2 + */ + width?: number; +} +/** + * @generated from protobuf message DevicePhoneField + */ +export interface DevicePhoneField { + /** + * @generated from protobuf field: optional string imei = 1 + */ + imei?: string; +} +/** + * @generated from protobuf message DeviceProviderField + */ +export interface DeviceProviderField { + /** + * @generated from protobuf field: optional string name = 1 + */ + name?: string; +} +/** + * @generated from protobuf message DeviceGroupField + */ +export interface DeviceGroupField { + /** + * @generated from protobuf field: optional string id = 1 + */ + id?: string; + /** + * @generated from protobuf field: optional string name = 2 + */ + name?: string; + /** + * @generated from protobuf field: optional string origin = 3 + */ + origin?: string; + /** + * @generated from protobuf field: optional string originName = 4 + */ + originName?: string; + /** + * @generated from protobuf field: optional GroupOwnerField owner = 5 + */ + owner?: GroupOwnerField; +} +/** + * @generated from protobuf message DeviceField + */ +export interface DeviceField { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: optional string model = 2 + */ + model?: string; + /** + * @generated from protobuf field: optional string version = 3 + */ + version?: string; + /** + * @generated from protobuf field: optional string operator = 4 + */ + operator?: string; + /** + * @generated from protobuf field: optional DeviceNetworkField network = 5 + */ + network?: DeviceNetworkField; + /** + * @generated from protobuf field: optional DeviceDisplayField display = 6 + */ + display?: DeviceDisplayField; + /** + * @generated from protobuf field: optional string manufacturer = 7 + */ + manufacturer?: string; + /** + * @generated from protobuf field: optional string sdk = 8 + */ + sdk?: string; + /** + * @generated from protobuf field: optional string abi = 9 + */ + abi?: string; + /** + * @generated from protobuf field: optional string cpuPlatform = 10 + */ + cpuPlatform?: string; + /** + * @generated from protobuf field: optional string openGLESVersion = 11 + */ + openGLESVersion?: string; + /** + * @generated from protobuf field: optional DevicePhoneField phone = 12 + */ + phone?: DevicePhoneField; + /** + * @generated from protobuf field: optional DeviceProviderField provider = 13 + */ + provider?: DeviceProviderField; + /** + * @generated from protobuf field: optional DeviceGroupField group = 14 + */ + group?: DeviceGroupField; + /** + * @generated from protobuf field: optional string marketName = 15 + */ + marketName?: string; +} +/** + * @generated from protobuf message DeviceChangeMessage + */ +export interface DeviceChangeMessage { + /** + * @generated from protobuf field: required DeviceField device = 1 + */ + device?: DeviceField; + /** + * @generated from protobuf field: required string action = 2 + */ + action: string; + /** + * @generated from protobuf field: required string oldOriginGroupId = 3 + */ + oldOriginGroupId: string; + /** + * @generated from protobuf field: required double timeStamp = 4 + */ + timeStamp: number; +} +/** + * @generated from protobuf message GroupDateField + */ +export interface GroupDateField { + /** + * @generated from protobuf field: required string start = 1 + */ + start: string; + /** + * @generated from protobuf field: required string stop = 2 + */ + stop: string; +} +/** + * @generated from protobuf message GroupOwnerField + */ +export interface GroupOwnerField { + /** + * @generated from protobuf field: required string email = 1 + */ + email: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; +} +/** + * @generated from protobuf message GroupField + */ +export interface GroupField { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required string class = 3 + */ + class: string; + /** + * @generated from protobuf field: required string privilege = 4 + */ + privilege: string; + /** + * @generated from protobuf field: required GroupOwnerField owner = 5 + */ + owner?: GroupOwnerField; + /** + * @generated from protobuf field: repeated GroupDateField dates = 6 + */ + dates: GroupDateField[]; + /** + * @generated from protobuf field: required uint32 duration = 7 + */ + duration: number; + /** + * @generated from protobuf field: required uint32 repetitions = 8 + */ + repetitions: number; + /** + * @generated from protobuf field: repeated string devices = 9 + */ + devices: string[]; + /** + * @generated from protobuf field: repeated string users = 10 + */ + users: string[]; + /** + * @generated from protobuf field: required string state = 11 + */ + state: string; + /** + * @generated from protobuf field: required bool isActive = 12 + */ + isActive: boolean; + /** + * @generated from protobuf field: repeated string moderators = 13 + */ + moderators: string[]; +} +/** + * @generated from protobuf message GroupChangeMessage + */ +export interface GroupChangeMessage { + /** + * @generated from protobuf field: required GroupField group = 1 + */ + group?: GroupField; + /** + * @generated from protobuf field: required string action = 2 + */ + action: string; + /** + * @generated from protobuf field: repeated string subscribers = 3 + */ + subscribers: string[]; + /** + * @generated from protobuf field: required bool isChangedDates = 4 + */ + isChangedDates: boolean; + /** + * @generated from protobuf field: required bool isChangedClass = 5 + */ + isChangedClass: boolean; + /** + * @generated from protobuf field: required bool isAddedUser = 6 + */ + isAddedUser: boolean; + /** + * @generated from protobuf field: repeated string users = 7 + */ + users: string[]; + /** + * @generated from protobuf field: required bool isAddedDevice = 8 + */ + isAddedDevice: boolean; + /** + * @generated from protobuf field: repeated string devices = 9 + */ + devices: string[]; + /** + * @generated from protobuf field: required double timeStamp = 10 + */ + timeStamp: number; +} +/** + * @generated from protobuf message DeviceGroupChangeMessage + */ +export interface DeviceGroupChangeMessage { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required DeviceGroupMessage group = 2 + */ + group?: DeviceGroupMessage; + /** + * @generated from protobuf field: required string serial = 3 + */ + serial: string; +} +/** + * @generated from protobuf message GroupUserChangeMessage + */ +export interface GroupUserChangeMessage { + /** + * @generated from protobuf field: repeated string users = 1 + */ + users: string[]; + /** + * @generated from protobuf field: required bool isAdded = 2 + */ + isAdded: boolean; + /** + * @generated from protobuf field: required string id = 3 + */ + id: string; + /** + * @generated from protobuf field: required bool isDeletedLater = 4 + */ + isDeletedLater: boolean; + /** + * @generated from protobuf field: repeated string devices = 5 + */ + devices: string[]; +} +/** + * @generated from protobuf message ConnectStartedMessage + */ +export interface ConnectStartedMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string url = 2 + */ + url: string; +} +/** + * @generated from protobuf message InstallResultMessage + */ +export interface InstallResultMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string result = 2 + */ + result: string; +} +/** + * @generated from protobuf message ConnectStoppedMessage + */ +export interface ConnectStoppedMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message FileSystemListMessage + */ +export interface FileSystemListMessage { + /** + * @generated from protobuf field: required string dir = 1 + */ + dir: string; +} +/** + * @generated from protobuf message FileSystemGetMessage + */ +export interface FileSystemGetMessage { + /** + * @generated from protobuf field: required string file = 1 + */ + file: string; + /** + * @generated from protobuf field: optional string jwt = 2 + */ + jwt?: string; +} +/** + * @generated from protobuf message TransactionProgressMessage + */ +export interface TransactionProgressMessage { + /** + * @generated from protobuf field: required string source = 1 + */ + source: string; + /** + * @generated from protobuf field: required uint32 seq = 2 + */ + seq: number; + /** + * @generated from protobuf field: optional string data = 3 + */ + data?: string; + /** + * @generated from protobuf field: optional uint32 progress = 4 [default = 0] + */ + progress?: number; +} +/** + * @generated from protobuf message TransactionDoneMessage + */ +export interface TransactionDoneMessage { + /** + * @generated from protobuf field: required string source = 1 + */ + source: string; + /** + * @generated from protobuf field: required uint32 seq = 2 + */ + seq: number; + /** + * @generated from protobuf field: required bool success = 3 + */ + success: boolean; + /** + * @generated from protobuf field: optional string data = 4 + */ + data?: string; + /** + * @generated from protobuf field: optional string body = 5 + */ + body?: string; +} +/** + * @generated from protobuf message TransactionTreeMessage + */ +export interface TransactionTreeMessage { + /** + * @generated from protobuf field: required string source = 1 + */ + source: string; + /** + * @generated from protobuf field: required uint32 seq = 2 + */ + seq: number; + /** + * @generated from protobuf field: required bool success = 3 + */ + success: boolean; + /** + * @generated from protobuf field: optional string data = 4 + */ + data?: string; + /** + * @generated from protobuf field: optional string body = 5 + */ + body?: string; +} +// Logging + +/** + * @generated from protobuf message DeviceLogMessage + */ +export interface DeviceLogMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required double timestamp = 2 + */ + timestamp: number; + /** + * @generated from protobuf field: required uint32 priority = 3 + */ + priority: number; + /** + * @generated from protobuf field: required string tag = 4 + */ + tag: string; + /** + * @generated from protobuf field: required uint32 pid = 5 + */ + pid: number; + /** + * @generated from protobuf field: required string message = 6 + */ + message: string; + /** + * @generated from protobuf field: required string identifier = 7 + */ + identifier: string; +} +// Introductions + +/** + * @generated from protobuf message DeviceGroupOwnerMessage + */ +export interface DeviceGroupOwnerMessage { + /** + * @generated from protobuf field: required string email = 1 + */ + email: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; +} +/** + * @generated from protobuf message DeviceGroupLifetimeMessage + */ +export interface DeviceGroupLifetimeMessage { + /** + * @generated from protobuf field: required double start = 1 + */ + start: number; + /** + * @generated from protobuf field: required double stop = 2 + */ + stop: number; +} +/** + * @generated from protobuf message DeviceGroupMessage + */ +export interface DeviceGroupMessage { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required DeviceGroupOwnerMessage owner = 3 + */ + owner?: DeviceGroupOwnerMessage; + /** + * @generated from protobuf field: required DeviceGroupLifetimeMessage lifeTime = 4 + */ + lifeTime?: DeviceGroupLifetimeMessage; + /** + * @generated from protobuf field: required string class = 5 + */ + class: string; + /** + * @generated from protobuf field: required uint32 repetitions = 6 + */ + repetitions: number; + /** + * @generated from protobuf field: required string originName = 7 + */ + originName: string; +} +/** + * @generated from protobuf message ProviderMessage + */ +export interface ProviderMessage { + /** + * @generated from protobuf field: required string channel = 1 + */ + channel: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; +} +/** + * @generated from protobuf message ProviderIosMessage + */ +export interface ProviderIosMessage { + /** + * @generated from protobuf field: required string channel = 1 + */ + channel: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required string screenWsUrlPattern = 3 + */ + screenWsUrlPattern: string; +} +/** + * @generated from protobuf message DeviceHeartbeatMessage + */ +export interface DeviceHeartbeatMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message DeviceIntroductionMessage + */ +export interface DeviceIntroductionMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required DeviceStatus status = 2 + */ + status: DeviceStatus; + /** + * @generated from protobuf field: required ProviderMessage provider = 3 + */ + provider?: ProviderMessage; + /** + * @generated from protobuf field: optional string deviceType = 4 + */ + deviceType?: string; +} +/** + * @generated from protobuf message DeviceIosIntroductionMessage + */ +export interface DeviceIosIntroductionMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required DeviceStatus status = 2 + */ + status: DeviceStatus; + /** + * @generated from protobuf field: required ProviderMessage provider = 3 + */ + provider?: ProviderMessage; +} +/** + * @generated from protobuf message InitializeIosDeviceState + */ +export interface InitializeIosDeviceState { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required DeviceStatus status = 2 + */ + status: DeviceStatus; + /** + * @generated from protobuf field: required ProviderIosMessage provider = 3 + */ + provider?: ProviderIosMessage; + /** + * @generated from protobuf field: required IosDevicePorts ports = 4 + */ + ports?: IosDevicePorts; + /** + * @generated from protobuf field: required UpdateIosDevice options = 5 + */ + options?: UpdateIosDevice; +} +/** + * @generated from protobuf message DeviceRegisteredMessage + */ +export interface DeviceRegisteredMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message DevicePresentMessage + */ +export interface DevicePresentMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message DeviceAbsentMessage + */ +export interface DeviceAbsentMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message DeviceReadyMessage + */ +export interface DeviceReadyMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string channel = 2 + */ + channel: string; +} +/** + * @generated from protobuf message ProbeMessage + */ +export interface ProbeMessage { +} +/** + * @generated from protobuf message DeviceStatusMessage + */ +export interface DeviceStatusMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required DeviceStatus status = 2 + */ + status: DeviceStatus; +} +/** + * @generated from protobuf message DeviceTypeMessage + */ +export interface DeviceTypeMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string type = 2 + */ + type: string; +} +/** + * @generated from protobuf message DeviceDisplayMessage + */ +export interface DeviceDisplayMessage { + /** + * @generated from protobuf field: required int32 id = 1 + */ + id: number; + /** + * @generated from protobuf field: required int32 width = 2 + */ + width: number; + /** + * @generated from protobuf field: required int32 height = 3 + */ + height: number; + /** + * @generated from protobuf field: required int32 rotation = 4 + */ + rotation: number; + /** + * @generated from protobuf field: required float xdpi = 5 + */ + xdpi: number; + /** + * @generated from protobuf field: required float ydpi = 6 + */ + ydpi: number; + /** + * @generated from protobuf field: required float fps = 7 + */ + fps: number; + /** + * @generated from protobuf field: required float density = 8 + */ + density: number; + /** + * @generated from protobuf field: required bool secure = 9 + */ + secure: boolean; + /** + * @generated from protobuf field: required string url = 10 + */ + url: string; + /** + * @generated from protobuf field: optional float size = 11 + */ + size?: number; +} +/** + * @generated from protobuf message DeviceBrowserAppMessage + */ +export interface DeviceBrowserAppMessage { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required string type = 2 + */ + type: string; + /** + * @generated from protobuf field: required string name = 3 + */ + name: string; + /** + * @generated from protobuf field: required bool selected = 4 + */ + selected: boolean; + /** + * @generated from protobuf field: required bool system = 5 + */ + system: boolean; +} +/** + * @generated from protobuf message DeviceBrowserMessage + */ +export interface DeviceBrowserMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required bool selected = 2 + */ + selected: boolean; + /** + * @generated from protobuf field: repeated DeviceBrowserAppMessage apps = 3 + */ + apps: DeviceBrowserAppMessage[]; +} +/** + * @generated from protobuf message GetServicesAvailabilityMessage + */ +export interface GetServicesAvailabilityMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required bool hasGMS = 2 + */ + hasGMS: boolean; + /** + * @generated from protobuf field: required bool hasHMS = 3 + */ + hasHMS: boolean; +} +/** + * @generated from protobuf message DevicePhoneMessage + */ +export interface DevicePhoneMessage { + /** + * @generated from protobuf field: optional string imei = 1 + */ + imei?: string; + /** + * @generated from protobuf field: optional string imsi = 5 + */ + imsi?: string; + /** + * @generated from protobuf field: optional string phoneNumber = 2 + */ + phoneNumber?: string; + /** + * @generated from protobuf field: optional string iccid = 3 + */ + iccid?: string; + /** + * @generated from protobuf field: optional string network = 4 + */ + network?: string; +} +/** + * @generated from protobuf message DeviceIdentityMessage + */ +export interface DeviceIdentityMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string platform = 2 + */ + platform: string; + /** + * @generated from protobuf field: required string manufacturer = 3 + */ + manufacturer: string; + /** + * @generated from protobuf field: optional string operator = 4 + */ + operator?: string; + /** + * @generated from protobuf field: required string model = 5 + */ + model: string; + /** + * @generated from protobuf field: required string version = 6 + */ + version: string; + /** + * @generated from protobuf field: required string abi = 7 + */ + abi: string; + /** + * @generated from protobuf field: required string sdk = 8 + */ + sdk: string; + /** + * @generated from protobuf field: required DeviceDisplayMessage display = 9 + */ + display?: DeviceDisplayMessage; + /** + * @generated from protobuf field: required DevicePhoneMessage phone = 11 + */ + phone?: DevicePhoneMessage; + /** + * @generated from protobuf field: optional string product = 12 + */ + product?: string; + /** + * @generated from protobuf field: optional string cpuPlatform = 13 + */ + cpuPlatform?: string; + /** + * @generated from protobuf field: optional string openGLESVersion = 14 + */ + openGLESVersion?: string; + /** + * @generated from protobuf field: optional string marketName = 15 + */ + marketName?: string; + /** + * @generated from protobuf field: optional string macAddress = 16 + */ + macAddress?: string; + /** + * @generated from protobuf field: optional string ram = 17 + */ + ram?: string; +} +/** + * @generated from protobuf message DeviceProperty + */ +export interface DeviceProperty { + /** + * @generated from protobuf field: required string name = 1 + */ + name: string; + /** + * @generated from protobuf field: required string value = 2 + */ + value: string; +} +/** + * @generated from protobuf message DevicePropertiesMessage + */ +export interface DevicePropertiesMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: repeated DeviceProperty properties = 2 + */ + properties: DeviceProperty[]; +} +/** + * @generated from protobuf message DeviceRequirement + */ +export interface DeviceRequirement { + /** + * @generated from protobuf field: required string name = 1 + */ + name: string; + /** + * @generated from protobuf field: required string value = 2 + */ + value: string; + /** + * @generated from protobuf field: required RequirementType type = 3 + */ + type: RequirementType; +} +/** + * @generated from protobuf message OwnerMessage + */ +export interface OwnerMessage { + /** + * @generated from protobuf field: required string email = 1 + */ + email: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required string group = 3 + */ + group: string; +} +/** + * @generated from protobuf message GroupMessage + */ +export interface GroupMessage { + /** + * @generated from protobuf field: required OwnerMessage owner = 1 + */ + owner?: OwnerMessage; + /** + * @generated from protobuf field: optional uint32 timeout = 2 + */ + timeout?: number; + /** + * @generated from protobuf field: repeated DeviceRequirement requirements = 3 + */ + requirements: DeviceRequirement[]; + /** + * @generated from protobuf field: optional string usage = 4 + */ + usage?: string; + /** + * @generated from protobuf field: repeated string keys = 5 + */ + keys: string[]; +} +/** + * @generated from protobuf message AutoGroupMessage + */ +export interface AutoGroupMessage { + /** + * @generated from protobuf field: required OwnerMessage owner = 1 + */ + owner?: OwnerMessage; + /** + * @generated from protobuf field: required string identifier = 2 + */ + identifier: string; +} +/** + * @generated from protobuf message UngroupMessage + */ +export interface UngroupMessage { + /** + * @generated from protobuf field: repeated DeviceRequirement requirements = 2 + */ + requirements: DeviceRequirement[]; +} +/** + * @generated from protobuf message JoinGroupMessage + */ +export interface JoinGroupMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required OwnerMessage owner = 2 + */ + owner?: OwnerMessage; + /** + * @generated from protobuf field: optional string usage = 3 + */ + usage?: string; + /** + * @generated from protobuf field: optional uint32 timeout = 4 + */ + timeout?: number; +} +/** + * @generated from protobuf message JoinGroupByAdbFingerprintMessage + */ +export interface JoinGroupByAdbFingerprintMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string fingerprint = 2 + */ + fingerprint: string; + /** + * @generated from protobuf field: optional string comment = 3 + */ + comment?: string; + /** + * @generated from protobuf field: optional string currentGroup = 4 + */ + currentGroup?: string; +} +/** + * @generated from protobuf message JoinGroupByVncAuthResponseMessage + */ +export interface JoinGroupByVncAuthResponseMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string response = 2 + */ + response: string; + /** + * @generated from protobuf field: optional string currentGroup = 4 + */ + currentGroup?: string; +} +/** + * @generated from protobuf message AdbKeysUpdatedMessage + */ +export interface AdbKeysUpdatedMessage { +} +/** + * @generated from protobuf message VncAuthResponsesUpdatedMessage + */ +export interface VncAuthResponsesUpdatedMessage { +} +/** + * @generated from protobuf message LeaveGroupMessage + */ +export interface LeaveGroupMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required OwnerMessage owner = 2 + */ + owner?: OwnerMessage; + /** + * @generated from protobuf field: required string reason = 3 + */ + reason: string; +} +// Input + +/** + * @generated from protobuf message PhysicalIdentifyMessage + */ +export interface PhysicalIdentifyMessage { +} +/** + * @generated from protobuf message TouchDownMessage + */ +export interface TouchDownMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; + /** + * @generated from protobuf field: required uint32 contact = 2 + */ + contact: number; + /** + * @generated from protobuf field: required float x = 3 + */ + x: number; + /** + * @generated from protobuf field: required float y = 4 + */ + y: number; + /** + * @generated from protobuf field: optional float pressure = 5 + */ + pressure?: number; +} +/** + * @generated from protobuf message TouchMoveMessage + */ +export interface TouchMoveMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; + /** + * @generated from protobuf field: required uint32 contact = 2 + */ + contact: number; + /** + * @generated from protobuf field: required float x = 3 + */ + x: number; + /** + * @generated from protobuf field: required float y = 4 + */ + y: number; + /** + * @generated from protobuf field: optional float pressure = 5 + */ + pressure?: number; +} +/** + * @generated from protobuf message TouchMoveIosMessage + */ +export interface TouchMoveIosMessage { + /** + * @generated from protobuf field: required float toX = 1 + */ + toX: number; + /** + * @generated from protobuf field: required float toY = 2 + */ + toY: number; + /** + * @generated from protobuf field: required float fromX = 3 + */ + fromX: number; + /** + * @generated from protobuf field: required float fromY = 4 + */ + fromY: number; + /** + * @generated from protobuf field: optional float duration = 5 + */ + duration?: number; +} +/** + * @generated from protobuf message TouchUpMessage + */ +export interface TouchUpMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; + /** + * @generated from protobuf field: required uint32 contact = 2 + */ + contact: number; +} +/** + * @generated from protobuf message TouchCommitMessage + */ +export interface TouchCommitMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; +} +/** + * @generated from protobuf message TouchResetMessage + */ +export interface TouchResetMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; +} +/** + * @generated from protobuf message GestureStartMessage + */ +export interface GestureStartMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; +} +/** + * @generated from protobuf message GestureStopMessage + */ +export interface GestureStopMessage { + /** + * @generated from protobuf field: required uint32 seq = 1 + */ + seq: number; +} +/** + * @generated from protobuf message TypeMessage + */ +export interface TypeMessage { + /** + * @generated from protobuf field: required string text = 1 + */ + text: string; +} +/** + * @generated from protobuf message PasteMessage + */ +export interface PasteMessage { + /** + * @generated from protobuf field: required string text = 1 + */ + text: string; +} +/** + * @generated from protobuf message CopyMessage + */ +export interface CopyMessage { +} +/** + * @generated from protobuf message KeyDownMessage + */ +export interface KeyDownMessage { + /** + * @generated from protobuf field: required string key = 1 + */ + key: string; +} +/** + * @generated from protobuf message KeyUpMessage + */ +export interface KeyUpMessage { + /** + * @generated from protobuf field: required string key = 1 + */ + key: string; +} +/** + * @generated from protobuf message KeyPressMessage + */ +export interface KeyPressMessage { + /** + * @generated from protobuf field: required string key = 1 + */ + key: string; +} +/** + * @generated from protobuf message RebootMessage + */ +export interface RebootMessage { +} +// Output + +/** + * @generated from protobuf message DeviceLogcatEntryMessage + */ +export interface DeviceLogcatEntryMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required double date = 2 + */ + date: number; + /** + * @generated from protobuf field: required uint32 pid = 3 + */ + pid: number; + /** + * @generated from protobuf field: required uint32 tid = 4 + */ + tid: number; + /** + * @generated from protobuf field: required uint32 priority = 5 + */ + priority: number; + /** + * @generated from protobuf field: required string tag = 6 + */ + tag: string; + /** + * @generated from protobuf field: required string message = 7 + */ + message: string; +} +/** + * @generated from protobuf message LogcatFilter + */ +export interface LogcatFilter { + /** + * @generated from protobuf field: required string tag = 1 + */ + tag: string; + /** + * @generated from protobuf field: required uint32 priority = 2 + */ + priority: number; +} +/** + * @generated from protobuf message LogcatStartMessage + */ +export interface LogcatStartMessage { + /** + * @generated from protobuf field: repeated LogcatFilter filters = 1 + */ + filters: LogcatFilter[]; +} +/** + * @generated from protobuf message LogcatStopMessage + */ +export interface LogcatStopMessage { +} +/** + * @generated from protobuf message LogcatApplyFiltersMessage + */ +export interface LogcatApplyFiltersMessage { + /** + * @generated from protobuf field: repeated LogcatFilter filters = 1 + */ + filters: LogcatFilter[]; +} +// Commands + +/** + * @generated from protobuf message ShellCommandMessage + */ +export interface ShellCommandMessage { + /** + * @generated from protobuf field: required string command = 1 + */ + command: string; + /** + * @generated from protobuf field: required uint32 timeout = 2 + */ + timeout: number; +} +/** + * @generated from protobuf message ShellKeepAliveMessage + */ +export interface ShellKeepAliveMessage { + /** + * @generated from protobuf field: required uint32 timeout = 1 + */ + timeout: number; +} +/** + * @generated from protobuf message InstallMessage + */ +export interface InstallMessage { + /** + * @generated from protobuf field: required string href = 1 + */ + href: string; + /** + * @generated from protobuf field: required bool launch = 2 + */ + launch: boolean; + /** + * @generated from protobuf field: required bool isApi = 3 + */ + isApi: boolean; + /** + * @generated from protobuf field: optional string manifest = 4 + */ + manifest?: string; + /** + * @generated from protobuf field: repeated string installFlags = 5 + */ + installFlags: string[]; + /** + * @generated from protobuf field: optional string jwt = 6 + */ + jwt?: string; // used for storage authorization + /** + * @generated from protobuf field: optional string pkg = 7 + */ + pkg?: string; // used for .tpk installation via sdb +} +/** + * @generated from protobuf message UninstallMessage + */ +export interface UninstallMessage { + /** + * @generated from protobuf field: required string packageName = 1 + */ + packageName: string; +} +/** + * @generated from protobuf message UninstallIosMessage + */ +export interface UninstallIosMessage { + /** + * @generated from protobuf field: required string packageName = 1 + */ + packageName: string; +} +/** + * @generated from protobuf message LaunchActivityMessage + */ +export interface LaunchActivityMessage { + /** + * @generated from protobuf field: required string action = 1 + */ + action: string; + /** + * @generated from protobuf field: required string component = 2 + */ + component: string; + /** + * @generated from protobuf field: repeated string category = 3 + */ + category: string[]; + /** + * @generated from protobuf field: optional uint32 flags = 4 + */ + flags?: number; +} +/** + * @generated from protobuf message RotateMessage + */ +export interface RotateMessage { + /** + * @generated from protobuf field: required int32 rotation = 1 + */ + rotation: number; +} +/** + * @generated from protobuf message ChangeQualityMessage + */ +export interface ChangeQualityMessage { + /** + * @generated from protobuf field: required int32 quality = 1 + */ + quality: number; +} +/** + * @generated from protobuf message ForwardTestMessage + */ +export interface ForwardTestMessage { + /** + * @generated from protobuf field: required string targetHost = 1 + */ + targetHost: string; + /** + * @generated from protobuf field: required uint32 targetPort = 2 + */ + targetPort: number; +} +/** + * @generated from protobuf message ForwardCreateMessage + */ +export interface ForwardCreateMessage { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required uint32 devicePort = 2 + */ + devicePort: number; + /** + * @generated from protobuf field: required string targetHost = 3 + */ + targetHost: string; + /** + * @generated from protobuf field: required uint32 targetPort = 4 + */ + targetPort: number; +} +/** + * @generated from protobuf message ForwardRemoveMessage + */ +export interface ForwardRemoveMessage { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; +} +/** + * @generated from protobuf message ReverseForward + */ +export interface ReverseForward { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required uint32 devicePort = 2 + */ + devicePort: number; + /** + * @generated from protobuf field: required string targetHost = 3 + */ + targetHost: string; + /** + * @generated from protobuf field: required uint32 targetPort = 4 + */ + targetPort: number; +} +/** + * @generated from protobuf message ReverseForwardsEvent + */ +export interface ReverseForwardsEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: repeated ReverseForward forwards = 2 + */ + forwards: ReverseForward[]; +} +/** + * @generated from protobuf message BrowserOpenMessage + */ +export interface BrowserOpenMessage { + /** + * @generated from protobuf field: required string url = 1 + */ + url: string; + /** + * @generated from protobuf field: optional string browser = 2 + */ + browser?: string; +} +/** + * @generated from protobuf message BrowserClearMessage + */ +export interface BrowserClearMessage { + /** + * @generated from protobuf field: optional string browser = 1 + */ + browser?: string; +} +/** + * @generated from protobuf message StoreOpenMessage + */ +export interface StoreOpenMessage { +} +/** + * @generated from protobuf message ScreenCaptureMessage + */ +export interface ScreenCaptureMessage { +} +/** + * @generated from protobuf message ConnectStartMessage + */ +export interface ConnectStartMessage { +} +/** + * @generated from protobuf message ConnectGetForwardUrlMessage + */ +export interface ConnectGetForwardUrlMessage { +} +/** + * @generated from protobuf message ConnectStopMessage + */ +export interface ConnectStopMessage { +} +/** + * @generated from protobuf message AccountAddMenuMessage + */ +export interface AccountAddMenuMessage { +} +/** + * @generated from protobuf message AccountAddMessage + */ +export interface AccountAddMessage { + /** + * @generated from protobuf field: required string user = 1 + */ + user: string; + /** + * @generated from protobuf field: required string password = 2 + */ + password: string; +} +/** + * @generated from protobuf message AccountCheckMessage + */ +export interface AccountCheckMessage { + /** + * @generated from protobuf field: required string type = 1 + */ + type: string; + /** + * @generated from protobuf field: required string account = 2 + */ + account: string; +} +/** + * @generated from protobuf message AccountGetMessage + */ +export interface AccountGetMessage { + /** + * @generated from protobuf field: optional string type = 1 + */ + type?: string; +} +/** + * @generated from protobuf message AccountRemoveMessage + */ +export interface AccountRemoveMessage { + /** + * @generated from protobuf field: required string type = 1 + */ + type: string; + /** + * @generated from protobuf field: optional string account = 2 + */ + account?: string; +} +/** + * @generated from protobuf message SdStatusMessage + */ +export interface SdStatusMessage { +} +/** + * @generated from protobuf message AirplaneSetMessage + */ +export interface AirplaneSetMessage { + /** + * @generated from protobuf field: required bool enabled = 1 + */ + enabled: boolean; +} +/** + * @generated from protobuf message RingerSetMessage + */ +export interface RingerSetMessage { + /** + * @generated from protobuf field: required RingerMode mode = 1 + */ + mode: RingerMode; +} +/** + * @generated from protobuf message RingerGetMessage + */ +export interface RingerGetMessage { +} +/** + * @generated from protobuf message WifiSetEnabledMessage + */ +export interface WifiSetEnabledMessage { + /** + * @generated from protobuf field: required bool enabled = 1 + */ + enabled: boolean; +} +/** + * @generated from protobuf message WifiGetStatusMessage + */ +export interface WifiGetStatusMessage { +} +/** + * @generated from protobuf message BluetoothSetEnabledMessage + */ +export interface BluetoothSetEnabledMessage { + /** + * @generated from protobuf field: required bool enabled = 1 + */ + enabled: boolean; +} +/** + * @generated from protobuf message BluetoothGetStatusMessage + */ +export interface BluetoothGetStatusMessage { +} +/** + * @generated from protobuf message BluetoothCleanBondedMessage + */ +export interface BluetoothCleanBondedMessage { +} +/** + * @generated from protobuf message CapabilitiesMessage + */ +export interface CapabilitiesMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required bool hasTouch = 2 + */ + hasTouch: boolean; + /** + * @generated from protobuf field: required bool hasCursor = 3 + */ + hasCursor: boolean; // TODO: + // required bool hasKeyboard = 1; + // hasLogs + // hasMedia + // hasClipboard and stuff like that, but later.. +} +// Events, these must be kept in sync with STFService/wire.proto + +/** + * @generated from protobuf message AirplaneModeEvent + */ +export interface AirplaneModeEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required bool enabled = 2 + */ + enabled: boolean; +} +/** + * @generated from protobuf message BatteryEvent + */ +export interface BatteryEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string status = 2 + */ + status: string; + /** + * @generated from protobuf field: required string health = 3 + */ + health: string; + /** + * @generated from protobuf field: required string source = 4 + */ + source: string; + /** + * @generated from protobuf field: required uint32 level = 5 + */ + level: number; + /** + * @generated from protobuf field: required uint32 scale = 6 + */ + scale: number; + /** + * @generated from protobuf field: required double temp = 7 + */ + temp: number; + /** + * @generated from protobuf field: optional double voltage = 8 + */ + voltage?: number; +} +/** + * @generated from protobuf message ConnectivityEvent + */ +export interface ConnectivityEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required bool connected = 2 + */ + connected: boolean; + /** + * @generated from protobuf field: optional string type = 3 + */ + type?: string; + /** + * @generated from protobuf field: optional string subtype = 4 + */ + subtype?: string; + /** + * @generated from protobuf field: optional bool failover = 5 + */ + failover?: boolean; + /** + * @generated from protobuf field: optional bool roaming = 6 + */ + roaming?: boolean; +} +/** + * @generated from protobuf message PhoneStateEvent + */ +export interface PhoneStateEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string state = 2 + */ + state: string; + /** + * @generated from protobuf field: required bool manual = 3 + */ + manual: boolean; + /** + * @generated from protobuf field: optional string operator = 4 + */ + operator?: string; +} +/** + * @generated from protobuf message RotationEvent + */ +export interface RotationEvent { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required int32 rotation = 2 + */ + rotation: number; + /** + * @generated from protobuf field: optional int32 width = 3 + */ + width?: number; + /** + * @generated from protobuf field: optional int32 height = 4 + */ + height?: number; +} +/** + * @generated from protobuf message SetDeviceDisplay + */ +export interface SetDeviceDisplay { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string channel = 2 + */ + channel: string; + /** + * @generated from protobuf field: required int32 width = 3 + */ + width: number; + /** + * @generated from protobuf field: required int32 height = 4 + */ + height: number; +} +/** + * @generated from protobuf message IosDevicePorts + */ +export interface IosDevicePorts { + /** + * @generated from protobuf field: required int32 screenPort = 2 + */ + screenPort: number; + /** + * @generated from protobuf field: required int32 connectPort = 3 + */ + connectPort: number; +} +/** + * @generated from protobuf message StartStreaming + */ +export interface StartStreaming { + /** + * @generated from protobuf field: required int32 port = 1 + */ + port: number; + /** + * @generated from protobuf field: required string channel = 2 + */ + channel: string; +} +/** + * @generated from protobuf message DeleteDevice + */ +export interface DeleteDevice { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message SetAbsentDisconnectedDevices + */ +export interface SetAbsentDisconnectedDevices { +} +/** + * @generated from protobuf message Applications + */ +export interface Applications { + /** + * @generated from protobuf field: required string bundleId = 1 + */ + bundleId: string; + /** + * @generated from protobuf field: required string bundleName = 2 + */ + bundleName: string; +} +/** + * @generated from protobuf message InstalledApplications + */ +export interface InstalledApplications { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: repeated Applications applications = 2 + */ + applications: Applications[]; +} +/** + * @generated from protobuf message TransportInstalledApps + */ +export interface TransportInstalledApps { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message SetDeviceApp + */ +export interface SetDeviceApp { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string bundleId = 2 + */ + bundleId: string; + /** + * @generated from protobuf field: required string bundleName = 3 + */ + bundleName: string; + /** + * @generated from protobuf field: required string pathToApp = 4 + */ + pathToApp: string; +} +/** + * @generated from protobuf message GetIosDeviceApps + */ +export interface GetIosDeviceApps { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required string bundleId = 2 + */ + bundleId: string; + /** + * @generated from protobuf field: required string bundleName = 3 + */ + bundleName: string; + /** + * @generated from protobuf field: required string pathToApp = 4 + */ + pathToApp: string; +} +/** + * @generated from protobuf message TransationGetMessage + */ +export interface TransationGetMessage { + /** + * @generated from protobuf field: required string source = 1 + */ + source: string; + /** + * @generated from protobuf field: required string data = 2 + */ + data: string; +} +/** + * required string serial = 1; + * optional string channel = 2; + * + * @generated from protobuf message GetInstalledApplications + */ +export interface GetInstalledApplications { +} +/** + * @generated from protobuf message UpdateIosDevice + */ +export interface UpdateIosDevice { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required string name = 2 + */ + name: string; + /** + * @generated from protobuf field: required string platform = 3 + */ + platform: string; + /** + * @generated from protobuf field: required string architecture = 4 + */ + architecture: string; + /** + * @generated from protobuf field: required string sdk = 5 + */ + sdk: string; + /** + * @generated from protobuf field: required IosServiceMessage service = 6 + */ + service?: IosServiceMessage; +} +/** + * @generated from protobuf message SdkIosVersion + */ +export interface SdkIosVersion { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required string sdkVersion = 2 + */ + sdkVersion: string; +} +/** + * @generated from protobuf message SizeIosDevice + */ +export interface SizeIosDevice { + /** + * @generated from protobuf field: required string id = 1 + */ + id: string; + /** + * @generated from protobuf field: required double height = 2 + */ + height: number; + /** + * @generated from protobuf field: required double width = 3 + */ + width: number; + /** + * @generated from protobuf field: required int32 scale = 4 + */ + scale: number; +} +/** + * @generated from protobuf message DashboardOpenMessage + */ +export interface DashboardOpenMessage { +} +/** + * @generated from protobuf message GetIosTreeElements + */ +export interface GetIosTreeElements { +} +/** + * @generated from protobuf message TapDeviceTreeElement + */ +export interface TapDeviceTreeElement { + /** + * @generated from protobuf field: required string label = 1 + */ + label: string; +} +/** + * @generated from protobuf message TemporarilyUnavailableMessage + */ +export interface TemporarilyUnavailableMessage { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message UpdateRemoteConnectUrl + */ +export interface UpdateRemoteConnectUrl { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message IosServiceMessage + */ +export interface IosServiceMessage { + /** + * @generated from protobuf field: required bool hasAPNS = 1 + */ + hasAPNS: boolean; +} +/** + * @generated from protobuf message LaunchDeviceApp + */ +export interface LaunchDeviceApp { + /** + * @generated from protobuf field: required string pkg = 1 + */ + pkg: string; +} +/** + * @generated from protobuf message TerminateDeviceApp + */ +export interface TerminateDeviceApp { +} +/** + * @generated from protobuf message KillDeviceApp + */ +export interface KillDeviceApp { +} +/** + * @generated from protobuf message GetAppAsset + */ +export interface GetAppAsset { + /** + * @generated from protobuf field: required string url = 1 + */ + url: string; +} +/** + * @generated from protobuf message GetAppAssetsList + */ +export interface GetAppAssetsList { +} +/** + * @generated from protobuf message GetAppHTML + */ +export interface GetAppHTML { +} +/** + * @generated from protobuf message GetAppInspectServerUrl + */ +export interface GetAppInspectServerUrl { +} +/** + * @generated from protobuf message DeviceStatusChange + */ +export interface DeviceStatusChange { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; + /** + * @generated from protobuf field: required uint32 timeout = 2 + */ + timeout: number; +} +/** + * @generated from protobuf message DeviceGetIsInOrigin + */ +export interface DeviceGetIsInOrigin { + /** + * @generated from protobuf field: required string serial = 1 + */ + serial: string; +} +/** + * @generated from protobuf message GetPresentDevices + */ +export interface GetPresentDevices { +} +/** + * @generated from protobuf message GetDeadDevices + */ +export interface GetDeadDevices { + /** + * @generated from protobuf field: required uint32 time = 1 + */ + time: number; +} +/** + * @generated from protobuf enum DeviceStatus + */ +export enum DeviceStatus { + /** + * @generated synthetic value - protobuf-ts requires all enums to have a 0 value + */ + UNSPECIFIED$ = 0, + /** + * @generated from protobuf enum value: OFFLINE = 1; + */ + OFFLINE = 1, + /** + * @generated from protobuf enum value: UNAUTHORIZED = 2; + */ + UNAUTHORIZED = 2, + /** + * @generated from protobuf enum value: ONLINE = 3; + */ + ONLINE = 3, + /** + * @generated from protobuf enum value: CONNECTING = 4; + */ + CONNECTING = 4, + /** + * @generated from protobuf enum value: AUTHORIZING = 5; + */ + AUTHORIZING = 5, + /** + * @generated from protobuf enum value: PREPARING = 6; + */ + PREPARING = 6, + /** + * @generated from protobuf enum value: UNHEALTHY = 7; + */ + UNHEALTHY = 7 +} +// Grouping + +/** + * @generated from protobuf enum RequirementType + */ +export enum RequirementType { + /** + * @generated synthetic value - protobuf-ts requires all enums to have a 0 value + */ + UNSPECIFIED$ = 0, + /** + * @generated from protobuf enum value: SEMVER = 1; + */ + SEMVER = 1, + /** + * @generated from protobuf enum value: GLOB = 2; + */ + GLOB = 2, + /** + * @generated from protobuf enum value: EXACT = 3; + */ + EXACT = 3 +} +/** + * @generated from protobuf enum RingerMode + */ +export enum RingerMode { + /** + * @generated from protobuf enum value: SILENT = 0; + */ + SILENT = 0, + /** + * @generated from protobuf enum value: VIBRATE = 1; + */ + VIBRATE = 1, + /** + * @generated from protobuf enum value: NORMAL = 2; + */ + NORMAL = 2 +} +// @generated message type with reflection information, may provide speed optimized methods +class Envelope$Type extends MessageType { + constructor() { + super("Envelope", [ + { no: 2, name: "message", kind: "message", T: () => Any }, + { no: 3, name: "channel", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): Envelope { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Envelope): Envelope { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required google.protobuf.Any message */ 2: + message.message = Any.internalBinaryRead(reader, reader.uint32(), options, message.message); + break; + case /* optional string channel */ 3: + message.channel = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: Envelope, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required google.protobuf.Any message = 2; */ + if (message.message) + Any.internalBinaryWrite(message.message, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* optional string channel = 3; */ + if (message.channel !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.channel); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message Envelope + */ +export const Envelope = new Envelope$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UpdateAccessTokenMessage$Type extends MessageType { + constructor() { + super("UpdateAccessTokenMessage", []); + } + create(value?: PartialMessage): UpdateAccessTokenMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UpdateAccessTokenMessage): UpdateAccessTokenMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UpdateAccessTokenMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UpdateAccessTokenMessage + */ +export const UpdateAccessTokenMessage = new UpdateAccessTokenMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UnlockDeviceMessage$Type extends MessageType { + constructor() { + super("UnlockDeviceMessage", []); + } + create(value?: PartialMessage): UnlockDeviceMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UnlockDeviceMessage): UnlockDeviceMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UnlockDeviceMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UnlockDeviceMessage + */ +export const UnlockDeviceMessage = new UnlockDeviceMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeleteUserMessage$Type extends MessageType { + constructor() { + super("DeleteUserMessage", [ + { no: 1, name: "email", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeleteUserMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.email = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeleteUserMessage): DeleteUserMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string email */ 1: + message.email = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeleteUserMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string email = 1; */ + if (message.email !== "") + writer.tag(1, WireType.LengthDelimited).string(message.email); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeleteUserMessage + */ +export const DeleteUserMessage = new DeleteUserMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceOriginGroupMessage$Type extends MessageType { + constructor() { + super("DeviceOriginGroupMessage", [ + { no: 1, name: "signature", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceOriginGroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.signature = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceOriginGroupMessage): DeviceOriginGroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string signature */ 1: + message.signature = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceOriginGroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string signature = 1; */ + if (message.signature !== "") + writer.tag(1, WireType.LengthDelimited).string(message.signature); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceOriginGroupMessage + */ +export const DeviceOriginGroupMessage = new DeviceOriginGroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserQuotasDetailField$Type extends MessageType { + constructor() { + super("UserQuotasDetailField", [ + { no: 1, name: "duration", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 2, name: "number", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): UserQuotasDetailField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.duration = 0; + message.number = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserQuotasDetailField): UserQuotasDetailField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required double duration */ 1: + message.duration = reader.double(); + break; + case /* required uint32 number */ 2: + message.number = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserQuotasDetailField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required double duration = 1; */ + if (message.duration !== 0) + writer.tag(1, WireType.Bit64).double(message.duration); + /* required uint32 number = 2; */ + if (message.number !== 0) + writer.tag(2, WireType.Varint).uint32(message.number); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserQuotasDetailField + */ +export const UserQuotasDetailField = new UserQuotasDetailField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserQuotasField$Type extends MessageType { + constructor() { + super("UserQuotasField", [ + { no: 1, name: "allocated", kind: "message", T: () => UserQuotasDetailField }, + { no: 2, name: "consumed", kind: "message", T: () => UserQuotasDetailField }, + { no: 3, name: "defaultGroupsDuration", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "defaultGroupsNumber", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 5, name: "defaultGroupsRepetitions", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: "repetitions", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): UserQuotasField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.defaultGroupsDuration = 0; + message.defaultGroupsNumber = 0; + message.defaultGroupsRepetitions = 0; + message.repetitions = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserQuotasField): UserQuotasField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required UserQuotasDetailField allocated */ 1: + message.allocated = UserQuotasDetailField.internalBinaryRead(reader, reader.uint32(), options, message.allocated); + break; + case /* required UserQuotasDetailField consumed */ 2: + message.consumed = UserQuotasDetailField.internalBinaryRead(reader, reader.uint32(), options, message.consumed); + break; + case /* required uint32 defaultGroupsDuration */ 3: + message.defaultGroupsDuration = reader.uint32(); + break; + case /* required uint32 defaultGroupsNumber */ 4: + message.defaultGroupsNumber = reader.uint32(); + break; + case /* required uint32 defaultGroupsRepetitions */ 5: + message.defaultGroupsRepetitions = reader.uint32(); + break; + case /* required uint32 repetitions */ 6: + message.repetitions = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserQuotasField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required UserQuotasDetailField allocated = 1; */ + if (message.allocated) + UserQuotasDetailField.internalBinaryWrite(message.allocated, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* required UserQuotasDetailField consumed = 2; */ + if (message.consumed) + UserQuotasDetailField.internalBinaryWrite(message.consumed, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* required uint32 defaultGroupsDuration = 3; */ + if (message.defaultGroupsDuration !== 0) + writer.tag(3, WireType.Varint).uint32(message.defaultGroupsDuration); + /* required uint32 defaultGroupsNumber = 4; */ + if (message.defaultGroupsNumber !== 0) + writer.tag(4, WireType.Varint).uint32(message.defaultGroupsNumber); + /* required uint32 defaultGroupsRepetitions = 5; */ + if (message.defaultGroupsRepetitions !== 0) + writer.tag(5, WireType.Varint).uint32(message.defaultGroupsRepetitions); + /* required uint32 repetitions = 6; */ + if (message.repetitions !== 0) + writer.tag(6, WireType.Varint).uint32(message.repetitions); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserQuotasField + */ +export const UserQuotasField = new UserQuotasField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserGroupsField$Type extends MessageType { + constructor() { + super("UserGroupsField", [ + { no: 1, name: "quotas", kind: "message", T: () => UserQuotasField }, + { no: 2, name: "subscribed", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): UserGroupsField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.subscribed = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserGroupsField): UserGroupsField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required UserQuotasField quotas */ 1: + message.quotas = UserQuotasField.internalBinaryRead(reader, reader.uint32(), options, message.quotas); + break; + case /* repeated string subscribed */ 2: + message.subscribed.push(reader.string()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserGroupsField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required UserQuotasField quotas = 1; */ + if (message.quotas) + UserQuotasField.internalBinaryWrite(message.quotas, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* repeated string subscribed = 2; */ + for (let i = 0; i < message.subscribed.length; i++) + writer.tag(2, WireType.LengthDelimited).string(message.subscribed[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserGroupsField + */ +export const UserGroupsField = new UserGroupsField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AlertMessageField$Type extends MessageType { + constructor() { + super("AlertMessageField", [ + { no: 1, name: "activation", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "data", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "level", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AlertMessageField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.activation = ""; + message.data = ""; + message.level = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AlertMessageField): AlertMessageField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string activation */ 1: + message.activation = reader.string(); + break; + case /* required string data */ 2: + message.data = reader.string(); + break; + case /* required string level */ 3: + message.level = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AlertMessageField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string activation = 1; */ + if (message.activation !== "") + writer.tag(1, WireType.LengthDelimited).string(message.activation); + /* required string data = 2; */ + if (message.data !== "") + writer.tag(2, WireType.LengthDelimited).string(message.data); + /* required string level = 3; */ + if (message.level !== "") + writer.tag(3, WireType.LengthDelimited).string(message.level); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AlertMessageField + */ +export const AlertMessageField = new AlertMessageField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserSettingsField$Type extends MessageType { + constructor() { + super("UserSettingsField", [ + { no: 1, name: "alertMessage", kind: "message", T: () => AlertMessageField } + ]); + } + create(value?: PartialMessage): UserSettingsField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserSettingsField): UserSettingsField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional AlertMessageField alertMessage */ 1: + message.alertMessage = AlertMessageField.internalBinaryRead(reader, reader.uint32(), options, message.alertMessage); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserSettingsField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional AlertMessageField alertMessage = 1; */ + if (message.alertMessage) + AlertMessageField.internalBinaryWrite(message.alertMessage, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserSettingsField + */ +export const UserSettingsField = new UserSettingsField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserField$Type extends MessageType { + constructor() { + super("UserField", [ + { no: 1, name: "email", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "privilege", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "groups", kind: "message", T: () => UserGroupsField }, + { no: 5, name: "settings", kind: "message", T: () => UserSettingsField } + ]); + } + create(value?: PartialMessage): UserField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.email = ""; + message.name = ""; + message.privilege = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserField): UserField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string email */ 1: + message.email = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required string privilege */ 3: + message.privilege = reader.string(); + break; + case /* required UserGroupsField groups */ 4: + message.groups = UserGroupsField.internalBinaryRead(reader, reader.uint32(), options, message.groups); + break; + case /* optional UserSettingsField settings */ 5: + message.settings = UserSettingsField.internalBinaryRead(reader, reader.uint32(), options, message.settings); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string email = 1; */ + if (message.email !== "") + writer.tag(1, WireType.LengthDelimited).string(message.email); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required string privilege = 3; */ + if (message.privilege !== "") + writer.tag(3, WireType.LengthDelimited).string(message.privilege); + /* required UserGroupsField groups = 4; */ + if (message.groups) + UserGroupsField.internalBinaryWrite(message.groups, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* optional UserSettingsField settings = 5; */ + if (message.settings) + UserSettingsField.internalBinaryWrite(message.settings, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserField + */ +export const UserField = new UserField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UserChangeMessage$Type extends MessageType { + constructor() { + super("UserChangeMessage", [ + { no: 1, name: "user", kind: "message", T: () => UserField }, + { no: 2, name: "isAddedGroup", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "groups", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "action", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "targets", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "timeStamp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): UserChangeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.isAddedGroup = false; + message.groups = []; + message.action = ""; + message.targets = []; + message.timeStamp = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UserChangeMessage): UserChangeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required UserField user */ 1: + message.user = UserField.internalBinaryRead(reader, reader.uint32(), options, message.user); + break; + case /* required bool isAddedGroup */ 2: + message.isAddedGroup = reader.bool(); + break; + case /* repeated string groups */ 3: + message.groups.push(reader.string()); + break; + case /* required string action */ 4: + message.action = reader.string(); + break; + case /* repeated string targets */ 5: + message.targets.push(reader.string()); + break; + case /* required double timeStamp */ 6: + message.timeStamp = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UserChangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required UserField user = 1; */ + if (message.user) + UserField.internalBinaryWrite(message.user, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* required bool isAddedGroup = 2; */ + if (message.isAddedGroup !== false) + writer.tag(2, WireType.Varint).bool(message.isAddedGroup); + /* repeated string groups = 3; */ + for (let i = 0; i < message.groups.length; i++) + writer.tag(3, WireType.LengthDelimited).string(message.groups[i]); + /* required string action = 4; */ + if (message.action !== "") + writer.tag(4, WireType.LengthDelimited).string(message.action); + /* repeated string targets = 5; */ + for (let i = 0; i < message.targets.length; i++) + writer.tag(5, WireType.LengthDelimited).string(message.targets[i]); + /* required double timeStamp = 6; */ + if (message.timeStamp !== 0) + writer.tag(6, WireType.Bit64).double(message.timeStamp); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UserChangeMessage + */ +export const UserChangeMessage = new UserChangeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceNetworkField$Type extends MessageType { + constructor() { + super("DeviceNetworkField", [ + { no: 1, name: "type", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "subtype", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceNetworkField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceNetworkField): DeviceNetworkField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string type */ 1: + message.type = reader.string(); + break; + case /* optional string subtype */ 2: + message.subtype = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceNetworkField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string type = 1; */ + if (message.type !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.type); + /* optional string subtype = 2; */ + if (message.subtype !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.subtype); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceNetworkField + */ +export const DeviceNetworkField = new DeviceNetworkField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceDisplayField$Type extends MessageType { + constructor() { + super("DeviceDisplayField", [ + { no: 1, name: "height", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "width", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): DeviceDisplayField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceDisplayField): DeviceDisplayField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional uint32 height */ 1: + message.height = reader.uint32(); + break; + case /* optional uint32 width */ 2: + message.width = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceDisplayField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional uint32 height = 1; */ + if (message.height !== undefined) + writer.tag(1, WireType.Varint).uint32(message.height); + /* optional uint32 width = 2; */ + if (message.width !== undefined) + writer.tag(2, WireType.Varint).uint32(message.width); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceDisplayField + */ +export const DeviceDisplayField = new DeviceDisplayField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DevicePhoneField$Type extends MessageType { + constructor() { + super("DevicePhoneField", [ + { no: 1, name: "imei", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DevicePhoneField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DevicePhoneField): DevicePhoneField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string imei */ 1: + message.imei = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DevicePhoneField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string imei = 1; */ + if (message.imei !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.imei); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DevicePhoneField + */ +export const DevicePhoneField = new DevicePhoneField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceProviderField$Type extends MessageType { + constructor() { + super("DeviceProviderField", [ + { no: 1, name: "name", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceProviderField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceProviderField): DeviceProviderField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string name */ 1: + message.name = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceProviderField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string name = 1; */ + if (message.name !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.name); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceProviderField + */ +export const DeviceProviderField = new DeviceProviderField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGroupField$Type extends MessageType { + constructor() { + super("DeviceGroupField", [ + { no: 1, name: "id", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "origin", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "originName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "owner", kind: "message", T: () => GroupOwnerField } + ]); + } + create(value?: PartialMessage): DeviceGroupField { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGroupField): DeviceGroupField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string id */ 1: + message.id = reader.string(); + break; + case /* optional string name */ 2: + message.name = reader.string(); + break; + case /* optional string origin */ 3: + message.origin = reader.string(); + break; + case /* optional string originName */ 4: + message.originName = reader.string(); + break; + case /* optional GroupOwnerField owner */ 5: + message.owner = GroupOwnerField.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGroupField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string id = 1; */ + if (message.id !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* optional string name = 2; */ + if (message.name !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* optional string origin = 3; */ + if (message.origin !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.origin); + /* optional string originName = 4; */ + if (message.originName !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.originName); + /* optional GroupOwnerField owner = 5; */ + if (message.owner) + GroupOwnerField.internalBinaryWrite(message.owner, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGroupField + */ +export const DeviceGroupField = new DeviceGroupField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceField$Type extends MessageType { + constructor() { + super("DeviceField", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "model", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "version", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "operator", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "network", kind: "message", T: () => DeviceNetworkField }, + { no: 6, name: "display", kind: "message", T: () => DeviceDisplayField }, + { no: 7, name: "manufacturer", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "sdk", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 9, name: "abi", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 10, name: "cpuPlatform", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 11, name: "openGLESVersion", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 12, name: "phone", kind: "message", T: () => DevicePhoneField }, + { no: 13, name: "provider", kind: "message", T: () => DeviceProviderField }, + { no: 14, name: "group", kind: "message", T: () => DeviceGroupField }, + { no: 15, name: "marketName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceField): DeviceField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* optional string model */ 2: + message.model = reader.string(); + break; + case /* optional string version */ 3: + message.version = reader.string(); + break; + case /* optional string operator */ 4: + message.operator = reader.string(); + break; + case /* optional DeviceNetworkField network */ 5: + message.network = DeviceNetworkField.internalBinaryRead(reader, reader.uint32(), options, message.network); + break; + case /* optional DeviceDisplayField display */ 6: + message.display = DeviceDisplayField.internalBinaryRead(reader, reader.uint32(), options, message.display); + break; + case /* optional string manufacturer */ 7: + message.manufacturer = reader.string(); + break; + case /* optional string sdk */ 8: + message.sdk = reader.string(); + break; + case /* optional string abi */ 9: + message.abi = reader.string(); + break; + case /* optional string cpuPlatform */ 10: + message.cpuPlatform = reader.string(); + break; + case /* optional string openGLESVersion */ 11: + message.openGLESVersion = reader.string(); + break; + case /* optional DevicePhoneField phone */ 12: + message.phone = DevicePhoneField.internalBinaryRead(reader, reader.uint32(), options, message.phone); + break; + case /* optional DeviceProviderField provider */ 13: + message.provider = DeviceProviderField.internalBinaryRead(reader, reader.uint32(), options, message.provider); + break; + case /* optional DeviceGroupField group */ 14: + message.group = DeviceGroupField.internalBinaryRead(reader, reader.uint32(), options, message.group); + break; + case /* optional string marketName */ 15: + message.marketName = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* optional string model = 2; */ + if (message.model !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.model); + /* optional string version = 3; */ + if (message.version !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.version); + /* optional string operator = 4; */ + if (message.operator !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.operator); + /* optional DeviceNetworkField network = 5; */ + if (message.network) + DeviceNetworkField.internalBinaryWrite(message.network, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* optional DeviceDisplayField display = 6; */ + if (message.display) + DeviceDisplayField.internalBinaryWrite(message.display, writer.tag(6, WireType.LengthDelimited).fork(), options).join(); + /* optional string manufacturer = 7; */ + if (message.manufacturer !== undefined) + writer.tag(7, WireType.LengthDelimited).string(message.manufacturer); + /* optional string sdk = 8; */ + if (message.sdk !== undefined) + writer.tag(8, WireType.LengthDelimited).string(message.sdk); + /* optional string abi = 9; */ + if (message.abi !== undefined) + writer.tag(9, WireType.LengthDelimited).string(message.abi); + /* optional string cpuPlatform = 10; */ + if (message.cpuPlatform !== undefined) + writer.tag(10, WireType.LengthDelimited).string(message.cpuPlatform); + /* optional string openGLESVersion = 11; */ + if (message.openGLESVersion !== undefined) + writer.tag(11, WireType.LengthDelimited).string(message.openGLESVersion); + /* optional DevicePhoneField phone = 12; */ + if (message.phone) + DevicePhoneField.internalBinaryWrite(message.phone, writer.tag(12, WireType.LengthDelimited).fork(), options).join(); + /* optional DeviceProviderField provider = 13; */ + if (message.provider) + DeviceProviderField.internalBinaryWrite(message.provider, writer.tag(13, WireType.LengthDelimited).fork(), options).join(); + /* optional DeviceGroupField group = 14; */ + if (message.group) + DeviceGroupField.internalBinaryWrite(message.group, writer.tag(14, WireType.LengthDelimited).fork(), options).join(); + /* optional string marketName = 15; */ + if (message.marketName !== undefined) + writer.tag(15, WireType.LengthDelimited).string(message.marketName); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceField + */ +export const DeviceField = new DeviceField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceChangeMessage$Type extends MessageType { + constructor() { + super("DeviceChangeMessage", [ + { no: 1, name: "device", kind: "message", T: () => DeviceField }, + { no: 2, name: "action", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "oldOriginGroupId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "timeStamp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): DeviceChangeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.action = ""; + message.oldOriginGroupId = ""; + message.timeStamp = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceChangeMessage): DeviceChangeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required DeviceField device */ 1: + message.device = DeviceField.internalBinaryRead(reader, reader.uint32(), options, message.device); + break; + case /* required string action */ 2: + message.action = reader.string(); + break; + case /* required string oldOriginGroupId */ 3: + message.oldOriginGroupId = reader.string(); + break; + case /* required double timeStamp */ 4: + message.timeStamp = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceChangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required DeviceField device = 1; */ + if (message.device) + DeviceField.internalBinaryWrite(message.device, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* required string action = 2; */ + if (message.action !== "") + writer.tag(2, WireType.LengthDelimited).string(message.action); + /* required string oldOriginGroupId = 3; */ + if (message.oldOriginGroupId !== "") + writer.tag(3, WireType.LengthDelimited).string(message.oldOriginGroupId); + /* required double timeStamp = 4; */ + if (message.timeStamp !== 0) + writer.tag(4, WireType.Bit64).double(message.timeStamp); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceChangeMessage + */ +export const DeviceChangeMessage = new DeviceChangeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupDateField$Type extends MessageType { + constructor() { + super("GroupDateField", [ + { no: 1, name: "start", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "stop", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GroupDateField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.start = ""; + message.stop = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupDateField): GroupDateField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string start */ 1: + message.start = reader.string(); + break; + case /* required string stop */ 2: + message.stop = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupDateField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string start = 1; */ + if (message.start !== "") + writer.tag(1, WireType.LengthDelimited).string(message.start); + /* required string stop = 2; */ + if (message.stop !== "") + writer.tag(2, WireType.LengthDelimited).string(message.stop); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupDateField + */ +export const GroupDateField = new GroupDateField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupOwnerField$Type extends MessageType { + constructor() { + super("GroupOwnerField", [ + { no: 1, name: "email", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GroupOwnerField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.email = ""; + message.name = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupOwnerField): GroupOwnerField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string email */ 1: + message.email = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupOwnerField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string email = 1; */ + if (message.email !== "") + writer.tag(1, WireType.LengthDelimited).string(message.email); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupOwnerField + */ +export const GroupOwnerField = new GroupOwnerField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupField$Type extends MessageType { + constructor() { + super("GroupField", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "class", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "privilege", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "owner", kind: "message", T: () => GroupOwnerField }, + { no: 6, name: "dates", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => GroupDateField }, + { no: 7, name: "duration", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 8, name: "repetitions", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 9, name: "devices", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 10, name: "users", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 11, name: "state", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 12, name: "isActive", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 13, name: "moderators", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GroupField { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.name = ""; + message.class = ""; + message.privilege = ""; + message.dates = []; + message.duration = 0; + message.repetitions = 0; + message.devices = []; + message.users = []; + message.state = ""; + message.isActive = false; + message.moderators = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupField): GroupField { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required string class */ 3: + message.class = reader.string(); + break; + case /* required string privilege */ 4: + message.privilege = reader.string(); + break; + case /* required GroupOwnerField owner */ 5: + message.owner = GroupOwnerField.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* repeated GroupDateField dates */ 6: + message.dates.push(GroupDateField.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* required uint32 duration */ 7: + message.duration = reader.uint32(); + break; + case /* required uint32 repetitions */ 8: + message.repetitions = reader.uint32(); + break; + case /* repeated string devices */ 9: + message.devices.push(reader.string()); + break; + case /* repeated string users */ 10: + message.users.push(reader.string()); + break; + case /* required string state */ 11: + message.state = reader.string(); + break; + case /* required bool isActive */ 12: + message.isActive = reader.bool(); + break; + case /* repeated string moderators */ 13: + message.moderators.push(reader.string()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupField, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required string class = 3; */ + if (message.class !== "") + writer.tag(3, WireType.LengthDelimited).string(message.class); + /* required string privilege = 4; */ + if (message.privilege !== "") + writer.tag(4, WireType.LengthDelimited).string(message.privilege); + /* required GroupOwnerField owner = 5; */ + if (message.owner) + GroupOwnerField.internalBinaryWrite(message.owner, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* repeated GroupDateField dates = 6; */ + for (let i = 0; i < message.dates.length; i++) + GroupDateField.internalBinaryWrite(message.dates[i], writer.tag(6, WireType.LengthDelimited).fork(), options).join(); + /* required uint32 duration = 7; */ + if (message.duration !== 0) + writer.tag(7, WireType.Varint).uint32(message.duration); + /* required uint32 repetitions = 8; */ + if (message.repetitions !== 0) + writer.tag(8, WireType.Varint).uint32(message.repetitions); + /* repeated string devices = 9; */ + for (let i = 0; i < message.devices.length; i++) + writer.tag(9, WireType.LengthDelimited).string(message.devices[i]); + /* repeated string users = 10; */ + for (let i = 0; i < message.users.length; i++) + writer.tag(10, WireType.LengthDelimited).string(message.users[i]); + /* required string state = 11; */ + if (message.state !== "") + writer.tag(11, WireType.LengthDelimited).string(message.state); + /* required bool isActive = 12; */ + if (message.isActive !== false) + writer.tag(12, WireType.Varint).bool(message.isActive); + /* repeated string moderators = 13; */ + for (let i = 0; i < message.moderators.length; i++) + writer.tag(13, WireType.LengthDelimited).string(message.moderators[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupField + */ +export const GroupField = new GroupField$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupChangeMessage$Type extends MessageType { + constructor() { + super("GroupChangeMessage", [ + { no: 1, name: "group", kind: "message", T: () => GroupField }, + { no: 2, name: "action", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "subscribers", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "isChangedDates", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 5, name: "isChangedClass", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 6, name: "isAddedUser", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 7, name: "users", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "isAddedDevice", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 9, name: "devices", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 10, name: "timeStamp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): GroupChangeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.action = ""; + message.subscribers = []; + message.isChangedDates = false; + message.isChangedClass = false; + message.isAddedUser = false; + message.users = []; + message.isAddedDevice = false; + message.devices = []; + message.timeStamp = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupChangeMessage): GroupChangeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required GroupField group */ 1: + message.group = GroupField.internalBinaryRead(reader, reader.uint32(), options, message.group); + break; + case /* required string action */ 2: + message.action = reader.string(); + break; + case /* repeated string subscribers */ 3: + message.subscribers.push(reader.string()); + break; + case /* required bool isChangedDates */ 4: + message.isChangedDates = reader.bool(); + break; + case /* required bool isChangedClass */ 5: + message.isChangedClass = reader.bool(); + break; + case /* required bool isAddedUser */ 6: + message.isAddedUser = reader.bool(); + break; + case /* repeated string users */ 7: + message.users.push(reader.string()); + break; + case /* required bool isAddedDevice */ 8: + message.isAddedDevice = reader.bool(); + break; + case /* repeated string devices */ 9: + message.devices.push(reader.string()); + break; + case /* required double timeStamp */ 10: + message.timeStamp = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupChangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required GroupField group = 1; */ + if (message.group) + GroupField.internalBinaryWrite(message.group, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* required string action = 2; */ + if (message.action !== "") + writer.tag(2, WireType.LengthDelimited).string(message.action); + /* repeated string subscribers = 3; */ + for (let i = 0; i < message.subscribers.length; i++) + writer.tag(3, WireType.LengthDelimited).string(message.subscribers[i]); + /* required bool isChangedDates = 4; */ + if (message.isChangedDates !== false) + writer.tag(4, WireType.Varint).bool(message.isChangedDates); + /* required bool isChangedClass = 5; */ + if (message.isChangedClass !== false) + writer.tag(5, WireType.Varint).bool(message.isChangedClass); + /* required bool isAddedUser = 6; */ + if (message.isAddedUser !== false) + writer.tag(6, WireType.Varint).bool(message.isAddedUser); + /* repeated string users = 7; */ + for (let i = 0; i < message.users.length; i++) + writer.tag(7, WireType.LengthDelimited).string(message.users[i]); + /* required bool isAddedDevice = 8; */ + if (message.isAddedDevice !== false) + writer.tag(8, WireType.Varint).bool(message.isAddedDevice); + /* repeated string devices = 9; */ + for (let i = 0; i < message.devices.length; i++) + writer.tag(9, WireType.LengthDelimited).string(message.devices[i]); + /* required double timeStamp = 10; */ + if (message.timeStamp !== 0) + writer.tag(10, WireType.Bit64).double(message.timeStamp); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupChangeMessage + */ +export const GroupChangeMessage = new GroupChangeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGroupChangeMessage$Type extends MessageType { + constructor() { + super("DeviceGroupChangeMessage", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "group", kind: "message", T: () => DeviceGroupMessage }, + { no: 3, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceGroupChangeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGroupChangeMessage): DeviceGroupChangeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required DeviceGroupMessage group */ 2: + message.group = DeviceGroupMessage.internalBinaryRead(reader, reader.uint32(), options, message.group); + break; + case /* required string serial */ 3: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGroupChangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required DeviceGroupMessage group = 2; */ + if (message.group) + DeviceGroupMessage.internalBinaryWrite(message.group, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* required string serial = 3; */ + if (message.serial !== "") + writer.tag(3, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGroupChangeMessage + */ +export const DeviceGroupChangeMessage = new DeviceGroupChangeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupUserChangeMessage$Type extends MessageType { + constructor() { + super("GroupUserChangeMessage", [ + { no: 1, name: "users", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "isAdded", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "isDeletedLater", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 5, name: "devices", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GroupUserChangeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.users = []; + message.isAdded = false; + message.id = ""; + message.isDeletedLater = false; + message.devices = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupUserChangeMessage): GroupUserChangeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated string users */ 1: + message.users.push(reader.string()); + break; + case /* required bool isAdded */ 2: + message.isAdded = reader.bool(); + break; + case /* required string id */ 3: + message.id = reader.string(); + break; + case /* required bool isDeletedLater */ 4: + message.isDeletedLater = reader.bool(); + break; + case /* repeated string devices */ 5: + message.devices.push(reader.string()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupUserChangeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated string users = 1; */ + for (let i = 0; i < message.users.length; i++) + writer.tag(1, WireType.LengthDelimited).string(message.users[i]); + /* required bool isAdded = 2; */ + if (message.isAdded !== false) + writer.tag(2, WireType.Varint).bool(message.isAdded); + /* required string id = 3; */ + if (message.id !== "") + writer.tag(3, WireType.LengthDelimited).string(message.id); + /* required bool isDeletedLater = 4; */ + if (message.isDeletedLater !== false) + writer.tag(4, WireType.Varint).bool(message.isDeletedLater); + /* repeated string devices = 5; */ + for (let i = 0; i < message.devices.length; i++) + writer.tag(5, WireType.LengthDelimited).string(message.devices[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupUserChangeMessage + */ +export const GroupUserChangeMessage = new GroupUserChangeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectStartedMessage$Type extends MessageType { + constructor() { + super("ConnectStartedMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "url", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ConnectStartedMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.url = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectStartedMessage): ConnectStartedMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string url */ 2: + message.url = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectStartedMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string url = 2; */ + if (message.url !== "") + writer.tag(2, WireType.LengthDelimited).string(message.url); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectStartedMessage + */ +export const ConnectStartedMessage = new ConnectStartedMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InstallResultMessage$Type extends MessageType { + constructor() { + super("InstallResultMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "result", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): InstallResultMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.result = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InstallResultMessage): InstallResultMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string result */ 2: + message.result = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InstallResultMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string result = 2; */ + if (message.result !== "") + writer.tag(2, WireType.LengthDelimited).string(message.result); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message InstallResultMessage + */ +export const InstallResultMessage = new InstallResultMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectStoppedMessage$Type extends MessageType { + constructor() { + super("ConnectStoppedMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ConnectStoppedMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectStoppedMessage): ConnectStoppedMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectStoppedMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectStoppedMessage + */ +export const ConnectStoppedMessage = new ConnectStoppedMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FileSystemListMessage$Type extends MessageType { + constructor() { + super("FileSystemListMessage", [ + { no: 1, name: "dir", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): FileSystemListMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.dir = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FileSystemListMessage): FileSystemListMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string dir */ 1: + message.dir = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: FileSystemListMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string dir = 1; */ + if (message.dir !== "") + writer.tag(1, WireType.LengthDelimited).string(message.dir); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message FileSystemListMessage + */ +export const FileSystemListMessage = new FileSystemListMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FileSystemGetMessage$Type extends MessageType { + constructor() { + super("FileSystemGetMessage", [ + { no: 1, name: "file", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "jwt", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): FileSystemGetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.file = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FileSystemGetMessage): FileSystemGetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string file */ 1: + message.file = reader.string(); + break; + case /* optional string jwt */ 2: + message.jwt = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: FileSystemGetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string file = 1; */ + if (message.file !== "") + writer.tag(1, WireType.LengthDelimited).string(message.file); + /* optional string jwt = 2; */ + if (message.jwt !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.jwt); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message FileSystemGetMessage + */ +export const FileSystemGetMessage = new FileSystemGetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TransactionProgressMessage$Type extends MessageType { + constructor() { + super("TransactionProgressMessage", [ + { no: 1, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "data", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "progress", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): TransactionProgressMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.source = ""; + message.seq = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TransactionProgressMessage): TransactionProgressMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string source */ 1: + message.source = reader.string(); + break; + case /* required uint32 seq */ 2: + message.seq = reader.uint32(); + break; + case /* optional string data */ 3: + message.data = reader.string(); + break; + case /* optional uint32 progress = 4 [default = 0] */ 4: + message.progress = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TransactionProgressMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string source = 1; */ + if (message.source !== "") + writer.tag(1, WireType.LengthDelimited).string(message.source); + /* required uint32 seq = 2; */ + if (message.seq !== 0) + writer.tag(2, WireType.Varint).uint32(message.seq); + /* optional string data = 3; */ + if (message.data !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.data); + /* optional uint32 progress = 4 [default = 0]; */ + if (message.progress !== undefined) + writer.tag(4, WireType.Varint).uint32(message.progress); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TransactionProgressMessage + */ +export const TransactionProgressMessage = new TransactionProgressMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TransactionDoneMessage$Type extends MessageType { + constructor() { + super("TransactionDoneMessage", [ + { no: 1, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "success", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "data", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "body", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TransactionDoneMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.source = ""; + message.seq = 0; + message.success = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TransactionDoneMessage): TransactionDoneMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string source */ 1: + message.source = reader.string(); + break; + case /* required uint32 seq */ 2: + message.seq = reader.uint32(); + break; + case /* required bool success */ 3: + message.success = reader.bool(); + break; + case /* optional string data */ 4: + message.data = reader.string(); + break; + case /* optional string body */ 5: + message.body = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TransactionDoneMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string source = 1; */ + if (message.source !== "") + writer.tag(1, WireType.LengthDelimited).string(message.source); + /* required uint32 seq = 2; */ + if (message.seq !== 0) + writer.tag(2, WireType.Varint).uint32(message.seq); + /* required bool success = 3; */ + if (message.success !== false) + writer.tag(3, WireType.Varint).bool(message.success); + /* optional string data = 4; */ + if (message.data !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.data); + /* optional string body = 5; */ + if (message.body !== undefined) + writer.tag(5, WireType.LengthDelimited).string(message.body); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TransactionDoneMessage + */ +export const TransactionDoneMessage = new TransactionDoneMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TransactionTreeMessage$Type extends MessageType { + constructor() { + super("TransactionTreeMessage", [ + { no: 1, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "success", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "data", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "body", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TransactionTreeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.source = ""; + message.seq = 0; + message.success = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TransactionTreeMessage): TransactionTreeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string source */ 1: + message.source = reader.string(); + break; + case /* required uint32 seq */ 2: + message.seq = reader.uint32(); + break; + case /* required bool success */ 3: + message.success = reader.bool(); + break; + case /* optional string data */ 4: + message.data = reader.string(); + break; + case /* optional string body */ 5: + message.body = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TransactionTreeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string source = 1; */ + if (message.source !== "") + writer.tag(1, WireType.LengthDelimited).string(message.source); + /* required uint32 seq = 2; */ + if (message.seq !== 0) + writer.tag(2, WireType.Varint).uint32(message.seq); + /* required bool success = 3; */ + if (message.success !== false) + writer.tag(3, WireType.Varint).bool(message.success); + /* optional string data = 4; */ + if (message.data !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.data); + /* optional string body = 5; */ + if (message.body !== undefined) + writer.tag(5, WireType.LengthDelimited).string(message.body); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TransactionTreeMessage + */ +export const TransactionTreeMessage = new TransactionTreeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceLogMessage$Type extends MessageType { + constructor() { + super("DeviceLogMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "timestamp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 3, name: "priority", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "tag", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "pid", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "identifier", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceLogMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.timestamp = 0; + message.priority = 0; + message.tag = ""; + message.pid = 0; + message.message = ""; + message.identifier = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceLogMessage): DeviceLogMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required double timestamp */ 2: + message.timestamp = reader.double(); + break; + case /* required uint32 priority */ 3: + message.priority = reader.uint32(); + break; + case /* required string tag */ 4: + message.tag = reader.string(); + break; + case /* required uint32 pid */ 5: + message.pid = reader.uint32(); + break; + case /* required string message */ 6: + message.message = reader.string(); + break; + case /* required string identifier */ 7: + message.identifier = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceLogMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required double timestamp = 2; */ + if (message.timestamp !== 0) + writer.tag(2, WireType.Bit64).double(message.timestamp); + /* required uint32 priority = 3; */ + if (message.priority !== 0) + writer.tag(3, WireType.Varint).uint32(message.priority); + /* required string tag = 4; */ + if (message.tag !== "") + writer.tag(4, WireType.LengthDelimited).string(message.tag); + /* required uint32 pid = 5; */ + if (message.pid !== 0) + writer.tag(5, WireType.Varint).uint32(message.pid); + /* required string message = 6; */ + if (message.message !== "") + writer.tag(6, WireType.LengthDelimited).string(message.message); + /* required string identifier = 7; */ + if (message.identifier !== "") + writer.tag(7, WireType.LengthDelimited).string(message.identifier); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceLogMessage + */ +export const DeviceLogMessage = new DeviceLogMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGroupOwnerMessage$Type extends MessageType { + constructor() { + super("DeviceGroupOwnerMessage", [ + { no: 1, name: "email", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceGroupOwnerMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.email = ""; + message.name = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGroupOwnerMessage): DeviceGroupOwnerMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string email */ 1: + message.email = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGroupOwnerMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string email = 1; */ + if (message.email !== "") + writer.tag(1, WireType.LengthDelimited).string(message.email); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGroupOwnerMessage + */ +export const DeviceGroupOwnerMessage = new DeviceGroupOwnerMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGroupLifetimeMessage$Type extends MessageType { + constructor() { + super("DeviceGroupLifetimeMessage", [ + { no: 1, name: "start", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 2, name: "stop", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): DeviceGroupLifetimeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.start = 0; + message.stop = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGroupLifetimeMessage): DeviceGroupLifetimeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required double start */ 1: + message.start = reader.double(); + break; + case /* required double stop */ 2: + message.stop = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGroupLifetimeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required double start = 1; */ + if (message.start !== 0) + writer.tag(1, WireType.Bit64).double(message.start); + /* required double stop = 2; */ + if (message.stop !== 0) + writer.tag(2, WireType.Bit64).double(message.stop); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGroupLifetimeMessage + */ +export const DeviceGroupLifetimeMessage = new DeviceGroupLifetimeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGroupMessage$Type extends MessageType { + constructor() { + super("DeviceGroupMessage", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "owner", kind: "message", T: () => DeviceGroupOwnerMessage }, + { no: 4, name: "lifeTime", kind: "message", T: () => DeviceGroupLifetimeMessage }, + { no: 5, name: "class", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "repetitions", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 7, name: "originName", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceGroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.name = ""; + message.class = ""; + message.repetitions = 0; + message.originName = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGroupMessage): DeviceGroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required DeviceGroupOwnerMessage owner */ 3: + message.owner = DeviceGroupOwnerMessage.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* required DeviceGroupLifetimeMessage lifeTime */ 4: + message.lifeTime = DeviceGroupLifetimeMessage.internalBinaryRead(reader, reader.uint32(), options, message.lifeTime); + break; + case /* required string class */ 5: + message.class = reader.string(); + break; + case /* required uint32 repetitions */ 6: + message.repetitions = reader.uint32(); + break; + case /* required string originName */ 7: + message.originName = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required DeviceGroupOwnerMessage owner = 3; */ + if (message.owner) + DeviceGroupOwnerMessage.internalBinaryWrite(message.owner, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* required DeviceGroupLifetimeMessage lifeTime = 4; */ + if (message.lifeTime) + DeviceGroupLifetimeMessage.internalBinaryWrite(message.lifeTime, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* required string class = 5; */ + if (message.class !== "") + writer.tag(5, WireType.LengthDelimited).string(message.class); + /* required uint32 repetitions = 6; */ + if (message.repetitions !== 0) + writer.tag(6, WireType.Varint).uint32(message.repetitions); + /* required string originName = 7; */ + if (message.originName !== "") + writer.tag(7, WireType.LengthDelimited).string(message.originName); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGroupMessage + */ +export const DeviceGroupMessage = new DeviceGroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ProviderMessage$Type extends MessageType { + constructor() { + super("ProviderMessage", [ + { no: 1, name: "channel", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ProviderMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.channel = ""; + message.name = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ProviderMessage): ProviderMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string channel */ 1: + message.channel = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ProviderMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string channel = 1; */ + if (message.channel !== "") + writer.tag(1, WireType.LengthDelimited).string(message.channel); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ProviderMessage + */ +export const ProviderMessage = new ProviderMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ProviderIosMessage$Type extends MessageType { + constructor() { + super("ProviderIosMessage", [ + { no: 1, name: "channel", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "screenWsUrlPattern", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ProviderIosMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.channel = ""; + message.name = ""; + message.screenWsUrlPattern = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ProviderIosMessage): ProviderIosMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string channel */ 1: + message.channel = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required string screenWsUrlPattern */ 3: + message.screenWsUrlPattern = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ProviderIosMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string channel = 1; */ + if (message.channel !== "") + writer.tag(1, WireType.LengthDelimited).string(message.channel); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required string screenWsUrlPattern = 3; */ + if (message.screenWsUrlPattern !== "") + writer.tag(3, WireType.LengthDelimited).string(message.screenWsUrlPattern); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ProviderIosMessage + */ +export const ProviderIosMessage = new ProviderIosMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceHeartbeatMessage$Type extends MessageType { + constructor() { + super("DeviceHeartbeatMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceHeartbeatMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceHeartbeatMessage): DeviceHeartbeatMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceHeartbeatMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceHeartbeatMessage + */ +export const DeviceHeartbeatMessage = new DeviceHeartbeatMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceIntroductionMessage$Type extends MessageType { + constructor() { + super("DeviceIntroductionMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "enum", T: () => ["DeviceStatus", DeviceStatus] }, + { no: 3, name: "provider", kind: "message", T: () => ProviderMessage }, + { no: 4, name: "deviceType", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceIntroductionMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.status = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceIntroductionMessage): DeviceIntroductionMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required DeviceStatus status */ 2: + message.status = reader.int32(); + break; + case /* required ProviderMessage provider */ 3: + message.provider = ProviderMessage.internalBinaryRead(reader, reader.uint32(), options, message.provider); + break; + case /* optional string deviceType */ 4: + message.deviceType = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceIntroductionMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required DeviceStatus status = 2; */ + if (message.status !== 0) + writer.tag(2, WireType.Varint).int32(message.status); + /* required ProviderMessage provider = 3; */ + if (message.provider) + ProviderMessage.internalBinaryWrite(message.provider, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* optional string deviceType = 4; */ + if (message.deviceType !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.deviceType); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceIntroductionMessage + */ +export const DeviceIntroductionMessage = new DeviceIntroductionMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceIosIntroductionMessage$Type extends MessageType { + constructor() { + super("DeviceIosIntroductionMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "enum", T: () => ["DeviceStatus", DeviceStatus] }, + { no: 3, name: "provider", kind: "message", T: () => ProviderMessage } + ]); + } + create(value?: PartialMessage): DeviceIosIntroductionMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.status = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceIosIntroductionMessage): DeviceIosIntroductionMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required DeviceStatus status */ 2: + message.status = reader.int32(); + break; + case /* required ProviderMessage provider */ 3: + message.provider = ProviderMessage.internalBinaryRead(reader, reader.uint32(), options, message.provider); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceIosIntroductionMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required DeviceStatus status = 2; */ + if (message.status !== 0) + writer.tag(2, WireType.Varint).int32(message.status); + /* required ProviderMessage provider = 3; */ + if (message.provider) + ProviderMessage.internalBinaryWrite(message.provider, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceIosIntroductionMessage + */ +export const DeviceIosIntroductionMessage = new DeviceIosIntroductionMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InitializeIosDeviceState$Type extends MessageType { + constructor() { + super("InitializeIosDeviceState", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "enum", T: () => ["DeviceStatus", DeviceStatus] }, + { no: 3, name: "provider", kind: "message", T: () => ProviderIosMessage }, + { no: 4, name: "ports", kind: "message", T: () => IosDevicePorts }, + { no: 5, name: "options", kind: "message", T: () => UpdateIosDevice } + ]); + } + create(value?: PartialMessage): InitializeIosDeviceState { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.status = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InitializeIosDeviceState): InitializeIosDeviceState { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required DeviceStatus status */ 2: + message.status = reader.int32(); + break; + case /* required ProviderIosMessage provider */ 3: + message.provider = ProviderIosMessage.internalBinaryRead(reader, reader.uint32(), options, message.provider); + break; + case /* required IosDevicePorts ports */ 4: + message.ports = IosDevicePorts.internalBinaryRead(reader, reader.uint32(), options, message.ports); + break; + case /* required UpdateIosDevice options */ 5: + message.options = UpdateIosDevice.internalBinaryRead(reader, reader.uint32(), options, message.options); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InitializeIosDeviceState, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required DeviceStatus status = 2; */ + if (message.status !== 0) + writer.tag(2, WireType.Varint).int32(message.status); + /* required ProviderIosMessage provider = 3; */ + if (message.provider) + ProviderIosMessage.internalBinaryWrite(message.provider, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* required IosDevicePorts ports = 4; */ + if (message.ports) + IosDevicePorts.internalBinaryWrite(message.ports, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* required UpdateIosDevice options = 5; */ + if (message.options) + UpdateIosDevice.internalBinaryWrite(message.options, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message InitializeIosDeviceState + */ +export const InitializeIosDeviceState = new InitializeIosDeviceState$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceRegisteredMessage$Type extends MessageType { + constructor() { + super("DeviceRegisteredMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceRegisteredMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceRegisteredMessage): DeviceRegisteredMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceRegisteredMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceRegisteredMessage + */ +export const DeviceRegisteredMessage = new DeviceRegisteredMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DevicePresentMessage$Type extends MessageType { + constructor() { + super("DevicePresentMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DevicePresentMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DevicePresentMessage): DevicePresentMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DevicePresentMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DevicePresentMessage + */ +export const DevicePresentMessage = new DevicePresentMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceAbsentMessage$Type extends MessageType { + constructor() { + super("DeviceAbsentMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceAbsentMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceAbsentMessage): DeviceAbsentMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceAbsentMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceAbsentMessage + */ +export const DeviceAbsentMessage = new DeviceAbsentMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceReadyMessage$Type extends MessageType { + constructor() { + super("DeviceReadyMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "channel", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceReadyMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.channel = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceReadyMessage): DeviceReadyMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string channel */ 2: + message.channel = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceReadyMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string channel = 2; */ + if (message.channel !== "") + writer.tag(2, WireType.LengthDelimited).string(message.channel); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceReadyMessage + */ +export const DeviceReadyMessage = new DeviceReadyMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ProbeMessage$Type extends MessageType { + constructor() { + super("ProbeMessage", []); + } + create(value?: PartialMessage): ProbeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ProbeMessage): ProbeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ProbeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ProbeMessage + */ +export const ProbeMessage = new ProbeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceStatusMessage$Type extends MessageType { + constructor() { + super("DeviceStatusMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "enum", T: () => ["DeviceStatus", DeviceStatus] } + ]); + } + create(value?: PartialMessage): DeviceStatusMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.status = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceStatusMessage): DeviceStatusMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required DeviceStatus status */ 2: + message.status = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceStatusMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required DeviceStatus status = 2; */ + if (message.status !== 0) + writer.tag(2, WireType.Varint).int32(message.status); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceStatusMessage + */ +export const DeviceStatusMessage = new DeviceStatusMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceTypeMessage$Type extends MessageType { + constructor() { + super("DeviceTypeMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "type", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceTypeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.type = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceTypeMessage): DeviceTypeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string type */ 2: + message.type = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceTypeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string type = 2; */ + if (message.type !== "") + writer.tag(2, WireType.LengthDelimited).string(message.type); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceTypeMessage + */ +export const DeviceTypeMessage = new DeviceTypeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceDisplayMessage$Type extends MessageType { + constructor() { + super("DeviceDisplayMessage", [ + { no: 1, name: "id", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 2, name: "width", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 3, name: "height", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 4, name: "rotation", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 5, name: "xdpi", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 6, name: "ydpi", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 7, name: "fps", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 8, name: "density", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 9, name: "secure", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 10, name: "url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 11, name: "size", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ } + ]); + } + create(value?: PartialMessage): DeviceDisplayMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = 0; + message.width = 0; + message.height = 0; + message.rotation = 0; + message.xdpi = 0; + message.ydpi = 0; + message.fps = 0; + message.density = 0; + message.secure = false; + message.url = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceDisplayMessage): DeviceDisplayMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required int32 id */ 1: + message.id = reader.int32(); + break; + case /* required int32 width */ 2: + message.width = reader.int32(); + break; + case /* required int32 height */ 3: + message.height = reader.int32(); + break; + case /* required int32 rotation */ 4: + message.rotation = reader.int32(); + break; + case /* required float xdpi */ 5: + message.xdpi = reader.float(); + break; + case /* required float ydpi */ 6: + message.ydpi = reader.float(); + break; + case /* required float fps */ 7: + message.fps = reader.float(); + break; + case /* required float density */ 8: + message.density = reader.float(); + break; + case /* required bool secure */ 9: + message.secure = reader.bool(); + break; + case /* required string url */ 10: + message.url = reader.string(); + break; + case /* optional float size */ 11: + message.size = reader.float(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceDisplayMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required int32 id = 1; */ + if (message.id !== 0) + writer.tag(1, WireType.Varint).int32(message.id); + /* required int32 width = 2; */ + if (message.width !== 0) + writer.tag(2, WireType.Varint).int32(message.width); + /* required int32 height = 3; */ + if (message.height !== 0) + writer.tag(3, WireType.Varint).int32(message.height); + /* required int32 rotation = 4; */ + if (message.rotation !== 0) + writer.tag(4, WireType.Varint).int32(message.rotation); + /* required float xdpi = 5; */ + if (message.xdpi !== 0) + writer.tag(5, WireType.Bit32).float(message.xdpi); + /* required float ydpi = 6; */ + if (message.ydpi !== 0) + writer.tag(6, WireType.Bit32).float(message.ydpi); + /* required float fps = 7; */ + if (message.fps !== 0) + writer.tag(7, WireType.Bit32).float(message.fps); + /* required float density = 8; */ + if (message.density !== 0) + writer.tag(8, WireType.Bit32).float(message.density); + /* required bool secure = 9; */ + if (message.secure !== false) + writer.tag(9, WireType.Varint).bool(message.secure); + /* required string url = 10; */ + if (message.url !== "") + writer.tag(10, WireType.LengthDelimited).string(message.url); + /* optional float size = 11; */ + if (message.size !== undefined) + writer.tag(11, WireType.Bit32).float(message.size); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceDisplayMessage + */ +export const DeviceDisplayMessage = new DeviceDisplayMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceBrowserAppMessage$Type extends MessageType { + constructor() { + super("DeviceBrowserAppMessage", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "selected", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 5, name: "system", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): DeviceBrowserAppMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.type = ""; + message.name = ""; + message.selected = false; + message.system = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceBrowserAppMessage): DeviceBrowserAppMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required string type */ 2: + message.type = reader.string(); + break; + case /* required string name */ 3: + message.name = reader.string(); + break; + case /* required bool selected */ 4: + message.selected = reader.bool(); + break; + case /* required bool system */ 5: + message.system = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceBrowserAppMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required string type = 2; */ + if (message.type !== "") + writer.tag(2, WireType.LengthDelimited).string(message.type); + /* required string name = 3; */ + if (message.name !== "") + writer.tag(3, WireType.LengthDelimited).string(message.name); + /* required bool selected = 4; */ + if (message.selected !== false) + writer.tag(4, WireType.Varint).bool(message.selected); + /* required bool system = 5; */ + if (message.system !== false) + writer.tag(5, WireType.Varint).bool(message.system); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceBrowserAppMessage + */ +export const DeviceBrowserAppMessage = new DeviceBrowserAppMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceBrowserMessage$Type extends MessageType { + constructor() { + super("DeviceBrowserMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "selected", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "apps", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DeviceBrowserAppMessage } + ]); + } + create(value?: PartialMessage): DeviceBrowserMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.selected = false; + message.apps = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceBrowserMessage): DeviceBrowserMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required bool selected */ 2: + message.selected = reader.bool(); + break; + case /* repeated DeviceBrowserAppMessage apps */ 3: + message.apps.push(DeviceBrowserAppMessage.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceBrowserMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required bool selected = 2; */ + if (message.selected !== false) + writer.tag(2, WireType.Varint).bool(message.selected); + /* repeated DeviceBrowserAppMessage apps = 3; */ + for (let i = 0; i < message.apps.length; i++) + DeviceBrowserAppMessage.internalBinaryWrite(message.apps[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceBrowserMessage + */ +export const DeviceBrowserMessage = new DeviceBrowserMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetServicesAvailabilityMessage$Type extends MessageType { + constructor() { + super("GetServicesAvailabilityMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "hasGMS", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "hasHMS", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): GetServicesAvailabilityMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.hasGMS = false; + message.hasHMS = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetServicesAvailabilityMessage): GetServicesAvailabilityMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required bool hasGMS */ 2: + message.hasGMS = reader.bool(); + break; + case /* required bool hasHMS */ 3: + message.hasHMS = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetServicesAvailabilityMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required bool hasGMS = 2; */ + if (message.hasGMS !== false) + writer.tag(2, WireType.Varint).bool(message.hasGMS); + /* required bool hasHMS = 3; */ + if (message.hasHMS !== false) + writer.tag(3, WireType.Varint).bool(message.hasHMS); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetServicesAvailabilityMessage + */ +export const GetServicesAvailabilityMessage = new GetServicesAvailabilityMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DevicePhoneMessage$Type extends MessageType { + constructor() { + super("DevicePhoneMessage", [ + { no: 1, name: "imei", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "imsi", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "phoneNumber", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "iccid", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "network", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DevicePhoneMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DevicePhoneMessage): DevicePhoneMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string imei */ 1: + message.imei = reader.string(); + break; + case /* optional string imsi */ 5: + message.imsi = reader.string(); + break; + case /* optional string phoneNumber */ 2: + message.phoneNumber = reader.string(); + break; + case /* optional string iccid */ 3: + message.iccid = reader.string(); + break; + case /* optional string network */ 4: + message.network = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DevicePhoneMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string imei = 1; */ + if (message.imei !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.imei); + /* optional string phoneNumber = 2; */ + if (message.phoneNumber !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.phoneNumber); + /* optional string iccid = 3; */ + if (message.iccid !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.iccid); + /* optional string network = 4; */ + if (message.network !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.network); + /* optional string imsi = 5; */ + if (message.imsi !== undefined) + writer.tag(5, WireType.LengthDelimited).string(message.imsi); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DevicePhoneMessage + */ +export const DevicePhoneMessage = new DevicePhoneMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceIdentityMessage$Type extends MessageType { + constructor() { + super("DeviceIdentityMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "platform", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "manufacturer", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "operator", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "model", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "abi", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "sdk", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 9, name: "display", kind: "message", T: () => DeviceDisplayMessage }, + { no: 11, name: "phone", kind: "message", T: () => DevicePhoneMessage }, + { no: 12, name: "product", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 13, name: "cpuPlatform", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 14, name: "openGLESVersion", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 15, name: "marketName", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 16, name: "macAddress", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 17, name: "ram", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceIdentityMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.platform = ""; + message.manufacturer = ""; + message.model = ""; + message.version = ""; + message.abi = ""; + message.sdk = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceIdentityMessage): DeviceIdentityMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string platform */ 2: + message.platform = reader.string(); + break; + case /* required string manufacturer */ 3: + message.manufacturer = reader.string(); + break; + case /* optional string operator */ 4: + message.operator = reader.string(); + break; + case /* required string model */ 5: + message.model = reader.string(); + break; + case /* required string version */ 6: + message.version = reader.string(); + break; + case /* required string abi */ 7: + message.abi = reader.string(); + break; + case /* required string sdk */ 8: + message.sdk = reader.string(); + break; + case /* required DeviceDisplayMessage display */ 9: + message.display = DeviceDisplayMessage.internalBinaryRead(reader, reader.uint32(), options, message.display); + break; + case /* required DevicePhoneMessage phone */ 11: + message.phone = DevicePhoneMessage.internalBinaryRead(reader, reader.uint32(), options, message.phone); + break; + case /* optional string product */ 12: + message.product = reader.string(); + break; + case /* optional string cpuPlatform */ 13: + message.cpuPlatform = reader.string(); + break; + case /* optional string openGLESVersion */ 14: + message.openGLESVersion = reader.string(); + break; + case /* optional string marketName */ 15: + message.marketName = reader.string(); + break; + case /* optional string macAddress */ 16: + message.macAddress = reader.string(); + break; + case /* optional string ram */ 17: + message.ram = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceIdentityMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string platform = 2; */ + if (message.platform !== "") + writer.tag(2, WireType.LengthDelimited).string(message.platform); + /* required string manufacturer = 3; */ + if (message.manufacturer !== "") + writer.tag(3, WireType.LengthDelimited).string(message.manufacturer); + /* optional string operator = 4; */ + if (message.operator !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.operator); + /* required string model = 5; */ + if (message.model !== "") + writer.tag(5, WireType.LengthDelimited).string(message.model); + /* required string version = 6; */ + if (message.version !== "") + writer.tag(6, WireType.LengthDelimited).string(message.version); + /* required string abi = 7; */ + if (message.abi !== "") + writer.tag(7, WireType.LengthDelimited).string(message.abi); + /* required string sdk = 8; */ + if (message.sdk !== "") + writer.tag(8, WireType.LengthDelimited).string(message.sdk); + /* required DeviceDisplayMessage display = 9; */ + if (message.display) + DeviceDisplayMessage.internalBinaryWrite(message.display, writer.tag(9, WireType.LengthDelimited).fork(), options).join(); + /* required DevicePhoneMessage phone = 11; */ + if (message.phone) + DevicePhoneMessage.internalBinaryWrite(message.phone, writer.tag(11, WireType.LengthDelimited).fork(), options).join(); + /* optional string product = 12; */ + if (message.product !== undefined) + writer.tag(12, WireType.LengthDelimited).string(message.product); + /* optional string cpuPlatform = 13; */ + if (message.cpuPlatform !== undefined) + writer.tag(13, WireType.LengthDelimited).string(message.cpuPlatform); + /* optional string openGLESVersion = 14; */ + if (message.openGLESVersion !== undefined) + writer.tag(14, WireType.LengthDelimited).string(message.openGLESVersion); + /* optional string marketName = 15; */ + if (message.marketName !== undefined) + writer.tag(15, WireType.LengthDelimited).string(message.marketName); + /* optional string macAddress = 16; */ + if (message.macAddress !== undefined) + writer.tag(16, WireType.LengthDelimited).string(message.macAddress); + /* optional string ram = 17; */ + if (message.ram !== undefined) + writer.tag(17, WireType.LengthDelimited).string(message.ram); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceIdentityMessage + */ +export const DeviceIdentityMessage = new DeviceIdentityMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceProperty$Type extends MessageType { + constructor() { + super("DeviceProperty", [ + { no: 1, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "value", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceProperty { + const message = globalThis.Object.create((this.messagePrototype!)); + message.name = ""; + message.value = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceProperty): DeviceProperty { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string name */ 1: + message.name = reader.string(); + break; + case /* required string value */ 2: + message.value = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceProperty, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string name = 1; */ + if (message.name !== "") + writer.tag(1, WireType.LengthDelimited).string(message.name); + /* required string value = 2; */ + if (message.value !== "") + writer.tag(2, WireType.LengthDelimited).string(message.value); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceProperty + */ +export const DeviceProperty = new DeviceProperty$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DevicePropertiesMessage$Type extends MessageType { + constructor() { + super("DevicePropertiesMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "properties", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DeviceProperty } + ]); + } + create(value?: PartialMessage): DevicePropertiesMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.properties = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DevicePropertiesMessage): DevicePropertiesMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* repeated DeviceProperty properties */ 2: + message.properties.push(DeviceProperty.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DevicePropertiesMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* repeated DeviceProperty properties = 2; */ + for (let i = 0; i < message.properties.length; i++) + DeviceProperty.internalBinaryWrite(message.properties[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DevicePropertiesMessage + */ +export const DevicePropertiesMessage = new DevicePropertiesMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceRequirement$Type extends MessageType { + constructor() { + super("DeviceRequirement", [ + { no: 1, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "value", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "type", kind: "enum", T: () => ["RequirementType", RequirementType] } + ]); + } + create(value?: PartialMessage): DeviceRequirement { + const message = globalThis.Object.create((this.messagePrototype!)); + message.name = ""; + message.value = ""; + message.type = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceRequirement): DeviceRequirement { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string name */ 1: + message.name = reader.string(); + break; + case /* required string value */ 2: + message.value = reader.string(); + break; + case /* required RequirementType type */ 3: + message.type = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceRequirement, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string name = 1; */ + if (message.name !== "") + writer.tag(1, WireType.LengthDelimited).string(message.name); + /* required string value = 2; */ + if (message.value !== "") + writer.tag(2, WireType.LengthDelimited).string(message.value); + /* required RequirementType type = 3; */ + if (message.type !== 0) + writer.tag(3, WireType.Varint).int32(message.type); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceRequirement + */ +export const DeviceRequirement = new DeviceRequirement$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class OwnerMessage$Type extends MessageType { + constructor() { + super("OwnerMessage", [ + { no: 1, name: "email", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "group", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): OwnerMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.email = ""; + message.name = ""; + message.group = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: OwnerMessage): OwnerMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string email */ 1: + message.email = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required string group */ 3: + message.group = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: OwnerMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string email = 1; */ + if (message.email !== "") + writer.tag(1, WireType.LengthDelimited).string(message.email); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required string group = 3; */ + if (message.group !== "") + writer.tag(3, WireType.LengthDelimited).string(message.group); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message OwnerMessage + */ +export const OwnerMessage = new OwnerMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GroupMessage$Type extends MessageType { + constructor() { + super("GroupMessage", [ + { no: 1, name: "owner", kind: "message", T: () => OwnerMessage }, + { no: 2, name: "timeout", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "requirements", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DeviceRequirement }, + { no: 4, name: "usage", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "keys", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.requirements = []; + message.keys = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GroupMessage): GroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required OwnerMessage owner */ 1: + message.owner = OwnerMessage.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* optional uint32 timeout */ 2: + message.timeout = reader.uint32(); + break; + case /* repeated DeviceRequirement requirements */ 3: + message.requirements.push(DeviceRequirement.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* optional string usage */ 4: + message.usage = reader.string(); + break; + case /* repeated string keys */ 5: + message.keys.push(reader.string()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required OwnerMessage owner = 1; */ + if (message.owner) + OwnerMessage.internalBinaryWrite(message.owner, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* optional uint32 timeout = 2; */ + if (message.timeout !== undefined) + writer.tag(2, WireType.Varint).uint32(message.timeout); + /* repeated DeviceRequirement requirements = 3; */ + for (let i = 0; i < message.requirements.length; i++) + DeviceRequirement.internalBinaryWrite(message.requirements[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* optional string usage = 4; */ + if (message.usage !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.usage); + /* repeated string keys = 5; */ + for (let i = 0; i < message.keys.length; i++) + writer.tag(5, WireType.LengthDelimited).string(message.keys[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GroupMessage + */ +export const GroupMessage = new GroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AutoGroupMessage$Type extends MessageType { + constructor() { + super("AutoGroupMessage", [ + { no: 1, name: "owner", kind: "message", T: () => OwnerMessage }, + { no: 2, name: "identifier", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AutoGroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.identifier = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AutoGroupMessage): AutoGroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required OwnerMessage owner */ 1: + message.owner = OwnerMessage.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* required string identifier */ 2: + message.identifier = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AutoGroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required OwnerMessage owner = 1; */ + if (message.owner) + OwnerMessage.internalBinaryWrite(message.owner, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* required string identifier = 2; */ + if (message.identifier !== "") + writer.tag(2, WireType.LengthDelimited).string(message.identifier); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AutoGroupMessage + */ +export const AutoGroupMessage = new AutoGroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UngroupMessage$Type extends MessageType { + constructor() { + super("UngroupMessage", [ + { no: 2, name: "requirements", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DeviceRequirement } + ]); + } + create(value?: PartialMessage): UngroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.requirements = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UngroupMessage): UngroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated DeviceRequirement requirements */ 2: + message.requirements.push(DeviceRequirement.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UngroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated DeviceRequirement requirements = 2; */ + for (let i = 0; i < message.requirements.length; i++) + DeviceRequirement.internalBinaryWrite(message.requirements[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UngroupMessage + */ +export const UngroupMessage = new UngroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class JoinGroupMessage$Type extends MessageType { + constructor() { + super("JoinGroupMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "owner", kind: "message", T: () => OwnerMessage }, + { no: 3, name: "usage", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "timeout", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): JoinGroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: JoinGroupMessage): JoinGroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required OwnerMessage owner */ 2: + message.owner = OwnerMessage.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* optional string usage */ 3: + message.usage = reader.string(); + break; + case /* optional uint32 timeout */ 4: + message.timeout = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: JoinGroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required OwnerMessage owner = 2; */ + if (message.owner) + OwnerMessage.internalBinaryWrite(message.owner, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* optional string usage = 3; */ + if (message.usage !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.usage); + /* optional uint32 timeout = 4; */ + if (message.timeout !== undefined) + writer.tag(4, WireType.Varint).uint32(message.timeout); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message JoinGroupMessage + */ +export const JoinGroupMessage = new JoinGroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class JoinGroupByAdbFingerprintMessage$Type extends MessageType { + constructor() { + super("JoinGroupByAdbFingerprintMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "fingerprint", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "comment", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "currentGroup", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): JoinGroupByAdbFingerprintMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.fingerprint = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: JoinGroupByAdbFingerprintMessage): JoinGroupByAdbFingerprintMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string fingerprint */ 2: + message.fingerprint = reader.string(); + break; + case /* optional string comment */ 3: + message.comment = reader.string(); + break; + case /* optional string currentGroup */ 4: + message.currentGroup = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: JoinGroupByAdbFingerprintMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string fingerprint = 2; */ + if (message.fingerprint !== "") + writer.tag(2, WireType.LengthDelimited).string(message.fingerprint); + /* optional string comment = 3; */ + if (message.comment !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.comment); + /* optional string currentGroup = 4; */ + if (message.currentGroup !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.currentGroup); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message JoinGroupByAdbFingerprintMessage + */ +export const JoinGroupByAdbFingerprintMessage = new JoinGroupByAdbFingerprintMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class JoinGroupByVncAuthResponseMessage$Type extends MessageType { + constructor() { + super("JoinGroupByVncAuthResponseMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "response", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "currentGroup", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): JoinGroupByVncAuthResponseMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.response = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: JoinGroupByVncAuthResponseMessage): JoinGroupByVncAuthResponseMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string response */ 2: + message.response = reader.string(); + break; + case /* optional string currentGroup */ 4: + message.currentGroup = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: JoinGroupByVncAuthResponseMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string response = 2; */ + if (message.response !== "") + writer.tag(2, WireType.LengthDelimited).string(message.response); + /* optional string currentGroup = 4; */ + if (message.currentGroup !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.currentGroup); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message JoinGroupByVncAuthResponseMessage + */ +export const JoinGroupByVncAuthResponseMessage = new JoinGroupByVncAuthResponseMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AdbKeysUpdatedMessage$Type extends MessageType { + constructor() { + super("AdbKeysUpdatedMessage", []); + } + create(value?: PartialMessage): AdbKeysUpdatedMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AdbKeysUpdatedMessage): AdbKeysUpdatedMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AdbKeysUpdatedMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AdbKeysUpdatedMessage + */ +export const AdbKeysUpdatedMessage = new AdbKeysUpdatedMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class VncAuthResponsesUpdatedMessage$Type extends MessageType { + constructor() { + super("VncAuthResponsesUpdatedMessage", []); + } + create(value?: PartialMessage): VncAuthResponsesUpdatedMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: VncAuthResponsesUpdatedMessage): VncAuthResponsesUpdatedMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: VncAuthResponsesUpdatedMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message VncAuthResponsesUpdatedMessage + */ +export const VncAuthResponsesUpdatedMessage = new VncAuthResponsesUpdatedMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LeaveGroupMessage$Type extends MessageType { + constructor() { + super("LeaveGroupMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "owner", kind: "message", T: () => OwnerMessage }, + { no: 3, name: "reason", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): LeaveGroupMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.reason = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LeaveGroupMessage): LeaveGroupMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required OwnerMessage owner */ 2: + message.owner = OwnerMessage.internalBinaryRead(reader, reader.uint32(), options, message.owner); + break; + case /* required string reason */ 3: + message.reason = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LeaveGroupMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required OwnerMessage owner = 2; */ + if (message.owner) + OwnerMessage.internalBinaryWrite(message.owner, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* required string reason = 3; */ + if (message.reason !== "") + writer.tag(3, WireType.LengthDelimited).string(message.reason); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LeaveGroupMessage + */ +export const LeaveGroupMessage = new LeaveGroupMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PhysicalIdentifyMessage$Type extends MessageType { + constructor() { + super("PhysicalIdentifyMessage", []); + } + create(value?: PartialMessage): PhysicalIdentifyMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PhysicalIdentifyMessage): PhysicalIdentifyMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PhysicalIdentifyMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message PhysicalIdentifyMessage + */ +export const PhysicalIdentifyMessage = new PhysicalIdentifyMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchDownMessage$Type extends MessageType { + constructor() { + super("TouchDownMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "contact", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "x", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 4, name: "y", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 5, name: "pressure", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ } + ]); + } + create(value?: PartialMessage): TouchDownMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + message.contact = 0; + message.x = 0; + message.y = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchDownMessage): TouchDownMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + case /* required uint32 contact */ 2: + message.contact = reader.uint32(); + break; + case /* required float x */ 3: + message.x = reader.float(); + break; + case /* required float y */ 4: + message.y = reader.float(); + break; + case /* optional float pressure */ 5: + message.pressure = reader.float(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchDownMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + /* required uint32 contact = 2; */ + if (message.contact !== 0) + writer.tag(2, WireType.Varint).uint32(message.contact); + /* required float x = 3; */ + if (message.x !== 0) + writer.tag(3, WireType.Bit32).float(message.x); + /* required float y = 4; */ + if (message.y !== 0) + writer.tag(4, WireType.Bit32).float(message.y); + /* optional float pressure = 5; */ + if (message.pressure !== undefined) + writer.tag(5, WireType.Bit32).float(message.pressure); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchDownMessage + */ +export const TouchDownMessage = new TouchDownMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchMoveMessage$Type extends MessageType { + constructor() { + super("TouchMoveMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "contact", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "x", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 4, name: "y", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 5, name: "pressure", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ } + ]); + } + create(value?: PartialMessage): TouchMoveMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + message.contact = 0; + message.x = 0; + message.y = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchMoveMessage): TouchMoveMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + case /* required uint32 contact */ 2: + message.contact = reader.uint32(); + break; + case /* required float x */ 3: + message.x = reader.float(); + break; + case /* required float y */ 4: + message.y = reader.float(); + break; + case /* optional float pressure */ 5: + message.pressure = reader.float(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchMoveMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + /* required uint32 contact = 2; */ + if (message.contact !== 0) + writer.tag(2, WireType.Varint).uint32(message.contact); + /* required float x = 3; */ + if (message.x !== 0) + writer.tag(3, WireType.Bit32).float(message.x); + /* required float y = 4; */ + if (message.y !== 0) + writer.tag(4, WireType.Bit32).float(message.y); + /* optional float pressure = 5; */ + if (message.pressure !== undefined) + writer.tag(5, WireType.Bit32).float(message.pressure); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchMoveMessage + */ +export const TouchMoveMessage = new TouchMoveMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchMoveIosMessage$Type extends MessageType { + constructor() { + super("TouchMoveIosMessage", [ + { no: 1, name: "toX", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 2, name: "toY", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 3, name: "fromX", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 4, name: "fromY", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ }, + { no: 5, name: "duration", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ } + ]); + } + create(value?: PartialMessage): TouchMoveIosMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.toX = 0; + message.toY = 0; + message.fromX = 0; + message.fromY = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchMoveIosMessage): TouchMoveIosMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required float toX */ 1: + message.toX = reader.float(); + break; + case /* required float toY */ 2: + message.toY = reader.float(); + break; + case /* required float fromX */ 3: + message.fromX = reader.float(); + break; + case /* required float fromY */ 4: + message.fromY = reader.float(); + break; + case /* optional float duration */ 5: + message.duration = reader.float(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchMoveIosMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required float toX = 1; */ + if (message.toX !== 0) + writer.tag(1, WireType.Bit32).float(message.toX); + /* required float toY = 2; */ + if (message.toY !== 0) + writer.tag(2, WireType.Bit32).float(message.toY); + /* required float fromX = 3; */ + if (message.fromX !== 0) + writer.tag(3, WireType.Bit32).float(message.fromX); + /* required float fromY = 4; */ + if (message.fromY !== 0) + writer.tag(4, WireType.Bit32).float(message.fromY); + /* optional float duration = 5; */ + if (message.duration !== undefined) + writer.tag(5, WireType.Bit32).float(message.duration); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchMoveIosMessage + */ +export const TouchMoveIosMessage = new TouchMoveIosMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchUpMessage$Type extends MessageType { + constructor() { + super("TouchUpMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: "contact", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): TouchUpMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + message.contact = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchUpMessage): TouchUpMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + case /* required uint32 contact */ 2: + message.contact = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchUpMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + /* required uint32 contact = 2; */ + if (message.contact !== 0) + writer.tag(2, WireType.Varint).uint32(message.contact); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchUpMessage + */ +export const TouchUpMessage = new TouchUpMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchCommitMessage$Type extends MessageType { + constructor() { + super("TouchCommitMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): TouchCommitMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchCommitMessage): TouchCommitMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchCommitMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchCommitMessage + */ +export const TouchCommitMessage = new TouchCommitMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TouchResetMessage$Type extends MessageType { + constructor() { + super("TouchResetMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): TouchResetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TouchResetMessage): TouchResetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TouchResetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TouchResetMessage + */ +export const TouchResetMessage = new TouchResetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GestureStartMessage$Type extends MessageType { + constructor() { + super("GestureStartMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): GestureStartMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GestureStartMessage): GestureStartMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GestureStartMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GestureStartMessage + */ +export const GestureStartMessage = new GestureStartMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GestureStopMessage$Type extends MessageType { + constructor() { + super("GestureStopMessage", [ + { no: 1, name: "seq", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): GestureStopMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.seq = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GestureStopMessage): GestureStopMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 seq */ 1: + message.seq = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GestureStopMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 seq = 1; */ + if (message.seq !== 0) + writer.tag(1, WireType.Varint).uint32(message.seq); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GestureStopMessage + */ +export const GestureStopMessage = new GestureStopMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TypeMessage$Type extends MessageType { + constructor() { + super("TypeMessage", [ + { no: 1, name: "text", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TypeMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.text = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TypeMessage): TypeMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string text */ 1: + message.text = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TypeMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string text = 1; */ + if (message.text !== "") + writer.tag(1, WireType.LengthDelimited).string(message.text); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TypeMessage + */ +export const TypeMessage = new TypeMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PasteMessage$Type extends MessageType { + constructor() { + super("PasteMessage", [ + { no: 1, name: "text", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): PasteMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.text = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PasteMessage): PasteMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string text */ 1: + message.text = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PasteMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string text = 1; */ + if (message.text !== "") + writer.tag(1, WireType.LengthDelimited).string(message.text); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message PasteMessage + */ +export const PasteMessage = new PasteMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class CopyMessage$Type extends MessageType { + constructor() { + super("CopyMessage", []); + } + create(value?: PartialMessage): CopyMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CopyMessage): CopyMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: CopyMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message CopyMessage + */ +export const CopyMessage = new CopyMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class KeyDownMessage$Type extends MessageType { + constructor() { + super("KeyDownMessage", [ + { no: 1, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): KeyDownMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.key = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: KeyDownMessage): KeyDownMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string key */ 1: + message.key = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: KeyDownMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string key = 1; */ + if (message.key !== "") + writer.tag(1, WireType.LengthDelimited).string(message.key); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message KeyDownMessage + */ +export const KeyDownMessage = new KeyDownMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class KeyUpMessage$Type extends MessageType { + constructor() { + super("KeyUpMessage", [ + { no: 1, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): KeyUpMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.key = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: KeyUpMessage): KeyUpMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string key */ 1: + message.key = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: KeyUpMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string key = 1; */ + if (message.key !== "") + writer.tag(1, WireType.LengthDelimited).string(message.key); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message KeyUpMessage + */ +export const KeyUpMessage = new KeyUpMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class KeyPressMessage$Type extends MessageType { + constructor() { + super("KeyPressMessage", [ + { no: 1, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): KeyPressMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.key = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: KeyPressMessage): KeyPressMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string key */ 1: + message.key = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: KeyPressMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string key = 1; */ + if (message.key !== "") + writer.tag(1, WireType.LengthDelimited).string(message.key); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message KeyPressMessage + */ +export const KeyPressMessage = new KeyPressMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RebootMessage$Type extends MessageType { + constructor() { + super("RebootMessage", []); + } + create(value?: PartialMessage): RebootMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RebootMessage): RebootMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RebootMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message RebootMessage + */ +export const RebootMessage = new RebootMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceLogcatEntryMessage$Type extends MessageType { + constructor() { + super("DeviceLogcatEntryMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "date", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 3, name: "pid", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "tid", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 5, name: "priority", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: "tag", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceLogcatEntryMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.date = 0; + message.pid = 0; + message.tid = 0; + message.priority = 0; + message.tag = ""; + message.message = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceLogcatEntryMessage): DeviceLogcatEntryMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required double date */ 2: + message.date = reader.double(); + break; + case /* required uint32 pid */ 3: + message.pid = reader.uint32(); + break; + case /* required uint32 tid */ 4: + message.tid = reader.uint32(); + break; + case /* required uint32 priority */ 5: + message.priority = reader.uint32(); + break; + case /* required string tag */ 6: + message.tag = reader.string(); + break; + case /* required string message */ 7: + message.message = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceLogcatEntryMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required double date = 2; */ + if (message.date !== 0) + writer.tag(2, WireType.Bit64).double(message.date); + /* required uint32 pid = 3; */ + if (message.pid !== 0) + writer.tag(3, WireType.Varint).uint32(message.pid); + /* required uint32 tid = 4; */ + if (message.tid !== 0) + writer.tag(4, WireType.Varint).uint32(message.tid); + /* required uint32 priority = 5; */ + if (message.priority !== 0) + writer.tag(5, WireType.Varint).uint32(message.priority); + /* required string tag = 6; */ + if (message.tag !== "") + writer.tag(6, WireType.LengthDelimited).string(message.tag); + /* required string message = 7; */ + if (message.message !== "") + writer.tag(7, WireType.LengthDelimited).string(message.message); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceLogcatEntryMessage + */ +export const DeviceLogcatEntryMessage = new DeviceLogcatEntryMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogcatFilter$Type extends MessageType { + constructor() { + super("LogcatFilter", [ + { no: 1, name: "tag", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "priority", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): LogcatFilter { + const message = globalThis.Object.create((this.messagePrototype!)); + message.tag = ""; + message.priority = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogcatFilter): LogcatFilter { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string tag */ 1: + message.tag = reader.string(); + break; + case /* required uint32 priority */ 2: + message.priority = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogcatFilter, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string tag = 1; */ + if (message.tag !== "") + writer.tag(1, WireType.LengthDelimited).string(message.tag); + /* required uint32 priority = 2; */ + if (message.priority !== 0) + writer.tag(2, WireType.Varint).uint32(message.priority); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LogcatFilter + */ +export const LogcatFilter = new LogcatFilter$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogcatStartMessage$Type extends MessageType { + constructor() { + super("LogcatStartMessage", [ + { no: 1, name: "filters", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => LogcatFilter } + ]); + } + create(value?: PartialMessage): LogcatStartMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.filters = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogcatStartMessage): LogcatStartMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated LogcatFilter filters */ 1: + message.filters.push(LogcatFilter.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogcatStartMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated LogcatFilter filters = 1; */ + for (let i = 0; i < message.filters.length; i++) + LogcatFilter.internalBinaryWrite(message.filters[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LogcatStartMessage + */ +export const LogcatStartMessage = new LogcatStartMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogcatStopMessage$Type extends MessageType { + constructor() { + super("LogcatStopMessage", []); + } + create(value?: PartialMessage): LogcatStopMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogcatStopMessage): LogcatStopMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogcatStopMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LogcatStopMessage + */ +export const LogcatStopMessage = new LogcatStopMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogcatApplyFiltersMessage$Type extends MessageType { + constructor() { + super("LogcatApplyFiltersMessage", [ + { no: 1, name: "filters", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => LogcatFilter } + ]); + } + create(value?: PartialMessage): LogcatApplyFiltersMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.filters = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogcatApplyFiltersMessage): LogcatApplyFiltersMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated LogcatFilter filters */ 1: + message.filters.push(LogcatFilter.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogcatApplyFiltersMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated LogcatFilter filters = 1; */ + for (let i = 0; i < message.filters.length; i++) + LogcatFilter.internalBinaryWrite(message.filters[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LogcatApplyFiltersMessage + */ +export const LogcatApplyFiltersMessage = new LogcatApplyFiltersMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ShellCommandMessage$Type extends MessageType { + constructor() { + super("ShellCommandMessage", [ + { no: 1, name: "command", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "timeout", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): ShellCommandMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.command = ""; + message.timeout = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ShellCommandMessage): ShellCommandMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string command */ 1: + message.command = reader.string(); + break; + case /* required uint32 timeout */ 2: + message.timeout = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ShellCommandMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string command = 1; */ + if (message.command !== "") + writer.tag(1, WireType.LengthDelimited).string(message.command); + /* required uint32 timeout = 2; */ + if (message.timeout !== 0) + writer.tag(2, WireType.Varint).uint32(message.timeout); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ShellCommandMessage + */ +export const ShellCommandMessage = new ShellCommandMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ShellKeepAliveMessage$Type extends MessageType { + constructor() { + super("ShellKeepAliveMessage", [ + { no: 1, name: "timeout", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): ShellKeepAliveMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.timeout = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ShellKeepAliveMessage): ShellKeepAliveMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 timeout */ 1: + message.timeout = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ShellKeepAliveMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 timeout = 1; */ + if (message.timeout !== 0) + writer.tag(1, WireType.Varint).uint32(message.timeout); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ShellKeepAliveMessage + */ +export const ShellKeepAliveMessage = new ShellKeepAliveMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InstallMessage$Type extends MessageType { + constructor() { + super("InstallMessage", [ + { no: 1, name: "href", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "launch", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "isApi", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "manifest", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "installFlags", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "jwt", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "pkg", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): InstallMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.href = ""; + message.launch = false; + message.isApi = false; + message.installFlags = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InstallMessage): InstallMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string href */ 1: + message.href = reader.string(); + break; + case /* required bool launch */ 2: + message.launch = reader.bool(); + break; + case /* required bool isApi */ 3: + message.isApi = reader.bool(); + break; + case /* optional string manifest */ 4: + message.manifest = reader.string(); + break; + case /* repeated string installFlags */ 5: + message.installFlags.push(reader.string()); + break; + case /* optional string jwt */ 6: + message.jwt = reader.string(); + break; + case /* optional string pkg */ 7: + message.pkg = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InstallMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string href = 1; */ + if (message.href !== "") + writer.tag(1, WireType.LengthDelimited).string(message.href); + /* required bool launch = 2; */ + if (message.launch !== false) + writer.tag(2, WireType.Varint).bool(message.launch); + /* required bool isApi = 3; */ + if (message.isApi !== false) + writer.tag(3, WireType.Varint).bool(message.isApi); + /* optional string manifest = 4; */ + if (message.manifest !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.manifest); + /* repeated string installFlags = 5; */ + for (let i = 0; i < message.installFlags.length; i++) + writer.tag(5, WireType.LengthDelimited).string(message.installFlags[i]); + /* optional string jwt = 6; */ + if (message.jwt !== undefined) + writer.tag(6, WireType.LengthDelimited).string(message.jwt); + /* optional string pkg = 7; */ + if (message.pkg !== undefined) + writer.tag(7, WireType.LengthDelimited).string(message.pkg); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message InstallMessage + */ +export const InstallMessage = new InstallMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UninstallMessage$Type extends MessageType { + constructor() { + super("UninstallMessage", [ + { no: 1, name: "packageName", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): UninstallMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.packageName = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UninstallMessage): UninstallMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string packageName */ 1: + message.packageName = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UninstallMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string packageName = 1; */ + if (message.packageName !== "") + writer.tag(1, WireType.LengthDelimited).string(message.packageName); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UninstallMessage + */ +export const UninstallMessage = new UninstallMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UninstallIosMessage$Type extends MessageType { + constructor() { + super("UninstallIosMessage", [ + { no: 1, name: "packageName", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): UninstallIosMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.packageName = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UninstallIosMessage): UninstallIosMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string packageName */ 1: + message.packageName = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UninstallIosMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string packageName = 1; */ + if (message.packageName !== "") + writer.tag(1, WireType.LengthDelimited).string(message.packageName); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UninstallIosMessage + */ +export const UninstallIosMessage = new UninstallIosMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LaunchActivityMessage$Type extends MessageType { + constructor() { + super("LaunchActivityMessage", [ + { no: 1, name: "action", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "component", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "category", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "flags", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): LaunchActivityMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.action = ""; + message.component = ""; + message.category = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LaunchActivityMessage): LaunchActivityMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string action */ 1: + message.action = reader.string(); + break; + case /* required string component */ 2: + message.component = reader.string(); + break; + case /* repeated string category */ 3: + message.category.push(reader.string()); + break; + case /* optional uint32 flags */ 4: + message.flags = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LaunchActivityMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string action = 1; */ + if (message.action !== "") + writer.tag(1, WireType.LengthDelimited).string(message.action); + /* required string component = 2; */ + if (message.component !== "") + writer.tag(2, WireType.LengthDelimited).string(message.component); + /* repeated string category = 3; */ + for (let i = 0; i < message.category.length; i++) + writer.tag(3, WireType.LengthDelimited).string(message.category[i]); + /* optional uint32 flags = 4; */ + if (message.flags !== undefined) + writer.tag(4, WireType.Varint).uint32(message.flags); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LaunchActivityMessage + */ +export const LaunchActivityMessage = new LaunchActivityMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RotateMessage$Type extends MessageType { + constructor() { + super("RotateMessage", [ + { no: 1, name: "rotation", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): RotateMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.rotation = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RotateMessage): RotateMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required int32 rotation */ 1: + message.rotation = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RotateMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required int32 rotation = 1; */ + if (message.rotation !== 0) + writer.tag(1, WireType.Varint).int32(message.rotation); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message RotateMessage + */ +export const RotateMessage = new RotateMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ChangeQualityMessage$Type extends MessageType { + constructor() { + super("ChangeQualityMessage", [ + { no: 1, name: "quality", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): ChangeQualityMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.quality = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ChangeQualityMessage): ChangeQualityMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required int32 quality */ 1: + message.quality = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ChangeQualityMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required int32 quality = 1; */ + if (message.quality !== 0) + writer.tag(1, WireType.Varint).int32(message.quality); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ChangeQualityMessage + */ +export const ChangeQualityMessage = new ChangeQualityMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ForwardTestMessage$Type extends MessageType { + constructor() { + super("ForwardTestMessage", [ + { no: 1, name: "targetHost", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "targetPort", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): ForwardTestMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.targetHost = ""; + message.targetPort = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ForwardTestMessage): ForwardTestMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string targetHost */ 1: + message.targetHost = reader.string(); + break; + case /* required uint32 targetPort */ 2: + message.targetPort = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ForwardTestMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string targetHost = 1; */ + if (message.targetHost !== "") + writer.tag(1, WireType.LengthDelimited).string(message.targetHost); + /* required uint32 targetPort = 2; */ + if (message.targetPort !== 0) + writer.tag(2, WireType.Varint).uint32(message.targetPort); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ForwardTestMessage + */ +export const ForwardTestMessage = new ForwardTestMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ForwardCreateMessage$Type extends MessageType { + constructor() { + super("ForwardCreateMessage", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "devicePort", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "targetHost", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "targetPort", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): ForwardCreateMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.devicePort = 0; + message.targetHost = ""; + message.targetPort = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ForwardCreateMessage): ForwardCreateMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required uint32 devicePort */ 2: + message.devicePort = reader.uint32(); + break; + case /* required string targetHost */ 3: + message.targetHost = reader.string(); + break; + case /* required uint32 targetPort */ 4: + message.targetPort = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ForwardCreateMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required uint32 devicePort = 2; */ + if (message.devicePort !== 0) + writer.tag(2, WireType.Varint).uint32(message.devicePort); + /* required string targetHost = 3; */ + if (message.targetHost !== "") + writer.tag(3, WireType.LengthDelimited).string(message.targetHost); + /* required uint32 targetPort = 4; */ + if (message.targetPort !== 0) + writer.tag(4, WireType.Varint).uint32(message.targetPort); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ForwardCreateMessage + */ +export const ForwardCreateMessage = new ForwardCreateMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ForwardRemoveMessage$Type extends MessageType { + constructor() { + super("ForwardRemoveMessage", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ForwardRemoveMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ForwardRemoveMessage): ForwardRemoveMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ForwardRemoveMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ForwardRemoveMessage + */ +export const ForwardRemoveMessage = new ForwardRemoveMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ReverseForward$Type extends MessageType { + constructor() { + super("ReverseForward", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "devicePort", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "targetHost", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "targetPort", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): ReverseForward { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.devicePort = 0; + message.targetHost = ""; + message.targetPort = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ReverseForward): ReverseForward { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required uint32 devicePort */ 2: + message.devicePort = reader.uint32(); + break; + case /* required string targetHost */ 3: + message.targetHost = reader.string(); + break; + case /* required uint32 targetPort */ 4: + message.targetPort = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ReverseForward, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required uint32 devicePort = 2; */ + if (message.devicePort !== 0) + writer.tag(2, WireType.Varint).uint32(message.devicePort); + /* required string targetHost = 3; */ + if (message.targetHost !== "") + writer.tag(3, WireType.LengthDelimited).string(message.targetHost); + /* required uint32 targetPort = 4; */ + if (message.targetPort !== 0) + writer.tag(4, WireType.Varint).uint32(message.targetPort); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ReverseForward + */ +export const ReverseForward = new ReverseForward$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ReverseForwardsEvent$Type extends MessageType { + constructor() { + super("ReverseForwardsEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "forwards", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ReverseForward } + ]); + } + create(value?: PartialMessage): ReverseForwardsEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.forwards = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ReverseForwardsEvent): ReverseForwardsEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* repeated ReverseForward forwards */ 2: + message.forwards.push(ReverseForward.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ReverseForwardsEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* repeated ReverseForward forwards = 2; */ + for (let i = 0; i < message.forwards.length; i++) + ReverseForward.internalBinaryWrite(message.forwards[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ReverseForwardsEvent + */ +export const ReverseForwardsEvent = new ReverseForwardsEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BrowserOpenMessage$Type extends MessageType { + constructor() { + super("BrowserOpenMessage", [ + { no: 1, name: "url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "browser", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): BrowserOpenMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.url = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BrowserOpenMessage): BrowserOpenMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string url */ 1: + message.url = reader.string(); + break; + case /* optional string browser */ 2: + message.browser = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BrowserOpenMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string url = 1; */ + if (message.url !== "") + writer.tag(1, WireType.LengthDelimited).string(message.url); + /* optional string browser = 2; */ + if (message.browser !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.browser); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BrowserOpenMessage + */ +export const BrowserOpenMessage = new BrowserOpenMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BrowserClearMessage$Type extends MessageType { + constructor() { + super("BrowserClearMessage", [ + { no: 1, name: "browser", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): BrowserClearMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BrowserClearMessage): BrowserClearMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string browser */ 1: + message.browser = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BrowserClearMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string browser = 1; */ + if (message.browser !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.browser); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BrowserClearMessage + */ +export const BrowserClearMessage = new BrowserClearMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class StoreOpenMessage$Type extends MessageType { + constructor() { + super("StoreOpenMessage", []); + } + create(value?: PartialMessage): StoreOpenMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StoreOpenMessage): StoreOpenMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: StoreOpenMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message StoreOpenMessage + */ +export const StoreOpenMessage = new StoreOpenMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ScreenCaptureMessage$Type extends MessageType { + constructor() { + super("ScreenCaptureMessage", []); + } + create(value?: PartialMessage): ScreenCaptureMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ScreenCaptureMessage): ScreenCaptureMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ScreenCaptureMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ScreenCaptureMessage + */ +export const ScreenCaptureMessage = new ScreenCaptureMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectStartMessage$Type extends MessageType { + constructor() { + super("ConnectStartMessage", []); + } + create(value?: PartialMessage): ConnectStartMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectStartMessage): ConnectStartMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectStartMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectStartMessage + */ +export const ConnectStartMessage = new ConnectStartMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectGetForwardUrlMessage$Type extends MessageType { + constructor() { + super("ConnectGetForwardUrlMessage", []); + } + create(value?: PartialMessage): ConnectGetForwardUrlMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectGetForwardUrlMessage): ConnectGetForwardUrlMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectGetForwardUrlMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectGetForwardUrlMessage + */ +export const ConnectGetForwardUrlMessage = new ConnectGetForwardUrlMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectStopMessage$Type extends MessageType { + constructor() { + super("ConnectStopMessage", []); + } + create(value?: PartialMessage): ConnectStopMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectStopMessage): ConnectStopMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectStopMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectStopMessage + */ +export const ConnectStopMessage = new ConnectStopMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AccountAddMenuMessage$Type extends MessageType { + constructor() { + super("AccountAddMenuMessage", []); + } + create(value?: PartialMessage): AccountAddMenuMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AccountAddMenuMessage): AccountAddMenuMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AccountAddMenuMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AccountAddMenuMessage + */ +export const AccountAddMenuMessage = new AccountAddMenuMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AccountAddMessage$Type extends MessageType { + constructor() { + super("AccountAddMessage", [ + { no: 1, name: "user", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "password", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AccountAddMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.user = ""; + message.password = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AccountAddMessage): AccountAddMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string user */ 1: + message.user = reader.string(); + break; + case /* required string password */ 2: + message.password = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AccountAddMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string user = 1; */ + if (message.user !== "") + writer.tag(1, WireType.LengthDelimited).string(message.user); + /* required string password = 2; */ + if (message.password !== "") + writer.tag(2, WireType.LengthDelimited).string(message.password); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AccountAddMessage + */ +export const AccountAddMessage = new AccountAddMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AccountCheckMessage$Type extends MessageType { + constructor() { + super("AccountCheckMessage", [ + { no: 1, name: "type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "account", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AccountCheckMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.type = ""; + message.account = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AccountCheckMessage): AccountCheckMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string type */ 1: + message.type = reader.string(); + break; + case /* required string account */ 2: + message.account = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AccountCheckMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string type = 1; */ + if (message.type !== "") + writer.tag(1, WireType.LengthDelimited).string(message.type); + /* required string account = 2; */ + if (message.account !== "") + writer.tag(2, WireType.LengthDelimited).string(message.account); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AccountCheckMessage + */ +export const AccountCheckMessage = new AccountCheckMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AccountGetMessage$Type extends MessageType { + constructor() { + super("AccountGetMessage", [ + { no: 1, name: "type", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AccountGetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AccountGetMessage): AccountGetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string type */ 1: + message.type = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AccountGetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string type = 1; */ + if (message.type !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.type); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AccountGetMessage + */ +export const AccountGetMessage = new AccountGetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AccountRemoveMessage$Type extends MessageType { + constructor() { + super("AccountRemoveMessage", [ + { no: 1, name: "type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "account", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AccountRemoveMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.type = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AccountRemoveMessage): AccountRemoveMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string type */ 1: + message.type = reader.string(); + break; + case /* optional string account */ 2: + message.account = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AccountRemoveMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string type = 1; */ + if (message.type !== "") + writer.tag(1, WireType.LengthDelimited).string(message.type); + /* optional string account = 2; */ + if (message.account !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.account); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AccountRemoveMessage + */ +export const AccountRemoveMessage = new AccountRemoveMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SdStatusMessage$Type extends MessageType { + constructor() { + super("SdStatusMessage", []); + } + create(value?: PartialMessage): SdStatusMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SdStatusMessage): SdStatusMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SdStatusMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SdStatusMessage + */ +export const SdStatusMessage = new SdStatusMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AirplaneSetMessage$Type extends MessageType { + constructor() { + super("AirplaneSetMessage", [ + { no: 1, name: "enabled", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): AirplaneSetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.enabled = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AirplaneSetMessage): AirplaneSetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required bool enabled */ 1: + message.enabled = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AirplaneSetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required bool enabled = 1; */ + if (message.enabled !== false) + writer.tag(1, WireType.Varint).bool(message.enabled); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AirplaneSetMessage + */ +export const AirplaneSetMessage = new AirplaneSetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RingerSetMessage$Type extends MessageType { + constructor() { + super("RingerSetMessage", [ + { no: 1, name: "mode", kind: "enum", T: () => ["RingerMode", RingerMode] } + ]); + } + create(value?: PartialMessage): RingerSetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.mode = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RingerSetMessage): RingerSetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required RingerMode mode */ 1: + message.mode = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RingerSetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required RingerMode mode = 1; */ + if (message.mode !== 0) + writer.tag(1, WireType.Varint).int32(message.mode); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message RingerSetMessage + */ +export const RingerSetMessage = new RingerSetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RingerGetMessage$Type extends MessageType { + constructor() { + super("RingerGetMessage", []); + } + create(value?: PartialMessage): RingerGetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RingerGetMessage): RingerGetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RingerGetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message RingerGetMessage + */ +export const RingerGetMessage = new RingerGetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class WifiSetEnabledMessage$Type extends MessageType { + constructor() { + super("WifiSetEnabledMessage", [ + { no: 1, name: "enabled", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): WifiSetEnabledMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.enabled = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WifiSetEnabledMessage): WifiSetEnabledMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required bool enabled */ 1: + message.enabled = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: WifiSetEnabledMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required bool enabled = 1; */ + if (message.enabled !== false) + writer.tag(1, WireType.Varint).bool(message.enabled); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message WifiSetEnabledMessage + */ +export const WifiSetEnabledMessage = new WifiSetEnabledMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class WifiGetStatusMessage$Type extends MessageType { + constructor() { + super("WifiGetStatusMessage", []); + } + create(value?: PartialMessage): WifiGetStatusMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WifiGetStatusMessage): WifiGetStatusMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: WifiGetStatusMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message WifiGetStatusMessage + */ +export const WifiGetStatusMessage = new WifiGetStatusMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BluetoothSetEnabledMessage$Type extends MessageType { + constructor() { + super("BluetoothSetEnabledMessage", [ + { no: 1, name: "enabled", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): BluetoothSetEnabledMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.enabled = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BluetoothSetEnabledMessage): BluetoothSetEnabledMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required bool enabled */ 1: + message.enabled = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BluetoothSetEnabledMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required bool enabled = 1; */ + if (message.enabled !== false) + writer.tag(1, WireType.Varint).bool(message.enabled); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BluetoothSetEnabledMessage + */ +export const BluetoothSetEnabledMessage = new BluetoothSetEnabledMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BluetoothGetStatusMessage$Type extends MessageType { + constructor() { + super("BluetoothGetStatusMessage", []); + } + create(value?: PartialMessage): BluetoothGetStatusMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BluetoothGetStatusMessage): BluetoothGetStatusMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BluetoothGetStatusMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BluetoothGetStatusMessage + */ +export const BluetoothGetStatusMessage = new BluetoothGetStatusMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BluetoothCleanBondedMessage$Type extends MessageType { + constructor() { + super("BluetoothCleanBondedMessage", []); + } + create(value?: PartialMessage): BluetoothCleanBondedMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BluetoothCleanBondedMessage): BluetoothCleanBondedMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BluetoothCleanBondedMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BluetoothCleanBondedMessage + */ +export const BluetoothCleanBondedMessage = new BluetoothCleanBondedMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class CapabilitiesMessage$Type extends MessageType { + constructor() { + super("CapabilitiesMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "hasTouch", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "hasCursor", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): CapabilitiesMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.hasTouch = false; + message.hasCursor = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CapabilitiesMessage): CapabilitiesMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required bool hasTouch */ 2: + message.hasTouch = reader.bool(); + break; + case /* required bool hasCursor */ 3: + message.hasCursor = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: CapabilitiesMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required bool hasTouch = 2; */ + if (message.hasTouch !== false) + writer.tag(2, WireType.Varint).bool(message.hasTouch); + /* required bool hasCursor = 3; */ + if (message.hasCursor !== false) + writer.tag(3, WireType.Varint).bool(message.hasCursor); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message CapabilitiesMessage + */ +export const CapabilitiesMessage = new CapabilitiesMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AirplaneModeEvent$Type extends MessageType { + constructor() { + super("AirplaneModeEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "enabled", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): AirplaneModeEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.enabled = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AirplaneModeEvent): AirplaneModeEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required bool enabled */ 2: + message.enabled = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AirplaneModeEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required bool enabled = 2; */ + if (message.enabled !== false) + writer.tag(2, WireType.Varint).bool(message.enabled); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message AirplaneModeEvent + */ +export const AirplaneModeEvent = new AirplaneModeEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class BatteryEvent$Type extends MessageType { + constructor() { + super("BatteryEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "health", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "level", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: "scale", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 7, name: "temp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 8, name: "voltage", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): BatteryEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.status = ""; + message.health = ""; + message.source = ""; + message.level = 0; + message.scale = 0; + message.temp = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: BatteryEvent): BatteryEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string status */ 2: + message.status = reader.string(); + break; + case /* required string health */ 3: + message.health = reader.string(); + break; + case /* required string source */ 4: + message.source = reader.string(); + break; + case /* required uint32 level */ 5: + message.level = reader.uint32(); + break; + case /* required uint32 scale */ 6: + message.scale = reader.uint32(); + break; + case /* required double temp */ 7: + message.temp = reader.double(); + break; + case /* optional double voltage */ 8: + message.voltage = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: BatteryEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string status = 2; */ + if (message.status !== "") + writer.tag(2, WireType.LengthDelimited).string(message.status); + /* required string health = 3; */ + if (message.health !== "") + writer.tag(3, WireType.LengthDelimited).string(message.health); + /* required string source = 4; */ + if (message.source !== "") + writer.tag(4, WireType.LengthDelimited).string(message.source); + /* required uint32 level = 5; */ + if (message.level !== 0) + writer.tag(5, WireType.Varint).uint32(message.level); + /* required uint32 scale = 6; */ + if (message.scale !== 0) + writer.tag(6, WireType.Varint).uint32(message.scale); + /* required double temp = 7; */ + if (message.temp !== 0) + writer.tag(7, WireType.Bit64).double(message.temp); + /* optional double voltage = 8; */ + if (message.voltage !== undefined) + writer.tag(8, WireType.Bit64).double(message.voltage); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message BatteryEvent + */ +export const BatteryEvent = new BatteryEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ConnectivityEvent$Type extends MessageType { + constructor() { + super("ConnectivityEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "connected", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 3, name: "type", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "subtype", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "failover", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ }, + { no: 6, name: "roaming", kind: "scalar", opt: true, T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): ConnectivityEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.connected = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ConnectivityEvent): ConnectivityEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required bool connected */ 2: + message.connected = reader.bool(); + break; + case /* optional string type */ 3: + message.type = reader.string(); + break; + case /* optional string subtype */ 4: + message.subtype = reader.string(); + break; + case /* optional bool failover */ 5: + message.failover = reader.bool(); + break; + case /* optional bool roaming */ 6: + message.roaming = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ConnectivityEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required bool connected = 2; */ + if (message.connected !== false) + writer.tag(2, WireType.Varint).bool(message.connected); + /* optional string type = 3; */ + if (message.type !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.type); + /* optional string subtype = 4; */ + if (message.subtype !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.subtype); + /* optional bool failover = 5; */ + if (message.failover !== undefined) + writer.tag(5, WireType.Varint).bool(message.failover); + /* optional bool roaming = 6; */ + if (message.roaming !== undefined) + writer.tag(6, WireType.Varint).bool(message.roaming); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message ConnectivityEvent + */ +export const ConnectivityEvent = new ConnectivityEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class PhoneStateEvent$Type extends MessageType { + constructor() { + super("PhoneStateEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "state", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "manual", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "operator", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): PhoneStateEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.state = ""; + message.manual = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: PhoneStateEvent): PhoneStateEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string state */ 2: + message.state = reader.string(); + break; + case /* required bool manual */ 3: + message.manual = reader.bool(); + break; + case /* optional string operator */ 4: + message.operator = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: PhoneStateEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string state = 2; */ + if (message.state !== "") + writer.tag(2, WireType.LengthDelimited).string(message.state); + /* required bool manual = 3; */ + if (message.manual !== false) + writer.tag(3, WireType.Varint).bool(message.manual); + /* optional string operator = 4; */ + if (message.operator !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.operator); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message PhoneStateEvent + */ +export const PhoneStateEvent = new PhoneStateEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RotationEvent$Type extends MessageType { + constructor() { + super("RotationEvent", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "rotation", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 3, name: "width", kind: "scalar", opt: true, T: 5 /*ScalarType.INT32*/ }, + { no: 4, name: "height", kind: "scalar", opt: true, T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): RotationEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.rotation = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RotationEvent): RotationEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required int32 rotation */ 2: + message.rotation = reader.int32(); + break; + case /* optional int32 width */ 3: + message.width = reader.int32(); + break; + case /* optional int32 height */ 4: + message.height = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RotationEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required int32 rotation = 2; */ + if (message.rotation !== 0) + writer.tag(2, WireType.Varint).int32(message.rotation); + /* optional int32 width = 3; */ + if (message.width !== undefined) + writer.tag(3, WireType.Varint).int32(message.width); + /* optional int32 height = 4; */ + if (message.height !== undefined) + writer.tag(4, WireType.Varint).int32(message.height); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message RotationEvent + */ +export const RotationEvent = new RotationEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SetDeviceDisplay$Type extends MessageType { + constructor() { + super("SetDeviceDisplay", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "channel", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "width", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 4, name: "height", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): SetDeviceDisplay { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.channel = ""; + message.width = 0; + message.height = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SetDeviceDisplay): SetDeviceDisplay { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string channel */ 2: + message.channel = reader.string(); + break; + case /* required int32 width */ 3: + message.width = reader.int32(); + break; + case /* required int32 height */ 4: + message.height = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SetDeviceDisplay, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string channel = 2; */ + if (message.channel !== "") + writer.tag(2, WireType.LengthDelimited).string(message.channel); + /* required int32 width = 3; */ + if (message.width !== 0) + writer.tag(3, WireType.Varint).int32(message.width); + /* required int32 height = 4; */ + if (message.height !== 0) + writer.tag(4, WireType.Varint).int32(message.height); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SetDeviceDisplay + */ +export const SetDeviceDisplay = new SetDeviceDisplay$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class IosDevicePorts$Type extends MessageType { + constructor() { + super("IosDevicePorts", [ + { no: 2, name: "screenPort", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 3, name: "connectPort", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): IosDevicePorts { + const message = globalThis.Object.create((this.messagePrototype!)); + message.screenPort = 0; + message.connectPort = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: IosDevicePorts): IosDevicePorts { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required int32 screenPort */ 2: + message.screenPort = reader.int32(); + break; + case /* required int32 connectPort */ 3: + message.connectPort = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: IosDevicePorts, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required int32 screenPort = 2; */ + if (message.screenPort !== 0) + writer.tag(2, WireType.Varint).int32(message.screenPort); + /* required int32 connectPort = 3; */ + if (message.connectPort !== 0) + writer.tag(3, WireType.Varint).int32(message.connectPort); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message IosDevicePorts + */ +export const IosDevicePorts = new IosDevicePorts$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class StartStreaming$Type extends MessageType { + constructor() { + super("StartStreaming", [ + { no: 1, name: "port", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 2, name: "channel", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): StartStreaming { + const message = globalThis.Object.create((this.messagePrototype!)); + message.port = 0; + message.channel = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StartStreaming): StartStreaming { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required int32 port */ 1: + message.port = reader.int32(); + break; + case /* required string channel */ 2: + message.channel = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: StartStreaming, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required int32 port = 1; */ + if (message.port !== 0) + writer.tag(1, WireType.Varint).int32(message.port); + /* required string channel = 2; */ + if (message.channel !== "") + writer.tag(2, WireType.LengthDelimited).string(message.channel); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message StartStreaming + */ +export const StartStreaming = new StartStreaming$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeleteDevice$Type extends MessageType { + constructor() { + super("DeleteDevice", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeleteDevice { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeleteDevice): DeleteDevice { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeleteDevice, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeleteDevice + */ +export const DeleteDevice = new DeleteDevice$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SetAbsentDisconnectedDevices$Type extends MessageType { + constructor() { + super("SetAbsentDisconnectedDevices", []); + } + create(value?: PartialMessage): SetAbsentDisconnectedDevices { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SetAbsentDisconnectedDevices): SetAbsentDisconnectedDevices { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SetAbsentDisconnectedDevices, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SetAbsentDisconnectedDevices + */ +export const SetAbsentDisconnectedDevices = new SetAbsentDisconnectedDevices$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class Applications$Type extends MessageType { + constructor() { + super("Applications", [ + { no: 1, name: "bundleId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "bundleName", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): Applications { + const message = globalThis.Object.create((this.messagePrototype!)); + message.bundleId = ""; + message.bundleName = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Applications): Applications { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string bundleId */ 1: + message.bundleId = reader.string(); + break; + case /* required string bundleName */ 2: + message.bundleName = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: Applications, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string bundleId = 1; */ + if (message.bundleId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.bundleId); + /* required string bundleName = 2; */ + if (message.bundleName !== "") + writer.tag(2, WireType.LengthDelimited).string(message.bundleName); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message Applications + */ +export const Applications = new Applications$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class InstalledApplications$Type extends MessageType { + constructor() { + super("InstalledApplications", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "applications", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => Applications } + ]); + } + create(value?: PartialMessage): InstalledApplications { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.applications = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: InstalledApplications): InstalledApplications { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* repeated Applications applications */ 2: + message.applications.push(Applications.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: InstalledApplications, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* repeated Applications applications = 2; */ + for (let i = 0; i < message.applications.length; i++) + Applications.internalBinaryWrite(message.applications[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message InstalledApplications + */ +export const InstalledApplications = new InstalledApplications$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TransportInstalledApps$Type extends MessageType { + constructor() { + super("TransportInstalledApps", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TransportInstalledApps { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TransportInstalledApps): TransportInstalledApps { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TransportInstalledApps, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TransportInstalledApps + */ +export const TransportInstalledApps = new TransportInstalledApps$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SetDeviceApp$Type extends MessageType { + constructor() { + super("SetDeviceApp", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "bundleId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "bundleName", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "pathToApp", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): SetDeviceApp { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.bundleId = ""; + message.bundleName = ""; + message.pathToApp = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SetDeviceApp): SetDeviceApp { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string bundleId */ 2: + message.bundleId = reader.string(); + break; + case /* required string bundleName */ 3: + message.bundleName = reader.string(); + break; + case /* required string pathToApp */ 4: + message.pathToApp = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SetDeviceApp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string bundleId = 2; */ + if (message.bundleId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.bundleId); + /* required string bundleName = 3; */ + if (message.bundleName !== "") + writer.tag(3, WireType.LengthDelimited).string(message.bundleName); + /* required string pathToApp = 4; */ + if (message.pathToApp !== "") + writer.tag(4, WireType.LengthDelimited).string(message.pathToApp); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SetDeviceApp + */ +export const SetDeviceApp = new SetDeviceApp$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetIosDeviceApps$Type extends MessageType { + constructor() { + super("GetIosDeviceApps", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "bundleId", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "bundleName", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "pathToApp", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GetIosDeviceApps { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.bundleId = ""; + message.bundleName = ""; + message.pathToApp = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetIosDeviceApps): GetIosDeviceApps { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required string bundleId */ 2: + message.bundleId = reader.string(); + break; + case /* required string bundleName */ 3: + message.bundleName = reader.string(); + break; + case /* required string pathToApp */ 4: + message.pathToApp = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetIosDeviceApps, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required string bundleId = 2; */ + if (message.bundleId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.bundleId); + /* required string bundleName = 3; */ + if (message.bundleName !== "") + writer.tag(3, WireType.LengthDelimited).string(message.bundleName); + /* required string pathToApp = 4; */ + if (message.pathToApp !== "") + writer.tag(4, WireType.LengthDelimited).string(message.pathToApp); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetIosDeviceApps + */ +export const GetIosDeviceApps = new GetIosDeviceApps$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TransationGetMessage$Type extends MessageType { + constructor() { + super("TransationGetMessage", [ + { no: 1, name: "source", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "data", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TransationGetMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.source = ""; + message.data = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TransationGetMessage): TransationGetMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string source */ 1: + message.source = reader.string(); + break; + case /* required string data */ 2: + message.data = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TransationGetMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string source = 1; */ + if (message.source !== "") + writer.tag(1, WireType.LengthDelimited).string(message.source); + /* required string data = 2; */ + if (message.data !== "") + writer.tag(2, WireType.LengthDelimited).string(message.data); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TransationGetMessage + */ +export const TransationGetMessage = new TransationGetMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetInstalledApplications$Type extends MessageType { + constructor() { + super("GetInstalledApplications", []); + } + create(value?: PartialMessage): GetInstalledApplications { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetInstalledApplications): GetInstalledApplications { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetInstalledApplications, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetInstalledApplications + */ +export const GetInstalledApplications = new GetInstalledApplications$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UpdateIosDevice$Type extends MessageType { + constructor() { + super("UpdateIosDevice", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "platform", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "architecture", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "sdk", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "service", kind: "message", T: () => IosServiceMessage } + ]); + } + create(value?: PartialMessage): UpdateIosDevice { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.name = ""; + message.platform = ""; + message.architecture = ""; + message.sdk = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UpdateIosDevice): UpdateIosDevice { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required string name */ 2: + message.name = reader.string(); + break; + case /* required string platform */ 3: + message.platform = reader.string(); + break; + case /* required string architecture */ 4: + message.architecture = reader.string(); + break; + case /* required string sdk */ 5: + message.sdk = reader.string(); + break; + case /* required IosServiceMessage service */ 6: + message.service = IosServiceMessage.internalBinaryRead(reader, reader.uint32(), options, message.service); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UpdateIosDevice, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* required string platform = 3; */ + if (message.platform !== "") + writer.tag(3, WireType.LengthDelimited).string(message.platform); + /* required string architecture = 4; */ + if (message.architecture !== "") + writer.tag(4, WireType.LengthDelimited).string(message.architecture); + /* required string sdk = 5; */ + if (message.sdk !== "") + writer.tag(5, WireType.LengthDelimited).string(message.sdk); + /* required IosServiceMessage service = 6; */ + if (message.service) + IosServiceMessage.internalBinaryWrite(message.service, writer.tag(6, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UpdateIosDevice + */ +export const UpdateIosDevice = new UpdateIosDevice$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SdkIosVersion$Type extends MessageType { + constructor() { + super("SdkIosVersion", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "sdkVersion", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): SdkIosVersion { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.sdkVersion = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SdkIosVersion): SdkIosVersion { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required string sdkVersion */ 2: + message.sdkVersion = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SdkIosVersion, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required string sdkVersion = 2; */ + if (message.sdkVersion !== "") + writer.tag(2, WireType.LengthDelimited).string(message.sdkVersion); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SdkIosVersion + */ +export const SdkIosVersion = new SdkIosVersion$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class SizeIosDevice$Type extends MessageType { + constructor() { + super("SizeIosDevice", [ + { no: 1, name: "id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "height", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 3, name: "width", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 4, name: "scale", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + ]); + } + create(value?: PartialMessage): SizeIosDevice { + const message = globalThis.Object.create((this.messagePrototype!)); + message.id = ""; + message.height = 0; + message.width = 0; + message.scale = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SizeIosDevice): SizeIosDevice { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string id */ 1: + message.id = reader.string(); + break; + case /* required double height */ 2: + message.height = reader.double(); + break; + case /* required double width */ 3: + message.width = reader.double(); + break; + case /* required int32 scale */ 4: + message.scale = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SizeIosDevice, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string id = 1; */ + if (message.id !== "") + writer.tag(1, WireType.LengthDelimited).string(message.id); + /* required double height = 2; */ + if (message.height !== 0) + writer.tag(2, WireType.Bit64).double(message.height); + /* required double width = 3; */ + if (message.width !== 0) + writer.tag(3, WireType.Bit64).double(message.width); + /* required int32 scale = 4; */ + if (message.scale !== 0) + writer.tag(4, WireType.Varint).int32(message.scale); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message SizeIosDevice + */ +export const SizeIosDevice = new SizeIosDevice$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DashboardOpenMessage$Type extends MessageType { + constructor() { + super("DashboardOpenMessage", []); + } + create(value?: PartialMessage): DashboardOpenMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DashboardOpenMessage): DashboardOpenMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DashboardOpenMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DashboardOpenMessage + */ +export const DashboardOpenMessage = new DashboardOpenMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetIosTreeElements$Type extends MessageType { + constructor() { + super("GetIosTreeElements", []); + } + create(value?: PartialMessage): GetIosTreeElements { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetIosTreeElements): GetIosTreeElements { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetIosTreeElements, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetIosTreeElements + */ +export const GetIosTreeElements = new GetIosTreeElements$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TapDeviceTreeElement$Type extends MessageType { + constructor() { + super("TapDeviceTreeElement", [ + { no: 1, name: "label", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TapDeviceTreeElement { + const message = globalThis.Object.create((this.messagePrototype!)); + message.label = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TapDeviceTreeElement): TapDeviceTreeElement { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string label */ 1: + message.label = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TapDeviceTreeElement, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string label = 1; */ + if (message.label !== "") + writer.tag(1, WireType.LengthDelimited).string(message.label); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TapDeviceTreeElement + */ +export const TapDeviceTreeElement = new TapDeviceTreeElement$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TemporarilyUnavailableMessage$Type extends MessageType { + constructor() { + super("TemporarilyUnavailableMessage", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TemporarilyUnavailableMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TemporarilyUnavailableMessage): TemporarilyUnavailableMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TemporarilyUnavailableMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TemporarilyUnavailableMessage + */ +export const TemporarilyUnavailableMessage = new TemporarilyUnavailableMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class UpdateRemoteConnectUrl$Type extends MessageType { + constructor() { + super("UpdateRemoteConnectUrl", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): UpdateRemoteConnectUrl { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: UpdateRemoteConnectUrl): UpdateRemoteConnectUrl { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: UpdateRemoteConnectUrl, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message UpdateRemoteConnectUrl + */ +export const UpdateRemoteConnectUrl = new UpdateRemoteConnectUrl$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class IosServiceMessage$Type extends MessageType { + constructor() { + super("IosServiceMessage", [ + { no: 1, name: "hasAPNS", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): IosServiceMessage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.hasAPNS = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: IosServiceMessage): IosServiceMessage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required bool hasAPNS */ 1: + message.hasAPNS = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: IosServiceMessage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required bool hasAPNS = 1; */ + if (message.hasAPNS !== false) + writer.tag(1, WireType.Varint).bool(message.hasAPNS); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message IosServiceMessage + */ +export const IosServiceMessage = new IosServiceMessage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LaunchDeviceApp$Type extends MessageType { + constructor() { + super("LaunchDeviceApp", [ + { no: 1, name: "pkg", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): LaunchDeviceApp { + const message = globalThis.Object.create((this.messagePrototype!)); + message.pkg = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LaunchDeviceApp): LaunchDeviceApp { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string pkg */ 1: + message.pkg = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LaunchDeviceApp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string pkg = 1; */ + if (message.pkg !== "") + writer.tag(1, WireType.LengthDelimited).string(message.pkg); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message LaunchDeviceApp + */ +export const LaunchDeviceApp = new LaunchDeviceApp$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TerminateDeviceApp$Type extends MessageType { + constructor() { + super("TerminateDeviceApp", []); + } + create(value?: PartialMessage): TerminateDeviceApp { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TerminateDeviceApp): TerminateDeviceApp { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TerminateDeviceApp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message TerminateDeviceApp + */ +export const TerminateDeviceApp = new TerminateDeviceApp$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class KillDeviceApp$Type extends MessageType { + constructor() { + super("KillDeviceApp", []); + } + create(value?: PartialMessage): KillDeviceApp { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: KillDeviceApp): KillDeviceApp { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: KillDeviceApp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message KillDeviceApp + */ +export const KillDeviceApp = new KillDeviceApp$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetAppAsset$Type extends MessageType { + constructor() { + super("GetAppAsset", [ + { no: 1, name: "url", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GetAppAsset { + const message = globalThis.Object.create((this.messagePrototype!)); + message.url = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetAppAsset): GetAppAsset { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string url */ 1: + message.url = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetAppAsset, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string url = 1; */ + if (message.url !== "") + writer.tag(1, WireType.LengthDelimited).string(message.url); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetAppAsset + */ +export const GetAppAsset = new GetAppAsset$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetAppAssetsList$Type extends MessageType { + constructor() { + super("GetAppAssetsList", []); + } + create(value?: PartialMessage): GetAppAssetsList { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetAppAssetsList): GetAppAssetsList { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetAppAssetsList, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetAppAssetsList + */ +export const GetAppAssetsList = new GetAppAssetsList$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetAppHTML$Type extends MessageType { + constructor() { + super("GetAppHTML", []); + } + create(value?: PartialMessage): GetAppHTML { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetAppHTML): GetAppHTML { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetAppHTML, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetAppHTML + */ +export const GetAppHTML = new GetAppHTML$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetAppInspectServerUrl$Type extends MessageType { + constructor() { + super("GetAppInspectServerUrl", []); + } + create(value?: PartialMessage): GetAppInspectServerUrl { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetAppInspectServerUrl): GetAppInspectServerUrl { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetAppInspectServerUrl, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetAppInspectServerUrl + */ +export const GetAppInspectServerUrl = new GetAppInspectServerUrl$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceStatusChange$Type extends MessageType { + constructor() { + super("DeviceStatusChange", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "timeout", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): DeviceStatusChange { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + message.timeout = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceStatusChange): DeviceStatusChange { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + case /* required uint32 timeout */ 2: + message.timeout = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceStatusChange, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + /* required uint32 timeout = 2; */ + if (message.timeout !== 0) + writer.tag(2, WireType.Varint).uint32(message.timeout); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceStatusChange + */ +export const DeviceStatusChange = new DeviceStatusChange$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DeviceGetIsInOrigin$Type extends MessageType { + constructor() { + super("DeviceGetIsInOrigin", [ + { no: 1, name: "serial", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DeviceGetIsInOrigin { + const message = globalThis.Object.create((this.messagePrototype!)); + message.serial = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DeviceGetIsInOrigin): DeviceGetIsInOrigin { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required string serial */ 1: + message.serial = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DeviceGetIsInOrigin, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required string serial = 1; */ + if (message.serial !== "") + writer.tag(1, WireType.LengthDelimited).string(message.serial); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message DeviceGetIsInOrigin + */ +export const DeviceGetIsInOrigin = new DeviceGetIsInOrigin$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetPresentDevices$Type extends MessageType { + constructor() { + super("GetPresentDevices", []); + } + create(value?: PartialMessage): GetPresentDevices { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetPresentDevices): GetPresentDevices { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetPresentDevices, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetPresentDevices + */ +export const GetPresentDevices = new GetPresentDevices$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetDeadDevices$Type extends MessageType { + constructor() { + super("GetDeadDevices", [ + { no: 1, name: "time", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): GetDeadDevices { + const message = globalThis.Object.create((this.messagePrototype!)); + message.time = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetDeadDevices): GetDeadDevices { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* required uint32 time */ 1: + message.time = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetDeadDevices, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* required uint32 time = 1; */ + if (message.time !== 0) + writer.tag(1, WireType.Varint).uint32(message.time); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message GetDeadDevices + */ +export const GetDeadDevices = new GetDeadDevices$Type(); diff --git a/package-lock.json b/package-lock.json index 03a743e69b..6139152d62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@irdk/usbmux": "^0.2.2", "@julusian/jpeg-turbo": "2.1.0", "@node-saml/passport-saml": "5.1.0", + "@protobuf-ts/plugin": "^2.11.1", "@sentry/node": "^8.34.0", "@types/chrome-remote-interface": "^0.31.14", "@u4/adbkit": "^5.1.7", @@ -96,7 +97,6 @@ "temp": "0.9.4", "tmp-promise": "^3.0.3", "transliteration": "2.2.0", - "ts-proto": "^2.6.1", "tsx": "4.20.3", "underscore.string": "3.3.6", "url-join": "1.1.0", @@ -116,7 +116,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.30.1", + "@eslint/js": "^9.33.0", "@playwright/test": "^1.52.0", "@types/bluebird": "^3.5.42", "@types/chalk": "^0.4.31", @@ -125,6 +125,7 @@ "@types/http-proxy": "^1.17.16", "@types/lodash": "^4.17.16", "@types/node": "^22.15.17", + "@types/semver": "^7.7.1", "@types/split": "^1.0.5", "@types/temp": "^0.9.4", "@types/tmp": "^0.2.6", @@ -132,14 +133,14 @@ "async": "2.6.4", "cli-docs-generator": "1.0.7", "esbuild": "0.25.8", - "eslint": "9.30.1", + "eslint": "^9.30.1", "event-stream": "3.3.5", "exports-loader": "^4.0.0", "fs-extra": "8.1.0", "globals": "^15.11.0", "http-https": "1.0.0", "imports-loader": "^4.0.1", - "typescript": "^5.5.3", + "typescript": "^5.9.2", "typescript-eslint": "^8.39.1" }, "engines": { @@ -1168,11 +1169,35 @@ } }, "node_modules/@bufbuild/protobuf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.2.tgz", - "integrity": "sha512-vLu7SRY84CV/Dd+NUdgtidn2hS5hSMUC1vDBY0VcviTdgRYkU43vIz3vIFbmx14cX1r+mM7WjzE5Fl1fGEM0RQ==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.3.tgz", + "integrity": "sha512-w/gJKME9mYN7ZoUAmSMAWXk4hkVpxRKvEJCb3dV5g9wwWdxTJJ0ayOJAVcNxtdqaxDyFuC0uz4RSGVacJ030PQ==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@bufbuild/protoplugin": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-2.6.3.tgz", + "integrity": "sha512-VceMuxeRukxGeABfo34SXq0VqY1MU+mzS+PBf0HAWo97ylFut8F6sQ3mV0tKiM08UQ/xQco7lxCn83BkoxrWrA==", + "license": "Apache-2.0", + "dependencies": { + "@bufbuild/protobuf": "2.6.3", + "@typescript/vfs": "^1.5.2", + "typescript": "5.4.5" + } + }, + "node_modules/@bufbuild/protoplugin/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@devicefarmer/adbkit-apkreader": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-apkreader/-/adbkit-apkreader-3.2.4.tgz", @@ -1255,70 +1280,6 @@ "integrity": "sha512-p87QMgXmJS5K8lWkVvYgwmSHmxSsB+N8ctcZZsGx26wOh+0/RiDfsVQAIMv+SME6IWVXIjo/FiZRsGNlvw85Sg==", "license": "CC-BY-SA-4.0" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", - "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", - "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", - "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", - "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", @@ -1335,342 +1296,6 @@ "node": ">=18" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", - "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", - "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", - "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", - "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", - "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", - "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", - "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", - "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", - "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", - "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", - "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", - "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", - "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", - "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", - "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", - "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", - "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", - "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", - "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", - "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", - "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -1789,9 +1414,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", - "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz", + "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==", "dev": true, "license": "MIT", "engines": { @@ -3450,6 +3075,61 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@protobuf-ts/plugin": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.11.1.tgz", + "integrity": "sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A==", + "license": "Apache-2.0", + "dependencies": { + "@bufbuild/protobuf": "^2.4.0", + "@bufbuild/protoplugin": "^2.4.0", + "@protobuf-ts/protoc": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "typescript": "^3.9" + }, + "bin": { + "protoc-gen-dump": "bin/protoc-gen-dump", + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/@protobuf-ts/plugin/node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@protobuf-ts/protoc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.11.1.tgz", + "integrity": "sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg==", + "license": "Apache-2.0", + "bin": { + "protoc": "protoc.js" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -4830,6 +4510,13 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/send": { "version": "0.17.5", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", @@ -5224,6 +4911,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript/vfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.1.tgz", + "integrity": "sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + }, + "peerDependencies": { + "typescript": "*" + } + }, "node_modules/@u4/adbkit": { "version": "5.1.7", "resolved": "https://registry.npmjs.org/@u4/adbkit/-/adbkit-5.1.7.tgz", @@ -5793,12 +5492,43 @@ "yauzl": "^2.7.0" } }, + "node_modules/appium-support/node_modules/axios": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz", + "integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/appium-support/node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "license": "MIT" }, + "node_modules/appium-support/node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/appium-support/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -6035,17 +5765,6 @@ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "license": "MIT" }, - "node_modules/axios": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.30.0.tgz", - "integrity": "sha512-Z4F3LjCgfjZz8BMYalWdMgAQUnEtKDmpwNHjh/C8pQZWde32TF64cqnSeyL3xD/aTIASRU30RHTNzRiV/NpGMg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/backoff": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", @@ -6471,18 +6190,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/case-anything": { - "version": "2.1.13", - "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", - "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", - "license": "MIT", - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -6878,9 +6585,9 @@ } }, "node_modules/cmake-js/node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz", + "integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -6889,9 +6596,9 @@ } }, "node_modules/cmake-js/node_modules/follow-redirects": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.10.tgz", - "integrity": "sha512-V7O/fFKM539IC2bweloFWuoiJ9OtI3W2uIqJPWM8IT5xxNyt73QtvVqmSpcDmk07ivmmlKB+rRY0vpQjIYNtKw==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -7526,18 +7233,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/devtools-protocol": { "version": "0.0.927104", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.927104.tgz", @@ -7567,15 +7262,6 @@ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, - "node_modules/dprint-node": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", - "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", - "license": "MIT", - "dependencies": { - "detect-libc": "^1.0.3" - } - }, "node_modules/draggabilly": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/draggabilly/-/draggabilly-1.2.4.tgz", @@ -13984,39 +13670,6 @@ "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==", "license": "MIT" }, - "node_modules/ts-poet": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", - "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", - "license": "Apache-2.0", - "dependencies": { - "dprint-node": "^1.0.8" - } - }, - "node_modules/ts-proto": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.7.5.tgz", - "integrity": "sha512-FoRxSaNW+P3m+GiXIZjUjhaHXT67Ah4zMGKzn4yklbGRQTS+PqpUhKo5AJnwfUDUByjEUG7ch36byFUYWRH9Nw==", - "license": "ISC", - "dependencies": { - "@bufbuild/protobuf": "^2.0.0", - "case-anything": "^2.1.13", - "ts-poet": "^6.12.0", - "ts-proto-descriptors": "2.0.0" - }, - "bin": { - "protoc-gen-ts_proto": "protoc-gen-ts_proto" - } - }, - "node_modules/ts-proto-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.0.0.tgz", - "integrity": "sha512-wHcTH3xIv11jxgkX5OyCSFfw27agpInAd6yh89hKG6zqIXnjW9SYqSER2CVQxdPj4czeOhGagNvZBEbJPy7qkw==", - "license": "ISC", - "dependencies": { - "@bufbuild/protobuf": "^2.0.0" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -14098,10 +13751,9 @@ } }, "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 269f40024a..f31f526540 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "build:swagger:tests": "cd ./test/api && poetry run just regen-schema", "build:swagger:ui": "cd ./ui && npm run generate-api", "build:swagger": "cd ./lib/units/api && python3 ./gen_routes.py & npm run build:swagger:ui", + "protoc": "npx protoc --ts_out ./lib/wire --ts_opt generate_dependencies --proto_path ./lib/wire ./lib/wire/wire.proto", "build": "tsc", "dev": "tsx ./bin/devstf.mjs" }, @@ -44,6 +45,7 @@ "@irdk/usbmux": "^0.2.2", "@julusian/jpeg-turbo": "2.1.0", "@node-saml/passport-saml": "5.1.0", + "@protobuf-ts/plugin": "^2.11.1", "@sentry/node": "^8.34.0", "@types/chrome-remote-interface": "^0.31.14", "@u4/adbkit": "^5.1.7", @@ -118,7 +120,6 @@ "temp": "0.9.4", "tmp-promise": "^3.0.3", "transliteration": "2.2.0", - "ts-proto": "^2.6.1", "tsx": "4.20.3", "underscore.string": "3.3.6", "url-join": "1.1.0", @@ -133,7 +134,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.30.1", + "@eslint/js": "^9.33.0", "@playwright/test": "^1.52.0", "@types/bluebird": "^3.5.42", "@types/chalk": "^0.4.31", @@ -142,6 +143,7 @@ "@types/http-proxy": "^1.17.16", "@types/lodash": "^4.17.16", "@types/node": "^22.15.17", + "@types/semver": "^7.7.1", "@types/split": "^1.0.5", "@types/temp": "^0.9.4", "@types/tmp": "^0.2.6", @@ -149,14 +151,14 @@ "async": "2.6.4", "cli-docs-generator": "1.0.7", "esbuild": "0.25.8", - "eslint": "9.30.1", + "eslint": "^9.30.1", "event-stream": "3.3.5", "exports-loader": "^4.0.0", "fs-extra": "8.1.0", "globals": "^15.11.0", "http-https": "1.0.0", "imports-loader": "^4.0.1", - "typescript": "^5.5.3", + "typescript": "^5.9.2", "typescript-eslint": "^8.39.1" }, "overrides": { @@ -169,7 +171,8 @@ "socket.io-parser": "4.2.4", "request": "$request", "validator": "13.9.0", - "node-forge": "1.3.1" + "node-forge": "1.3.1", + "axios": "1.12.0" }, "engines": { "node": ">= 12", diff --git a/tsconfig.json b/tsconfig.json index 0b837d6f07..77913205eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,6 +19,9 @@ "target": "es2022", "rewriteRelativeImportExtensions": true, "lib": ["ES2022", "DOM"], + "paths": { + "@u4/adbkit/*": ["./node_modules/@u4/adbkit/*"] + }, "types": ["node"] }, "include": [ diff --git a/ui/package-lock.json b/ui/package-lock.json index ab8c37f585..05631b6170 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -25,6 +25,8 @@ "i18next-http-backend": "^2.6.2", "inversify": "^6.2.1", "inversify-react": "^1.2.0", + "linkify-html": "^4.3.2", + "linkify-react": "^4.3.2", "lodash": "^4.17.21", "mobx": "^6.13.5", "mobx-persist-store": "^1.1.5", @@ -7379,17 +7381,6 @@ "react": "^15.x || ^16.x || ^17.x || ^18.x || ^19.x" } }, - "node_modules/console-feed/node_modules/linkifyjs": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-2.1.9.tgz", - "integrity": "sha512-74ivurkK6WHvHFozVaGtQWV38FzBwSTGNmJolEgFp7QgR2bl6ArUWlvT4GcHKbPe1z3nWYi+VUdDZk16zDOVug==", - "license": "MIT", - "peerDependencies": { - "jquery": ">= 1.11.0", - "react": ">= 0.14.0", - "react-dom": ">= 0.14.0" - } - }, "node_modules/console-feed/node_modules/react-inspector": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz", @@ -11276,13 +11267,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", - "license": "MIT", - "peer": true - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11640,6 +11624,31 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/linkify-html": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkify-html/-/linkify-html-4.3.2.tgz", + "integrity": "sha512-RozNgrfSFrNQlprJSZIN7lF+ZVPj5Pz8POQcu1PYGAUhL9tKtvtWcOXOmlXjuGGEWHtC6gt6Q2U4+VUq9ELmng==", + "license": "MIT", + "peerDependencies": { + "linkifyjs": "^4.0.0" + } + }, + "node_modules/linkify-react": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.3.2.tgz", + "integrity": "sha512-mi744h1hf+WDsr+paJgSBBgYNLMWNSHyM9V9LVUo03RidNGdw1VpI7Twnt+K3pEh3nIzB4xiiAgZxpd61ItKpQ==", + "license": "MIT", + "peerDependencies": { + "linkifyjs": "^4.0.0", + "react": ">= 15.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", diff --git a/ui/package.json b/ui/package.json index 4989f9d0da..de59eb82dc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -45,6 +45,8 @@ "i18next-http-backend": "^2.6.2", "inversify": "^6.2.1", "inversify-react": "^1.2.0", + "linkify-html": "^4.3.2", + "linkify-react": "^4.3.2", "lodash": "^4.17.21", "mobx": "^6.13.5", "mobx-persist-store": "^1.1.5", @@ -106,6 +108,9 @@ "vite-tsconfig-paths": "^5.0.1", "vitest": "^3.0.9" }, + "overrides": { + "linkifyjs": "4.3.2" + }, "msw": { "workerDirectory": [ "public" diff --git a/ui/src/store/device-connection.ts b/ui/src/store/device-connection.ts index d8060c09be..e14f1fe52c 100644 --- a/ui/src/store/device-connection.ts +++ b/ui/src/store/device-connection.ts @@ -30,9 +30,9 @@ export class DeviceConnection { async useDevice(): Promise { const device = await this.deviceBySerialStore.fetch() - if (!device?.channel) return - try { + if (!device?.channel) throw new Error('Device is not cooperating.') + const startRemoteConnectResult = await this.deviceControlStore.startRemoteConnect() startRemoteConnectResult.donePromise.then(({ data }) => { diff --git a/ui/vite.config.ts b/ui/vite.config.ts index f0da2be776..91d36f544f 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -9,7 +9,13 @@ import tsconfigPaths from 'vite-tsconfig-paths' export default defineConfig({ plugins: [react({ tsDecorators: true }), tsconfigPaths(), svgr()], resolve: { - alias: [{ find: /^@vkontakte\/vkui$/, replacement: '@vkontakte/vkui/dist/cssm' }], + alias: [ + { find: /^@vkontakte\/vkui$/, replacement: '@vkontakte/vkui/dist/cssm' }, + + // TODO: REMOVE AFTER REPLACING `console-feed` WITH `chii` + { find: /^linkifyjs\/html$/, replacement: 'linkify-html' }, + { find: /^linkifyjs\/react$/, replacement: 'linkify-react' } + ], }, preview: { port: 5173, From 62405aafdc8603cdfa8455b855a4353636733051 Mon Sep 17 00:00:00 2001 From: Elmir Khalilov <52529096+e-khalilov@users.noreply.github.com> Date: Wed, 22 Oct 2025 12:47:09 +0300 Subject: [PATCH 2/5] Hotfix: Fix broken import in ios Co-authored-by: e.khalilov --- lib/units/ios-device/plugins/install.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/units/ios-device/plugins/install.js b/lib/units/ios-device/plugins/install.js index 0d95efd686..a0f9e19338 100755 --- a/lib/units/ios-device/plugins/install.js +++ b/lib/units/ios-device/plugins/install.js @@ -1,7 +1,6 @@ import {v4 as uuidv4} from 'uuid' import syrup from '@devicefarmer/stf-syrup' import logger from '../../../util/logger.js' -import wire from '../../../wire/index.js' import wireutil from '../../../wire/util.js' import Promise from 'bluebird' import {exec} from 'child_process' @@ -10,7 +9,7 @@ import router from '../../base-device/support/router.js' import push from '../../base-device/support/push.js' import storage from '../../base-device/support/storage.js' import deviceutil from '../../../util/deviceutil.js' -import {InstallMessage} from '../../../wire/wire.js' +import {InstallMessage, UninstallIosMessage} from '../../../wire/wire.js' function execShellCommand(cmd) { return new Promise((resolve, reject) => { From cc26e2285e2b7c9c7ef5144aa0e5eb2f51e3ea63 Mon Sep 17 00:00:00 2001 From: Daniil <8039921+DaniilSmirnov@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:50:35 +0300 Subject: [PATCH 3/5] fix vulnerable deps (#384) --- package-lock.json | 72 +-------- package.json | 3 +- test/e2e/Dockerfile | 2 +- test/e2e/package-lock.json | 24 +-- test/e2e/package.json | 2 +- ui/package-lock.json | 303 +++++++++++++++++++++++-------------- ui/package.json | 8 +- 7 files changed, 211 insertions(+), 203 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6139152d62..bb8bed333a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "express-validator": "4.3.0", "fast-printf": "^1.6.10", "file-saver": "1.3.3", - "follow-redirects": "1.15.5", + "follow-redirects": "1.15.6", "formidable": "1.2.6", "gm": "1.25.1", "http-proxy": "1.18.1", @@ -117,7 +117,6 @@ "devDependencies": { "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.33.0", - "@playwright/test": "^1.52.0", "@types/bluebird": "^3.5.42", "@types/chalk": "^0.4.31", "@types/eventemitter3": "^1.2.0", @@ -2966,22 +2965,6 @@ "node": ">=14" } }, - "node_modules/@playwright/test": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz", - "integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright": "1.54.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@postman/form-data": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", @@ -8372,9 +8355,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -8545,21 +8528,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/ftp-response-parser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ftp-response-parser/-/ftp-response-parser-1.0.1.tgz", @@ -11384,38 +11352,6 @@ "node": ">= 14.15.0" } }, - "node_modules/playwright": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz", - "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.54.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz", - "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/please-upgrade-node": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", diff --git a/package.json b/package.json index f31f526540..6ed1237c03 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "express-validator": "4.3.0", "fast-printf": "^1.6.10", "file-saver": "1.3.3", - "follow-redirects": "1.15.5", + "follow-redirects": "1.15.6", "formidable": "1.2.6", "gm": "1.25.1", "http-proxy": "1.18.1", @@ -135,7 +135,6 @@ "devDependencies": { "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.33.0", - "@playwright/test": "^1.52.0", "@types/bluebird": "^3.5.42", "@types/chalk": "^0.4.31", "@types/eventemitter3": "^1.2.0", diff --git a/test/e2e/Dockerfile b/test/e2e/Dockerfile index 3e915f2153..b9107285c0 100644 --- a/test/e2e/Dockerfile +++ b/test/e2e/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/playwright:v1.52.0-noble +FROM mcr.microsoft.com/playwright:v1.55.1-noble WORKDIR /tests diff --git a/test/e2e/package-lock.json b/test/e2e/package-lock.json index 34a0217df7..70fd01ac88 100644 --- a/test/e2e/package-lock.json +++ b/test/e2e/package-lock.json @@ -8,7 +8,7 @@ "name": "vk-devicehub-e2e-tests", "version": "0.0.1", "dependencies": { - "@playwright/test": "^1.52.0", + "@playwright/test": "^1.55.1", "typescript": "^5.5.3" }, "devDependencies": { @@ -230,12 +230,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", - "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.52.0" + "playwright": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -2324,12 +2324,12 @@ } }, "node_modules/playwright": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", - "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.52.0" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -2342,9 +2342,9 @@ } }, "node_modules/playwright-core": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", - "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" diff --git a/test/e2e/package.json b/test/e2e/package.json index df6949660c..f81cd67ae7 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -9,7 +9,7 @@ "scripts": { }, "dependencies": { - "@playwright/test": "^1.52.0", + "@playwright/test": "^1.55.1", "typescript": "^5.5.3" }, "devDependencies": { diff --git a/ui/package-lock.json b/ui/package-lock.json index 05631b6170..ad744371f5 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -16,7 +16,7 @@ "@tanstack/react-virtual": "^3.10.8", "@vkontakte/icons": "^2.148.0", "@vkontakte/vkui": "^7.1.2", - "axios": "^1.11.0", + "axios": "^1.12.0", "classnames": "^2.5.1", "console-feed": "^3.8.0", "date-fns": "^4.1.0", @@ -55,8 +55,8 @@ "@types/react-slider": "^1.3.6", "@types/wicg-file-system-access": "^2023.10.5", "@vitejs/plugin-react-swc": "^3.5.0", - "@vitest/coverage-v8": "^3.0.9", - "@vitest/ui": "^3.0.9", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/ui": "^3.2.4", "eslint": "^9.11.1", "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-fp": "^2.3.0", @@ -83,7 +83,7 @@ "typescript": "^5.5.3", "typescript-eslint": "^8.16.0", "typescript-plugin-css-modules": "^5.1.0", - "vite": "^6.2.2", + "vite": "^6.4.1", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^5.0.1", "vitest": "^3.0.9" @@ -2887,9 +2887,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -4021,9 +4021,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "dev": true, "license": "MIT" }, @@ -5588,6 +5588,17 @@ "license": "MIT", "peer": true }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -5595,6 +5606,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/es-aggregate-error": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", @@ -5968,22 +5986,23 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.9.tgz", - "integrity": "sha512-15OACZcBtQ34keIEn19JYTVuMFTlFrClclwWjHo/IRPg/8ELpkgNTl0o7WLP9WO9XGH6+tip9CPYtEOrIDJvBA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^1.0.2", - "debug": "^4.4.0", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.6", "istanbul-reports": "^3.1.7", "magic-string": "^0.30.17", "magicast": "^0.3.5", - "std-env": "^3.8.0", + "std-env": "^3.9.0", "test-exclude": "^7.0.1", "tinyrainbow": "^2.0.0" }, @@ -5991,8 +6010,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "3.0.9", - "vitest": "3.0.9" + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -6001,14 +6020,15 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", - "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.9", - "@vitest/utils": "3.0.9", + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -6017,13 +6037,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", - "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.9", + "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -6032,7 +6052,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { "msw": { @@ -6054,9 +6074,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", - "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, "license": "MIT", "dependencies": { @@ -6067,27 +6087,28 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", - "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.9", - "pathe": "^2.0.3" + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", - "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.9", + "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -6096,49 +6117,49 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", - "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, "license": "MIT", "dependencies": { - "tinyspy": "^3.0.2" + "tinyspy": "^4.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/ui": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-3.0.9.tgz", - "integrity": "sha512-FpZD4aIv/qNpwkV3XbLV6xldWFHMgoNWAJEgg5GmpObmAOLAErpYjew9dDwXdYdKOS3iZRKdwI+P3JOJcYeUBg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-3.2.4.tgz", + "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.9", + "@vitest/utils": "3.2.4", "fflate": "^0.8.2", "flatted": "^3.3.3", "pathe": "^2.0.3", "sirv": "^3.0.1", - "tinyglobby": "^0.2.12", + "tinyglobby": "^0.2.14", "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "3.0.9" + "vitest": "3.2.4" } }, "node_modules/@vitest/utils": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", - "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.9", - "loupe": "^3.1.3", + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, "funding": { @@ -6618,6 +6639,35 @@ "dev": true, "license": "MIT" }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.8.tgz", + "integrity": "sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -6719,9 +6769,9 @@ } }, "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.0.tgz", + "integrity": "sha512-zt40Pz4zcRXra9CVV31KeyofwiNvAbJ5B6YPz9pMJ+yOSLikvPT4Yi5LjfgjRa9CawVYBaD1JQzIVcIvBejKeA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -7098,9 +7148,9 @@ } }, "node_modules/chai": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", "dev": true, "license": "MIT", "dependencies": { @@ -7111,7 +7161,7 @@ "pathval": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/chalk": { @@ -7753,9 +7803,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -8392,9 +8442,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "dev": true, "license": "MIT" }, @@ -9176,9 +9226,9 @@ } }, "node_modules/expect-type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", - "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11834,9 +11884,9 @@ } }, "node_modules/loupe": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", - "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", "dev": true, "license": "MIT" }, @@ -13313,9 +13363,9 @@ "license": "MIT" }, "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", "dev": true, "license": "MIT", "engines": { @@ -15371,9 +15421,9 @@ } }, "node_modules/sirv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", "dependencies": { @@ -15537,9 +15587,9 @@ } }, "node_modules/std-env": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", - "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, @@ -15814,6 +15864,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/stylelint": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.15.0.tgz", @@ -16388,9 +16458,9 @@ } }, "node_modules/tinypool": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", - "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, "license": "MIT", "engines": { @@ -16408,9 +16478,9 @@ } }, "node_modules/tinyspy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", - "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", "dev": true, "license": "MIT", "engines": { @@ -16945,9 +17015,9 @@ } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", "dependencies": { @@ -17020,17 +17090,17 @@ } }, "node_modules/vite-node": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", - "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", - "debug": "^4.4.0", - "es-module-lexer": "^1.6.0", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" @@ -17099,31 +17169,34 @@ } }, "node_modules/vitest": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", - "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.9", - "@vitest/mocker": "3.0.9", - "@vitest/pretty-format": "^3.0.9", - "@vitest/runner": "3.0.9", - "@vitest/snapshot": "3.0.9", - "@vitest/spy": "3.0.9", - "@vitest/utils": "3.0.9", + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", - "debug": "^4.4.0", - "expect-type": "^1.1.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", - "std-env": "^3.8.0", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", - "tinypool": "^1.0.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "bin": { @@ -17139,8 +17212,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.9", - "@vitest/ui": "3.0.9", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, diff --git a/ui/package.json b/ui/package.json index de59eb82dc..ac22e5449a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -36,7 +36,7 @@ "@tanstack/react-virtual": "^3.10.8", "@vkontakte/icons": "^2.148.0", "@vkontakte/vkui": "^7.1.2", - "axios": "^1.11.0", + "axios": "^1.12.0", "classnames": "^2.5.1", "console-feed": "^3.8.0", "date-fns": "^4.1.0", @@ -75,8 +75,8 @@ "@types/react-slider": "^1.3.6", "@types/wicg-file-system-access": "^2023.10.5", "@vitejs/plugin-react-swc": "^3.5.0", - "@vitest/coverage-v8": "^3.0.9", - "@vitest/ui": "^3.0.9", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/ui": "^3.2.4", "eslint": "^9.11.1", "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-fp": "^2.3.0", @@ -103,7 +103,7 @@ "typescript": "^5.5.3", "typescript-eslint": "^8.16.0", "typescript-plugin-css-modules": "^5.1.0", - "vite": "^6.2.2", + "vite": "^6.4.1", "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^5.0.1", "vitest": "^3.0.9" From c5c17a5051d7dbacb2a425ec7357a752882406bb Mon Sep 17 00:00:00 2001 From: "e.khalilov" Date: Mon, 17 Nov 2025 16:14:42 +0300 Subject: [PATCH 4/5] vnc for android device --- lib/cli/device/index.js | 8 +- lib/cli/provider/index.js | 10 +- lib/units/base-device/support/connector.js | 2 +- lib/units/device/index.ts | 33 +- lib/units/device/plugins/cleanup.js | 69 -- lib/units/device/plugins/cleanup.ts | 78 ++ lib/units/device/plugins/group.ts | 5 - lib/units/device/plugins/screen/stream.js | 618 -------------- lib/units/device/plugins/screen/stream.ts | 757 ++++++++++++++++++ .../device/plugins/screen/util/banner.js | 104 --- .../device/plugins/screen/util/banner.ts | 106 +++ .../plugins/screen/util/broadcastset.js | 39 - .../plugins/screen/util/broadcastset.ts | 81 ++ .../device/plugins/screen/util/frameconfig.js | 13 - .../device/plugins/screen/util/frameconfig.ts | 33 + .../device/plugins/screen/util/frameparser.js | 63 -- .../device/plugins/screen/util/frameparser.ts | 74 ++ lib/units/device/plugins/touch/index.ts | 80 +- lib/units/device/plugins/vnc/index.js | 242 ------ lib/units/device/plugins/vnc/index.ts | 561 +++++++++++++ .../device/plugins/vnc/util/connection.js | 465 ----------- .../device/plugins/vnc/util/connection.ts | 753 +++++++++++++++++ .../device/plugins/vnc/util/pixelformat.js | 13 - .../device/plugins/vnc/util/pixelformat.ts | 41 + .../plugins/vnc/util/pointertranslator.js | 58 -- .../plugins/vnc/util/pointertranslator.ts | 79 ++ lib/units/device/plugins/vnc/util/server.js | 40 - lib/units/device/plugins/vnc/util/server.ts | 66 ++ lib/units/device/resources/scrcpy.js | 2 +- lib/wire/util.ts | 2 +- 30 files changed, 2706 insertions(+), 1789 deletions(-) delete mode 100644 lib/units/device/plugins/cleanup.js create mode 100644 lib/units/device/plugins/cleanup.ts delete mode 100644 lib/units/device/plugins/screen/stream.js create mode 100644 lib/units/device/plugins/screen/stream.ts delete mode 100644 lib/units/device/plugins/screen/util/banner.js create mode 100644 lib/units/device/plugins/screen/util/banner.ts delete mode 100644 lib/units/device/plugins/screen/util/broadcastset.js create mode 100644 lib/units/device/plugins/screen/util/broadcastset.ts delete mode 100644 lib/units/device/plugins/screen/util/frameconfig.js create mode 100644 lib/units/device/plugins/screen/util/frameconfig.ts delete mode 100644 lib/units/device/plugins/screen/util/frameparser.js create mode 100644 lib/units/device/plugins/screen/util/frameparser.ts delete mode 100644 lib/units/device/plugins/vnc/index.js create mode 100644 lib/units/device/plugins/vnc/index.ts delete mode 100644 lib/units/device/plugins/vnc/util/connection.js create mode 100644 lib/units/device/plugins/vnc/util/connection.ts delete mode 100644 lib/units/device/plugins/vnc/util/pixelformat.js create mode 100644 lib/units/device/plugins/vnc/util/pixelformat.ts delete mode 100644 lib/units/device/plugins/vnc/util/pointertranslator.js create mode 100644 lib/units/device/plugins/vnc/util/pointertranslator.ts delete mode 100644 lib/units/device/plugins/vnc/util/server.js create mode 100644 lib/units/device/plugins/vnc/util/server.ts diff --git a/lib/cli/device/index.js b/lib/cli/device/index.js index f8d1069ffb..49eddf59f5 100644 --- a/lib/cli/device/index.js +++ b/lib/cli/device/index.js @@ -168,6 +168,11 @@ export const builder = function(yargs) { type: 'boolean', default: false }) + .option('need-vnc', { + describe: 'Need a running VNC server', + type: 'boolean', + default: false + }) .option('device-name', { describe: 'Device name', type: 'string', @@ -240,6 +245,7 @@ export const handler = function(argv) { urlWithoutAdbPort: argv.urlWithoutAdbPort, deviceCode: argv.deviceCode, secret: argv.secret, - disableLogsOverWire: argv.disableLogsOverWire + disableLogsOverWire: argv.disableLogsOverWire, + needVnc: argv.needVnc }) } diff --git a/lib/cli/provider/index.js b/lib/cli/provider/index.js index ff19d4e07c..4c5121a10f 100644 --- a/lib/cli/provider/index.js +++ b/lib/cli/provider/index.js @@ -172,6 +172,11 @@ export const builder = function(yargs) { type: 'boolean', default: false }) + .option('need-vnc', { + describe: 'Need a running VNC server', + type: 'boolean', + default: false + }) .option('vnc-port', { describe: 'Port allocated to VNC connections.', type: 'number', @@ -240,7 +245,7 @@ export const handler = function(argv) { }, allowRemote: argv.allowRemote, fork: function(device, ports) { - var args = [ + const args = [ 'device', '--serial', device.serial, '--device-name', argv.deviceName, @@ -268,7 +273,8 @@ export const handler = function(argv) { '--url-without-adb-port', argv.urlWithoutAdbPort, '--device-code', argv.deviceCode, '--secret', argv.secret, - '--disable-logs-over-wire', argv.disableLogsOverWire + '--disable-logs-over-wire', argv.disableLogsOverWire, + '--need-vnc', argv.needVnc ] .concat(argv.connectSub.reduce(function(all, val) { return all.concat(['--connect-sub', val]) diff --git a/lib/units/base-device/support/connector.js b/lib/units/base-device/support/connector.js index 4e48ca0bd6..5010d0dc1d 100755 --- a/lib/units/base-device/support/connector.js +++ b/lib/units/base-device/support/connector.js @@ -44,7 +44,7 @@ export default syrup.serial() /** @param {ConnectorInitOptions} opt*/ init({handlers, serial, storageUrl, deviceType, urlWithoutAdbPort}) { - this.handlers = handlers + this.handlers = {start: handlers.start, stop: handlers.stop} this.serial = serial this.reply = wireutil.reply(serial) this.storageUrl = storageUrl diff --git a/lib/units/device/index.ts b/lib/units/device/index.ts index 449935d910..01c0916bfc 100644 --- a/lib/units/device/index.ts +++ b/lib/units/device/index.ts @@ -28,12 +28,13 @@ import sd from './plugins/sd.js' import filesystem from './plugins/filesystem.js' import mobileService from './plugins/mobile-service.js' import remotedebug from './plugins/remotedebug.js' +import vnc from './plugins/vnc/index.js' import {trackModuleReadyness} from './readyness.js' -import wireutil from '../../wire/util.js' -import wire from '../../wire/index.js' +import wireutil, {DEVICE_STATUS_MAP} from '../../wire/util.js' import push from '../base-device/support/push.js' import adb from './support/adb.js' import router from '../base-device/support/router.js' +import {DeviceIntroductionMessage, DeviceRegisteredMessage, ProviderMessage} from "../../wire/wire.js"; export default (function(options: any) { return syrup.serial() @@ -51,7 +52,7 @@ export default (function(options: any) { let listener: ((...args: any[]) => void) | null = null const waitRegister = Promise.race([ new Promise(resolve => - router.on(wire.DeviceRegisteredMessage, listener = (...args: any[]) => resolve(args)) + router.on(DeviceRegisteredMessage, listener = (...args: any[]) => resolve(args)) ), new Promise(r => setTimeout(r, 15000)) ]) @@ -59,11 +60,20 @@ export default (function(options: any) { const type = await adb.getDevice(options.serial).getState() push?.send([ wireutil.global, - wireutil.envelope(new wire.DeviceIntroductionMessage(options.serial, wireutil.toDeviceStatus(type), new wire.ProviderMessage(solo.channel, `standalone-${options.serial}`))) + wireutil.pack(DeviceIntroductionMessage, { + serial: options.serial, + + // TODO: Verify that @u4/adbkit statuses are correct + status: wireutil.toDeviceStatus(type as keyof typeof DEVICE_STATUS_MAP), + provider: ProviderMessage.create({ + channel: solo.channel, + name: `standalone-${options.serial}` + }) + }) ]) await waitRegister - router.removeListener(wire.DeviceRegisteredMessage, listener!) + router.removeListener(DeviceRegisteredMessage, listener!) listener = null } @@ -72,17 +82,18 @@ export default (function(options: any) { .dependency(trackModuleReadyness('stream', stream)) .dependency(trackModuleReadyness('capture', capture)) .dependency(trackModuleReadyness('service', service)) + .dependency(trackModuleReadyness('shell', shell)) + .dependency(trackModuleReadyness('touch', touch)) + .dependency(trackModuleReadyness('group', group)) + .dependency(trackModuleReadyness('vnc', vnc)) .dependency(trackModuleReadyness('browser', browser)) .dependency(trackModuleReadyness('store', store)) .dependency(trackModuleReadyness('airplane', airplane)) .dependency(trackModuleReadyness('clipboard', clipboard)) .dependency(trackModuleReadyness('logcat', logcat)) .dependency(trackModuleReadyness('mute', mute)) - .dependency(trackModuleReadyness('shell', shell)) - .dependency(trackModuleReadyness('touch', touch)) .dependency(trackModuleReadyness('install', install)) .dependency(trackModuleReadyness('forward', forward)) - .dependency(trackModuleReadyness('group', group)) .dependency(trackModuleReadyness('cleanup', cleanup)) .dependency(trackModuleReadyness('reboot', reboot)) .dependency(trackModuleReadyness('connect', connect)) @@ -94,7 +105,11 @@ export default (function(options: any) { .dependency(trackModuleReadyness('filesystem', filesystem)) .dependency(trackModuleReadyness('mobileService', mobileService)) .dependency(trackModuleReadyness('remotedebug', remotedebug)) - .define((options, heartbeat) => { + .define((options, heartbeat, stream, capture, service, shell, touch, group, vnc) => { + if (options.needVnc) { + vnc.start() + } + if (process.send) { // Only if we have a parent process process.send('ready') diff --git a/lib/units/device/plugins/cleanup.js b/lib/units/device/plugins/cleanup.js deleted file mode 100644 index a80c7f1dc2..0000000000 --- a/lib/units/device/plugins/cleanup.js +++ /dev/null @@ -1,69 +0,0 @@ -import syrup from '@devicefarmer/stf-syrup' -import Promise from 'bluebird' -import _ from 'lodash' -import logger from '../../../util/logger.js' -import adb from '../support/adb.js' -import service from '../resources/service.js' -import group from './group.js' -import service$0 from './service.js' -export default syrup.serial() - .dependency(adb) - .dependency(service) - .dependency(group) - .dependency(service$0) - .define(function(options, adb, stfservice, group, service) { - var log = logger.createLogger('device:plugins:cleanup') - var plugin = Object.create(null) - if (!options.cleanup) { - return plugin - } - function listPackages() { - return Promise.resolve().then(async() => await adb.getDevice(options.serial).getPackages()) - } - function uninstallPackage(pkg) { - log.info('Cleaning up package "%s"', pkg) - return adb.getDevice(options.serial).uninstall(pkg) - .catch(function(err) { - log.warn('Unable to clean up package "%s"', pkg, err) - return true - }) - } - return listPackages() - .then(function(initialPackages) { - initialPackages.push(stfservice.pkg) - plugin.removePackages = function() { - return listPackages() - .then(function(currentPackages) { - var remove = _.difference(currentPackages, initialPackages) - return Promise.map(remove, uninstallPackage) - }) - } - plugin.disableBluetooth = function() { - if (!options.cleanupDisableBluetooth) { - return - } - return service.getBluetoothStatus() - .then(function(enabled) { - if (enabled) { - log.info('Disabling Bluetooth') - return service.setBluetoothEnabled(false) - } - }) - } - plugin.cleanBluetoothBonds = function() { - if (!options.cleanupBluetoothBonds) { - return - } - log.info('Cleanup Bluetooth bonds') - return service.cleanBluetoothBonds() - } - group.on('leave', function() { - Promise.all([ - plugin.removePackages(), - plugin.cleanBluetoothBonds(), - plugin.disableBluetooth() - ]) - }) - }) - .return(plugin) - }) diff --git a/lib/units/device/plugins/cleanup.ts b/lib/units/device/plugins/cleanup.ts new file mode 100644 index 0000000000..429f8a1356 --- /dev/null +++ b/lib/units/device/plugins/cleanup.ts @@ -0,0 +1,78 @@ +import syrup from '@devicefarmer/stf-syrup' +import logger from '../../../util/logger.js' +import adb from '../support/adb.js' +import group from './group.js' +import service$0 from './service.js' + +export default syrup.serial() + .dependency(adb) + .dependency(group) + .dependency(service$0) + .define(async(options, adb, group, service) => { + if (!options.cleanup) { + return + } + + const log = logger.createLogger('device:plugins:cleanup') + + const getInstalledApps = async() => ( + await adb.getDevice(options.serial).execOut('pm list packages -3') || '' + ) + .toString() + .trim() + .split('\n') + .map(pkg => pkg.trim().substring(8)) + + const checkpoint = await getInstalledApps() + log.info('Saved checkpoint of installed apps: %s', checkpoint.join(', ')) + + const uninstall = (pkg: string) => { + try { + log.info('Cleaning up package "%s"', pkg) + return adb.getDevice(options.serial).uninstall(pkg) + } catch (err: any) { + log.warn('Unable to clean up package "%s": %s', pkg, err?.message) + } + } + + const removePackages = async() => { + const apps = await getInstalledApps() + const newApps = apps.filter(app => !checkpoint.includes(app)) + + if (!newApps.length) return + log.info('Cleaning: %s', newApps.join(', ')) + + for (const pkg of newApps) { + await uninstall(pkg) + } + + log.info('Cleaning completed') + } + + const disableBluetooth = async() => { + if (!options.cleanupDisableBluetooth) { + return + } + + const enabled = await service.getBluetoothStatus() + if (enabled) { + log.info('Disabling Bluetooth') + return service.setBluetoothEnabled(false) + } + } + + const cleanBluetoothBonds = () => { + if (!options.cleanupBluetoothBonds) { + return + } + + log.info('Cleanup Bluetooth bonds') + return service.cleanBluetoothBonds() + } + + group.on('leave', async() => { + await removePackages() + await cleanBluetoothBonds() + await disableBluetooth() + }) + }) diff --git a/lib/units/device/plugins/group.ts b/lib/units/device/plugins/group.ts index c628918805..361d19024b 100644 --- a/lib/units/device/plugins/group.ts +++ b/lib/units/device/plugins/group.ts @@ -59,11 +59,6 @@ export default syrup.serial() service.sendCommand('pm clear com.android.chrome'), service.sendCommand('pm clear com.chrome.beta'), service.sendCommand('pm clear com.sec.android.app.sbrowser'), - service.sendCommand('pm uninstall com.vkontakte.android'), - service.sendCommand('pm uninstall com.vk.im'), - service.sendCommand('pm uninstall com.vk.clips'), - service.sendCommand('pm uninstall com.vk.calls'), - service.sendCommand('pm uninstall com.vk.admin'), service.sendCommand('pm clear com.mi.globalbrowser'), service.sendCommand('pm clear com.microsoft.emmx'), service.sendCommand('pm clear com.huawei.browser'), diff --git a/lib/units/device/plugins/screen/stream.js b/lib/units/device/plugins/screen/stream.js deleted file mode 100644 index 5305c28868..0000000000 --- a/lib/units/device/plugins/screen/stream.js +++ /dev/null @@ -1,618 +0,0 @@ -import util from 'util' -import Promise from 'bluebird' -import syrup from '@devicefarmer/stf-syrup' -import WebSocket from 'ws' -import {v4 as uuidv4} from 'uuid' -import EventEmitter from 'eventemitter3' -import split from 'split' -import {Adb} from '@u4/adbkit' -import logger from '../../../../util/logger.js' -import lifecycle from '../../../../util/lifecycle.js' -import * as bannerutil from './util/banner.js' -import FrameParser from './util/frameparser.js' -import FrameConfig from './util/frameconfig.js' -import BroadcastSet from './util/broadcastset.js' -import StateQueue from '../../../../util/statequeue.js' -import RiskyStream from '../../../../util/riskystream.js' -import FailCounter from '../../../../util/failcounter.js' -import wire from '../../../../wire/index.js' -import adb from '../../support/adb.js' -import router from '../../../base-device/support/router.js' -import minicap from '../../resources/minicap.js' -import scrcpy from '../../resources/scrcpy.js' -import display from '../util/display.js' -import options from './options.js' -import group from '../group.js' -import * as jwtutil from '../../../../util/jwtutil.js' -import {NoGroupError} from '../../../../util/grouputil.js' -import {ChangeQualityMessage} from '../../../../wire/wire.js' -export default syrup.serial() - .dependency(adb) - .dependency(router) - .dependency(minicap) - .dependency(scrcpy) - .dependency(display) - .dependency(options) - .dependency(group) - .define(function(options, adb, router, minicap, scrcpy, display, screenOptions, group) { - let log = logger.createLogger('device:plugins:screen:stream') - log.info('ScreenGrabber option set to %s', options.screenGrabber) - log.info('ScreenFrameRate option set to %d', options.screenFrameRate) - const scrcpyClient = new scrcpy.Scrcpy() - function FrameProducer(config, grabber) { - EventEmitter.call(this) - this.actionQueue = [] - this.runningState = FrameProducer.STATE_STOPPED - this.desiredState = new StateQueue() - this.output = null - this.socket = null - this.pid = -1 - this.banner = null - this.parser = null - this.frameConfig = config - this.grabber = options.screenGrabber - this.readable = false - this.needsReadable = false - this.failCounter = new FailCounter(3, 10000) - this.failCounter.on('exceedLimit', this._failLimitExceeded.bind(this)) - this.failed = false - this.readableListener = this._readableListener.bind(this) - } - util.inherits(FrameProducer, EventEmitter) - FrameProducer.STATE_STOPPED = 1 - FrameProducer.STATE_STARTING = 2 - FrameProducer.STATE_STARTED = 3 - FrameProducer.STATE_STOPPING = 4 - FrameProducer.prototype._ensureState = function() { - if (this.desiredState.empty()) { - return - } - if (this.failed) { - log.warn('Will not apply desired state due to too many failures') - return - } - switch (this.runningState) { - case FrameProducer.STATE_STARTING: - case FrameProducer.STATE_STOPPING: - // Just wait. - break - case FrameProducer.STATE_STOPPED: - if (this.desiredState.next() === FrameProducer.STATE_STARTED) { - this.runningState = FrameProducer.STATE_STARTING - if (options.needScrcpy) { - scrcpyClient.start() - .then((function() { - this.runningState = FrameProducer.STATE_STARTED - this.emit('start') - }).bind(this)) - } - else { - this._startService().bind(this) - .then(function(out) { - this.output = new RiskyStream(out) - .on('unexpectedEnd', this._outputEnded.bind(this)) - return this._readOutput(this.output.stream) - }) - .then(function() { - return this._waitForPid() - }) - .then(function() { - return this._connectService() - }) - .then(function(socket) { - this.parser = new FrameParser() - this.socket = new RiskyStream(socket) - .on('unexpectedEnd', this._socketEnded.bind(this)) - return this._readBanner(this.socket.stream) - }) - .then(function(banner) { - this.banner = banner - return this._readFrames(this.socket.stream) - }) - .then(function() { - this.runningState = FrameProducer.STATE_STARTED - this.emit('start') - }) - .catch(Promise.CancellationError, function() { - return this._stop() - }) - .catch(function(err) { - return this._stop().finally(function() { - this.failCounter.inc() - this.grabber = 'minicap-apk' - }) - }) - .finally(function() { - this._ensureState() - }) - } - } - else { - setImmediate(this._ensureState.bind(this)) - } - break - case FrameProducer.STATE_STARTED: - if (this.desiredState.next() === FrameProducer.STATE_STOPPED) { - this.runningState = FrameProducer.STATE_STOPPING - this._stop().finally(function() { - this._ensureState() - }) - } - else { - setImmediate(this._ensureState.bind(this)) - } - break - } - } - FrameProducer.prototype.start = function() { - log.info('Requesting frame producer to start') - this.desiredState.push(FrameProducer.STATE_STARTED) - this._ensureState() - } - FrameProducer.prototype.stop = function() { - log.info('Requesting frame producer to stop') - this.desiredState.push(FrameProducer.STATE_STOPPED) - this._ensureState() - } - FrameProducer.prototype.restart = function() { - switch (this.runningState) { - case FrameProducer.STATE_STARTED: - case FrameProducer.STATE_STARTING: - this.desiredState.push(FrameProducer.STATE_STOPPED) - this.desiredState.push(FrameProducer.STATE_STARTED) - this._ensureState() - break - } - } - FrameProducer.prototype.updateRotation = function(rotation) { - if (this.frameConfig.rotation === rotation) { - log.info('Keeping %d as current frame producer rotation', rotation) - return - } - log.info('Setting frame producer rotation to %d', rotation) - this.frameConfig.rotation = rotation - this._configChanged() - } - FrameProducer.prototype.changeQuality = function(newQuality) { - log.info('Setting frame producer quality to %d', newQuality) - this.frameConfig.quality = newQuality - this._configChanged() - } - FrameProducer.prototype.updateProjection = function(width, height) { - if (this.frameConfig.virtualWidth === width && - this.frameConfig.virtualHeight === height) { - log.info('Keeping %dx%d as current frame producer projection', width, height) - return - } - log.info('Setting frame producer projection to %dx%d', width, height) - this.frameConfig.virtualWidth = width - this.frameConfig.virtualHeight = height - this._configChanged() - } - FrameProducer.prototype.nextFrame = function() { - var frame = null - var chunk - if (this.parser) { - while ((frame = this.parser.nextFrame()) === null) { - chunk = this.socket.stream.read() - if (chunk) { - this.parser.push(chunk) - } - else { - this.readable = false - break - } - } - } - return frame - } - FrameProducer.prototype.needFrame = function() { - this.needsReadable = true - this._maybeEmitReadable() - } - FrameProducer.prototype._configChanged = function() { - this.restart() - } - FrameProducer.prototype._socketEnded = function() { - log.warn('Connection to minicap ended unexpectedly') - this.failCounter.inc() - this.restart() - } - FrameProducer.prototype._outputEnded = function() { - log.warn('Shell keeping minicap running ended unexpectedly') - this.failCounter.inc() - this.restart() - } - FrameProducer.prototype._failLimitExceeded = function(limit, time) { - this._stop() - this.failed = true - this.emit('error', new Error(util.format('Failed more than %d times in %dms', limit, time))) - } - FrameProducer.prototype._startService = function() { - log.info('Launching screen service %s', this.grabber) - if (options.screenFrameRate <= 0.0) { - return minicap.run(this.grabber, util.format('-S -Q %d -P %s', this.frameConfig.quality, this.frameConfig.toString())) - .timeout(10000) - } - else { - return minicap.run(this.grabber, util.format('-S -r %d -Q %d -P %s', options.screenFrameRate, this.frameConfig.quality, this.frameConfig.toString())) - .timeout(10000) - } - } - FrameProducer.prototype._readOutput = function(out) { - out.pipe(split()).on('data', function(line) { - var trimmed = line.toString().trim() - if (trimmed === '') { - return - } - if (/ERROR/.test(line)) { - log.fatal('minicap error: "%s"', line) - return lifecycle.fatal() - } - var match = /^PID: (\d+)$/.exec(line) - if (match) { - this.pid = Number(match[1]) - this.emit('pid', this.pid) - } - log.info('minicap says: "%s"', line) - }.bind(this)) - } - FrameProducer.prototype._waitForPid = function() { - if (this.pid > 0) { - return Promise.resolve(this.pid) - } - var pidListener - return new Promise(function(resolve) { - this.on('pid', pidListener = resolve) - }.bind(this)).bind(this) - .timeout(5000) - .finally(function() { - this.removeListener('pid', pidListener) - }) - } - FrameProducer.prototype._connectService = function() { - function tryConnect(times, delay) { - return adb.getDevice(options.serial).openLocal('localabstract:minicap') - .then(function(out) { - return out - }) - .catch(function(err) { - if (/closed/.test(err.message) && times > 1) { - return Promise.delay(delay) - .then(function() { - log.info('Retrying connect to minicap service') - return tryConnect(times - 1, delay + 100) // non exp, if need exponential use - delay * 2 - }) - } - return Promise.reject(err) - }) - } - log.info('Connecting to minicap service') - return tryConnect(10, 100) - } - FrameProducer.prototype._stop = function() { - return this._disconnectService(this.socket).bind(this) - .timeout(2000) - .then(function() { - return this._stopService(this.output).timeout(10000) - }) - .then(function() { - this.runningState = FrameProducer.STATE_STOPPED - this.emit('stop') - }) - .catch(function(err) { - // In practice we _should_ never get here due to _stopService() - // being quite aggressive. But if we do, well... assume it - // stopped anyway for now. - this.runningState = FrameProducer.STATE_STOPPED - this.emit('error', err) - this.emit('stop') - }) - .finally(function() { - this.output = null - this.socket = null - this.pid = -1 - this.banner = null - this.parser = null - }) - } - FrameProducer.prototype._disconnectService = function(socket) { - log.info('Disconnecting from minicap service') - if (!socket || socket.ended) { - return Promise.resolve(true) - } - socket.stream.removeListener('readable', this.readableListener) - var endListener - return new Promise(function(resolve) { - socket.on('end', endListener = function() { - resolve(true) - }) - socket.stream.resume() - socket.end() - }) - .finally(function() { - socket.removeListener('end', endListener) - }) - } - FrameProducer.prototype._stopService = function(output) { - log.info('Stopping minicap service') - if (!output || output.ended) { - return Promise.resolve(true) - } - var pid = this.pid - function kill(signal) { - if (pid <= 0) { - return Promise.reject(new Error('Minicap service pid is unknown')) - } - var signum = { - SIGTERM: -15, - SIGKILL: -9 - }[signal] - log.info('Sending %s to minicap', signal) - return Promise.all([ - output.waitForEnd(), - adb.getDevice(options.serial).shell(['kill', signum, pid]) - .then(Adb.util.readAll) - ]) - .timeout(2000) - } - function kindKill() { - return kill('SIGTERM') - } - function forceKill() { - return kill('SIGKILL') - } - function forceEnd() { - log.info('Ending minicap I/O as a last resort') - output.end() - return Promise.resolve(true) - } - return kindKill() - .catch(Promise.TimeoutError, forceKill) - .catch(forceEnd) - } - FrameProducer.prototype._readBanner = function(socket) { - log.info('Reading minicap banner') - return bannerutil.read(socket).timeout(2000) - } - FrameProducer.prototype._readFrames = function(socket) { - this.needsReadable = true - socket.on('readable', this.readableListener) - // We may already have data pending. Let the user know they should - // at least attempt to read frames now. - this.readableListener() - } - FrameProducer.prototype._maybeEmitReadable = function() { - if (this.readable && this.needsReadable) { - this.needsReadable = false - this.emit('readable') - } - } - FrameProducer.prototype._readableListener = function() { - this.readable = true - this._maybeEmitReadable() - } - function createServer() { - log.info('Starting WebSocket server on port %d', screenOptions.publicPort) - var wss = new WebSocket.Server({ - port: screenOptions.publicPort, - perMessageDeflate: false - }) - var listeningListener, errorListener - return new Promise(function(resolve, reject) { - listeningListener = function() { - return resolve(wss) - } - errorListener = function(err) { - return reject(err) - } - wss.on('listening', listeningListener) - wss.on('error', errorListener) - }) - .finally(function() { - wss.removeListener('listening', listeningListener) - wss.removeListener('error', errorListener) - }) - } - return createServer() - .then(function(wss) { - log.info('creating FrameProducer: %s', options.screenGrabber) - var frameProducer = new FrameProducer(new FrameConfig(display.properties, display.properties, options.screenJpegQuality)) - var broadcastSet = frameProducer.broadcastSet = new BroadcastSet() - broadcastSet.on('nonempty', function() { - frameProducer.start() - }) - broadcastSet.on('empty', function() { - frameProducer.stop() - }) - broadcastSet.on('insert', function(id) { - // If two clients join a session in the middle, one of them - // may not release the initial size because the projection - // doesn't necessarily change, and the producer doesn't Getting - // restarted. Therefore we have to call onStart() manually - // if the producer is already up and running. - switch (frameProducer.runningState) { - case FrameProducer.STATE_STARTED: - broadcastSet.get(id).onStart(frameProducer) - break - } - }) - display.on('rotationChange', function(newRotation) { - frameProducer.updateRotation(newRotation) - }) - router.on(ChangeQualityMessage, function(channel, message) { - frameProducer.changeQuality(message.quality) - }) - frameProducer.on('start', function() { - broadcastSet.keys().map(function(id) { - return broadcastSet.get(id).onStart(frameProducer) - }) - }) - frameProducer.on('readable', function next() { - var frame = frameProducer.nextFrame() - if (frame) { - Promise.settle([broadcastSet.keys().map(function(id) { - return broadcastSet.get(id).onFrame(frame) - })]).then(next) - } - else { - frameProducer.needFrame() - } - }) - frameProducer.on('error', function(err) { - log.fatal('Frame producer had an error', err.stack) - lifecycle.fatal() - }) - wss.on('connection', async function(ws, req) { - let id = uuidv4() - let pingTimer - - // Extract token from WebSocket subprotocols - const token = ws.protocol.substring('access_token.'.length) - const user = !!token && jwtutil.decode(token, options.secret) - - if (!token || !user) { - log.warn('WebSocket connection attempt without token from %s', req.socket.remoteAddress) - ws.send(JSON.stringify({ - type: 'auth_error', - message: 'Authentication token required' - })) - ws.close(1008, 'Authentication token required') - return - } - - const tryCheckDeviceGroup = async(fail = false) => { - try { - await new Promise(r => setTimeout(r, 200)) - - const deviceGroup = await group.get() - if (deviceGroup.email !== user?.email) { - const err = 'Device used by another user' - log.warn('WebSocket authentication failed for device %s: $s', options.serial, err) - ws.send(JSON.stringify({ - type: 'auth_error', - message: err - })) - ws.close(1008, 'Authentication failed') - return - } - - log.info('WebSocket authenticated for device %s', options.serial) - - // Send success message - ws.send(JSON.stringify({ - type: 'auth_success', - message: 'Authentication successful' - })) - - // Sending a ping message every now and then makes sure that - // reverse proxies like nginx don't time out the connection [1]. - // - // [1] http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout - pingTimer = setInterval(wsPingNotifier, 10 * 60000) // options.screenPingInterval - } - catch (/** @type {any} */err) { - if (!fail && err instanceof NoGroupError) { - await new Promise(r => setTimeout(r, 1000)) - return tryCheckDeviceGroup(true) - } - - log.error('WebSocket authentication error for device %s: %s', options.serial, err.message) - ws.send(JSON.stringify({ - type: 'auth_error', - message: 'Authentication error' - }), () => {}) - ws.close(1008, 'Authentication error') - } - } - - await tryCheckDeviceGroup() - - function send(message, options) { - return new Promise(function(resolve, reject) { - switch (ws.readyState) { - case WebSocket.OPENING: - // This should never happen. - log.warn('Unable to send to OPENING client "%s"', id) - break - case WebSocket.OPEN: - // This is what SHOULD happen. - ws.send(message, options, function(err) { - return err ? reject(err) : resolve() - }) - break - case WebSocket.CLOSING: - // Ok, a 'close' event should remove the client from the set - // soon. - break - case WebSocket.CLOSED: - // This should never happen. - log.warn('Unable to send to CLOSED client "%s"', id) - clearInterval(pingTimer) - broadcastSet.remove(id) - break - } - }) - } - function wsStartNotifier() { - return send(util.format('start %s', JSON.stringify(frameProducer.banner))) - } - function wsPingNotifier() { - return send('ping') - } - function wsFrameNotifier(frame) { - return send(frame, { - binary: true - }) - } - ws.on('message', function(data) { - var match = /^(on|off|(size) ([0-9]+)x([0-9]+))$/.exec(data) - if (match) { - switch (match[2] || match[1]) { - case 'on': - broadcastSet.insert(id, { - onStart: wsStartNotifier, - onFrame: wsFrameNotifier - }) - break - case 'off': - broadcastSet.remove(id) - // Keep pinging even when the screen is off. - break - case 'size': - frameProducer.updateProjection(Number(match[3]), Number(match[4])) - break - } - } - }) - ws.on('close', function() { - if (pingTimer) { - clearInterval(pingTimer) - } - broadcastSet.remove(id) - log.info('WebSocket closed for device %s', options.serial) - }) - if (options.needScrcpy) { - log.info(`Scrcpy client has gotten for device s/n ${options.serial}`) - scrcpyClient.on('rawData', (data) => { - console.log(`Data: ${data}`) - send(data, {binary: true}) - }) - } - ws.on('error', function(e) { - if (pingTimer) { - clearInterval(pingTimer) - } - broadcastSet.remove(id) - log.error('WebSocket error for device %s: %s', options.serial, e.message) - }) - }) - lifecycle.observe(function() { - wss.close() - }) - lifecycle.observe(function() { - frameProducer.stop() - }) - return frameProducer - }) - }) diff --git a/lib/units/device/plugins/screen/stream.ts b/lib/units/device/plugins/screen/stream.ts new file mode 100644 index 0000000000..800fe5ede2 --- /dev/null +++ b/lib/units/device/plugins/screen/stream.ts @@ -0,0 +1,757 @@ +import util from 'util' +import syrup from '@devicefarmer/stf-syrup' +import WebSocket from 'ws' +import {v4 as uuidv4} from 'uuid' +import EventEmitter from 'eventemitter3' +import split from 'split' +import {Adb} from '@u4/adbkit' +import {Readable} from 'stream' +import logger from '../../../../util/logger.js' +import lifecycle from '../../../../util/lifecycle.js' +import * as bannerutil from './util/banner.js' +import {Banner} from './util/banner.js' +import FrameParser from './util/frameparser.js' +import FrameConfig from './util/frameconfig.js' +import BroadcastSet from './util/broadcastset.js' +import StateQueue from '../../../../util/statequeue.js' +import RiskyStream from '../../../../util/riskystream.js' +import FailCounter from '../../../../util/failcounter.js' +import adb from '../../support/adb.js' +import router from '../../../base-device/support/router.js' +import minicap from '../../resources/minicap.js' +import scrcpy from '../../resources/scrcpy.js' +import display from '../util/display.js' +import options from './options.js' +import group from '../group.js' +import * as jwtutil from '../../../../util/jwtutil.js' +import {NoGroupError} from '../../../../util/grouputil.js' +import {ChangeQualityMessage} from '../../../../wire/wire.js' + +// Utility functions to replace Bluebird +class TimeoutError extends Error { + constructor(message: string = 'Operation timed out') { + super(message) + this.name = 'TimeoutError' + } +} + +class CancellationError extends Error { + constructor(message: string = 'Promise was cancelled') { + super(message) + this.name = 'CancellationError' + } +} + +function withTimeout(promise: Promise, ms: number): Promise { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new TimeoutError(`Operation timed out after ${ms}ms`)) + }, ms) + + promise + .then((value) => { + clearTimeout(timer) + resolve(value) + }) + .catch((error) => { + clearTimeout(timer) + reject(error) + }) + }) +} + +function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +type FrameProducerState = 1 | 2 | 3 | 4 + +interface ScreenOptions { + publicPort: number + screenPingInterval?: number +} + +interface DeviceOptions { + serial: string + screenGrabber: string + screenFrameRate: number + screenJpegQuality: number + needScrcpy: boolean + secret: string +} + +interface DisplayProperties { + width: number + height: number + rotation: number +} + +export default syrup.serial() + .dependency(adb) + .dependency(router) + .dependency(minicap) + .dependency(scrcpy) + .dependency(display) + .dependency(options) + .dependency(group) + .define((options: DeviceOptions, adb: any, router: any, minicap: any, scrcpy: any, display: any, screenOptions: ScreenOptions, group: any) => { + const log = logger.createLogger('device:plugins:screen:stream') + log.info('ScreenGrabber option set to %s', options.screenGrabber) + log.info('ScreenFrameRate option set to %s', options.screenFrameRate) + const scrcpyClient = new scrcpy.Scrcpy() + + class FrameProducer extends EventEmitter { + static readonly STATE_STOPPED: FrameProducerState = 1 + static readonly STATE_STARTING: FrameProducerState = 2 + static readonly STATE_STARTED: FrameProducerState = 3 + static readonly STATE_STOPPING: FrameProducerState = 4 + + public actionQueue: any[] + public runningState: FrameProducerState + public desiredState: StateQueue + public output: RiskyStream | null + public socket: RiskyStream | null + public pid: number + public banner: Banner | null + public parser: FrameParser | null + public frameConfig: FrameConfig + public grabber: string + public readable: boolean + public needsReadable: boolean + public failCounter: FailCounter + public failed: boolean + public broadcastSet?: BroadcastSet + private readableListener: () => void + + constructor(config: FrameConfig, grabber: string) { + super() + this.actionQueue = [] + this.runningState = FrameProducer.STATE_STOPPED + this.desiredState = new StateQueue() + this.output = null + this.socket = null + this.pid = -1 + this.banner = null + this.parser = null + this.frameConfig = config + this.grabber = options.screenGrabber + this.readable = false + this.needsReadable = false + this.failCounter = new FailCounter(3, 10000) + this.failCounter.on('exceedLimit', this._failLimitExceeded.bind(this)) + this.failed = false + this.readableListener = this._readableListener.bind(this) + } + + private async _ensureState(): Promise { + if (this.desiredState.empty()) { + return + } + + if (this.failed) { + log.warn('Will not apply desired state due to too many failures') + return + } + + switch (this.runningState) { + case FrameProducer.STATE_STARTING: + case FrameProducer.STATE_STOPPING: + // Just wait. + break + case FrameProducer.STATE_STOPPED: + if (this.desiredState.next() === FrameProducer.STATE_STARTED) { + this.runningState = FrameProducer.STATE_STARTING + if (options.needScrcpy) { + try { + await scrcpyClient.start() + this.runningState = FrameProducer.STATE_STARTED + this.emit('start') + } catch (err: any) { + log.error('Scrcpy start failed: %s', err?.message || err) + } + } + else { + try { + const out = await this._startService() + this.output = new RiskyStream(out) + .on('unexpectedEnd', this._outputEnded.bind(this)) + await this._readOutput(this.output.stream) + await this._waitForPid() + const socket = await this._connectService() + this.parser = new FrameParser() + this.socket = new RiskyStream(socket) + .on('unexpectedEnd', this._socketEnded.bind(this)) + const banner = await this._readBanner(this.socket.stream) + this.banner = banner + await this._readFrames(this.socket.stream) + this.runningState = FrameProducer.STATE_STARTED + this.emit('start') + } catch (err) { + if (err instanceof CancellationError) { + await this._stop() + } else { + await this._stop() + this.failCounter.inc() + this.grabber = 'minicap-apk' + } + } finally { + await this._ensureState() + } + } + } + else { + setImmediate(() => this._ensureState()) + } + break + case FrameProducer.STATE_STARTED: + if (this.desiredState.next() === FrameProducer.STATE_STOPPED) { + this.runningState = FrameProducer.STATE_STOPPING + try { + await this._stop() + } finally { + await this._ensureState() + } + } + else { + setImmediate(() => this._ensureState()) + } + break + } + } + + public start(): void { + log.info('Requesting frame producer to start') + this.desiredState.push(FrameProducer.STATE_STARTED) + this._ensureState() + } + + public stop(): void { + log.info('Requesting frame producer to stop') + this.desiredState.push(FrameProducer.STATE_STOPPED) + this._ensureState() + } + + public restart(): void { + switch (this.runningState) { + case FrameProducer.STATE_STARTED: + case FrameProducer.STATE_STARTING: + this.desiredState.push(FrameProducer.STATE_STOPPED) + this.desiredState.push(FrameProducer.STATE_STARTED) + this._ensureState() + break + } + } + + public updateRotation(rotation: number): void { + if (this.frameConfig.rotation === rotation) { + log.info('Keeping %s as current frame producer rotation', rotation) + return + } + log.info('Setting frame producer rotation to %s', rotation) + this.frameConfig.rotation = rotation + this._configChanged() + } + + public changeQuality(newQuality: number): void { + log.info('Setting frame producer quality to %s', newQuality) + this.frameConfig.quality = newQuality + this._configChanged() + } + + public updateProjection(width: number, height: number): void { + if (this.frameConfig.virtualWidth === width && + this.frameConfig.virtualHeight === height) { + log.info('Keeping %sx%s as current frame producer projection', width, height) + return + } + log.info('Setting frame producer projection to %sx%s', width, height) + this.frameConfig.virtualWidth = width + this.frameConfig.virtualHeight = height + this._configChanged() + } + + public nextFrame(): Buffer | null { + let frame: Buffer | null = null + let chunk: Buffer | null + + if (this.parser && this.socket) { + while ((frame = this.parser.nextFrame()) === null) { + chunk = this.socket.stream.read() + if (chunk) { + this.parser.push(chunk) + } + else { + this.readable = false + break + } + } + } + return frame + } + + public needFrame(): void { + this.needsReadable = true + this._maybeEmitReadable() + } + + private _configChanged(): void { + this.restart() + } + + private _socketEnded(): void { + log.warn('Connection to minicap ended unexpectedly') + this.failCounter.inc() + this.restart() + } + + private _outputEnded(): void { + log.warn('Shell keeping minicap running ended unexpectedly') + this.failCounter.inc() + this.restart() + } + + private _failLimitExceeded(limit: number, time: number): void { + this._stop() + this.failed = true + this.emit('error', new Error(util.format('Failed more than %s times in %sms', limit, time))) + } + + private async _startService(): Promise { + log.info('Launching screen service %s', this.grabber) + const args = options.screenFrameRate <= 0.0 + ? util.format('-S -Q %s -P %s', this.frameConfig.quality, this.frameConfig.toString()) + : util.format('-S -r %s -Q %s -P %s', options.screenFrameRate, this.frameConfig.quality, this.frameConfig.toString()) + + return withTimeout(minicap.run(this.grabber, args), 10000) + } + + private _readOutput(out: Readable): Promise { + return new Promise((resolve) => { + out.pipe(split()).on('data', (line: string) => { + const trimmed = line.toString().trim() + if (trimmed === '') { + return + } + if (/ERROR/.test(line)) { + log.fatal('minicap error: "%s"', line) + lifecycle.fatal() + return + } + const match = /^PID: (\d+)$/.exec(line) + if (match) { + this.pid = Number(match[1]) + this.emit('pid', this.pid) + } + log.info('minicap says: "%s"', line) + }) + // Resolve immediately as we're just setting up the pipe + resolve() + }) + } + + private async _waitForPid(): Promise { + if (this.pid > 0) { + return this.pid + } + + return withTimeout( + new Promise((resolve) => { + const pidListener = (pid: number) => { + this.removeListener('pid', pidListener) + resolve(pid) + } + this.on('pid', pidListener) + }), + 5000 + ) + } + + private async _connectService(): Promise { + const tryConnect = async (times: number, delayMs: number): Promise => { + try { + const device = adb.getDevice(options.serial) + return await device.openLocal('localabstract:minicap') + } catch (err: any) { + if (/closed/.test(err.message) && times > 1) { + await delay(delayMs) + log.info('Retrying connect to minicap service') + return tryConnect(times - 1, delayMs + 100) + } + throw err + } + } + + log.info('Connecting to minicap service') + return tryConnect(10, 100) + } + + private async _stop(): Promise { + try { + await withTimeout(this._disconnectService(this.socket), 2000) + await withTimeout(this._stopService(this.output), 10000) + this.runningState = FrameProducer.STATE_STOPPED + this.emit('stop') + } catch (err) { + // In practice we _should_ never get here due to _stopService() + // being quite aggressive. But if we do, well... assume it + // stopped anyway for now. + this.runningState = FrameProducer.STATE_STOPPED + this.emit('error', err) + this.emit('stop') + } finally { + this.output = null + this.socket = null + this.pid = -1 + this.banner = null + this.parser = null + } + } + + private async _disconnectService(socket: RiskyStream | null): Promise { + log.info('Disconnecting from minicap service') + if (!socket || socket.ended) { + return true + } + + socket.stream.removeListener('readable', this.readableListener) + + return new Promise((resolve) => { + const endListener = () => { + socket.removeListener('end', endListener) + resolve(true) + } + socket.on('end', endListener) + socket.stream.resume() + socket.end() + }) + } + + private async _stopService(output: RiskyStream | null): Promise { + log.info('Stopping minicap service') + if (!output || output.ended) { + return true + } + + const pid = this.pid + + const kill = async (signal: 'SIGTERM' | 'SIGKILL'): Promise => { + if (pid <= 0) { + throw new Error('Minicap service pid is unknown') + } + const signum = { + SIGTERM: -15, + SIGKILL: -9 + }[signal] + + log.info('Sending %s to minicap', signal) + const device = adb.getDevice(options.serial) + return withTimeout( + Promise.all([ + output.waitForEnd(), + device.shell(['kill', signum, pid]).then(Adb.util.readAll) + ]), + 2000 + ) + } + + const kindKill = () => kill('SIGTERM') + const forceKill = () => kill('SIGKILL') + const forceEnd = () => { + log.info('Ending minicap I/O as a last resort') + output.end() + return true + } + + try { + await kindKill() + return true + } catch (err) { + if (err instanceof TimeoutError) { + try { + await forceKill() + return true + } catch { + return forceEnd() + } + } + return forceEnd() + } + } + + private async _readBanner(socket: Readable): Promise { + log.info('Reading minicap banner') + return withTimeout(bannerutil.read(socket), 4000) + } + + private async _readFrames(socket: Readable): Promise { + this.needsReadable = true + socket.on('readable', this.readableListener) + // We may already have data pending. Let the user know they should + // at least attempt to read frames now. + this.readableListener() + } + + private _maybeEmitReadable(): void { + if (this.readable && this.needsReadable) { + this.needsReadable = false + this.emit('readable') + } + } + + private _readableListener(): void { + this.readable = true + this._maybeEmitReadable() + } + } + + async function createServer(): Promise { + log.info('Starting WebSocket server on port %s', screenOptions.publicPort) + const wss = new WebSocket.Server({ + port: screenOptions.publicPort, + perMessageDeflate: false + }) + + return new Promise((resolve, reject) => { + const listeningListener = () => { + wss.removeListener('listening', listeningListener) + wss.removeListener('error', errorListener) + resolve(wss) + } + const errorListener = (err: Error) => { + wss.removeListener('listening', listeningListener) + wss.removeListener('error', errorListener) + reject(err) + } + wss.on('listening', listeningListener) + wss.on('error', errorListener) + }) + } + + return createServer() + .then((wss) => { + log.info('creating FrameProducer: %s', options.screenGrabber) + const frameProducer = new FrameProducer( + new FrameConfig( + display.properties as DisplayProperties, + display.properties as DisplayProperties, + options.screenJpegQuality + ), + options.screenGrabber + ) + const broadcastSet = frameProducer.broadcastSet = new BroadcastSet() + + broadcastSet.on('nonempty', () => { + frameProducer.start() + }) + + broadcastSet.on('empty', () => { + frameProducer.stop() + }) + + broadcastSet.on('insert', (id: string) => { + // If two clients join a session in the middle, one of them + // may not release the initial size because the projection + // doesn't necessarily change, and the producer doesn't Getting + // restarted. Therefore we have to call onStart() manually + // if the producer is already up and running. + switch (frameProducer.runningState) { + case FrameProducer.STATE_STARTED: + broadcastSet.get(id).onStart(frameProducer) + break + } + }) + + display.on('rotationChange', (newRotation: number) => { + frameProducer.updateRotation(newRotation) + }) + + router.on(ChangeQualityMessage, (_channel: any, message: any) => { + frameProducer.changeQuality(message.quality) + }) + + frameProducer.on('start', () => { + broadcastSet.keys().map((id: string) => { + return broadcastSet.get(id).onStart(frameProducer) + }) + }) + + frameProducer.on('readable', function next() { + const frame = frameProducer.nextFrame() + if (frame) { + Promise.allSettled( + broadcastSet.keys().map((id: string) => { + return broadcastSet.get(id).onFrame(frame) + }) + ).then(next) + } + else { + frameProducer.needFrame() + } + }) + + frameProducer.on('error', (err: Error) => { + log.fatal('Frame producer had an error: %s', err.stack) + lifecycle.fatal() + }) + + wss.on('connection', async (ws: WebSocket, req) => { + const id = uuidv4() + let pingTimer: NodeJS.Timeout | undefined + + // Extract token from WebSocket subprotocols + const token = ws.protocol.substring('access_token.'.length) + const user = !!token && jwtutil.decode(token, options.secret) + + if (!token || !user) { + log.warn('WebSocket connection attempt without token from %s', req.socket.remoteAddress) + ws.send(JSON.stringify({ + type: 'auth_error', + message: 'Authentication token required' + })) + ws.close(1008, 'Authentication token required') + return + } + + const tryCheckDeviceGroup = async(fail = false) => { + try { + await delay(200) + + const deviceGroup = await group.get() + if (deviceGroup.email !== user?.email) { + const err = 'Device used by another user' + log.warn('WebSocket authentication failed for device %s: %s', options.serial, err) + ws.send(JSON.stringify({ + type: 'auth_error', + message: err + })) + ws.close(1008, 'Authentication failed') + return + } + + log.info('WebSocket authenticated for device %s', options.serial) + + // Send success message + ws.send(JSON.stringify({ + type: 'auth_success', + message: 'Authentication successful' + })) + + // Sending a ping message every now and then makes sure that + // reverse proxies like nginx don't time out the connection [1]. + // + // [1] http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout + pingTimer = setInterval(wsPingNotifier, 10 * 60000) // options.screenPingInterval + } + catch (err: any) { + if (!fail && err instanceof NoGroupError) { + await delay(1000) + return tryCheckDeviceGroup(true) + } + + log.error('WebSocket authentication error for device %s: %s', options.serial, err.message) + ws.send(JSON.stringify({ + type: 'auth_error', + message: 'Authentication error' + }), () => {}) + ws.close(1008, 'Authentication error') + } + } + + await tryCheckDeviceGroup() + + function send(message: string | Buffer, sendOptions?: {binary?: boolean}): Promise { + return new Promise((resolve, reject) => { + if (ws.readyState === WebSocket.OPEN) { + const onErr = (err?: Error) => + err ? reject(err) : resolve() + + // @ts-ignore + ws.send(...(sendOptions ? [message, sendOptions, onErr] : [message, onErr])) + return + } + + if (ws.readyState === WebSocket.CLOSED) { + log.warn('Unable to send to CLOSED client "%s"', id) + if (pingTimer) { + clearInterval(pingTimer) + } + broadcastSet.remove(id) + return + } + + log.warn('Unable to send to %s client "%s"', ws.readyState, id) + }) + } + + function wsStartNotifier(): Promise { + return send(util.format('start %s', JSON.stringify(frameProducer.banner))) + } + + function wsPingNotifier(): Promise { + return send('ping') + } + + function wsFrameNotifier(frame: Buffer): Promise { + return send(frame, { + binary: true + }) + } + + ws.on('message', (data: WebSocket.Data) => { + const match = /^(on|off|(size) ([0-9]+)x([0-9]+))$/.exec(data.toString()) + if (match) { + switch (match[2] || match[1]) { + case 'on': + broadcastSet.insert(id, { + onStart: wsStartNotifier, + onFrame: wsFrameNotifier + }) + break + case 'off': + broadcastSet.remove(id) + // Keep pinging even when the screen is off. + break + case 'size': + frameProducer.updateProjection(Number(match[3]), Number(match[4])) + break + } + } + }) + + ws.on('close', () => { + if (pingTimer) { + clearInterval(pingTimer) + } + broadcastSet.remove(id) + log.info('WebSocket closed for device %s', options.serial) + }) + + if (options.needScrcpy) { + log.info(`Scrcpy client has gotten for device s/n ${options.serial}`) + scrcpyClient.on('rawData', (data: Buffer) => { + console.log(`Data: ${data}`) + send(data, {binary: true}) + }) + } + + ws.on('error', (e: Error) => { + if (pingTimer) { + clearInterval(pingTimer) + } + broadcastSet.remove(id) + log.error('WebSocket error for device %s: %s', options.serial, e.message) + }) + }) + + lifecycle.observe(() => { + wss.close() + }) + + lifecycle.observe(() => { + frameProducer.stop() + }) + + return frameProducer + }) + }) + diff --git a/lib/units/device/plugins/screen/util/banner.js b/lib/units/device/plugins/screen/util/banner.js deleted file mode 100644 index b89729bb57..0000000000 --- a/lib/units/device/plugins/screen/util/banner.js +++ /dev/null @@ -1,104 +0,0 @@ -import Promise from 'bluebird' -export const read = function parseBanner(out) { - var tryRead - return new Promise(function(resolve, reject) { - var readBannerBytes = 0 - var needBannerBytes = 2 - var banner = out.banner = { - version: 0, - length: 0, - pid: 0, - realWidth: 0, - realHeight: 0, - virtualWidth: 0, - virtualHeight: 0, - orientation: 0, - quirks: { - dumb: false, - alwaysUpright: false, - tear: false - } - } - tryRead = function() { - for (var chunk; (chunk = out.read(needBannerBytes - readBannerBytes));) { - for (var cursor = 0, len = chunk.length; cursor < len;) { - if (readBannerBytes < needBannerBytes) { - switch (readBannerBytes) { - case 0: - // version - banner.version = chunk[cursor] - break - case 1: - // length - banner.length = needBannerBytes = chunk[cursor] - break - case 2: - case 3: - case 4: - case 5: - // pid - banner.pid += - (chunk[cursor] << ((readBannerBytes - 2) * 8)) >>> 0 - break - case 6: - case 7: - case 8: - case 9: - // real width - banner.realWidth += - (chunk[cursor] << ((readBannerBytes - 6) * 8)) >>> 0 - break - case 10: - case 11: - case 12: - case 13: - // real height - banner.realHeight += - (chunk[cursor] << ((readBannerBytes - 10) * 8)) >>> 0 - break - case 14: - case 15: - case 16: - case 17: - // virtual width - banner.virtualWidth += - (chunk[cursor] << ((readBannerBytes - 14) * 8)) >>> 0 - break - case 18: - case 19: - case 20: - case 21: - // virtual height - banner.virtualHeight += - (chunk[cursor] << ((readBannerBytes - 18) * 8)) >>> 0 - break - case 22: - // orientation - banner.orientation += chunk[cursor] * 90 - break - case 23: - // quirks - banner.quirks.dumb = (chunk[cursor] & 1) === 1 - banner.quirks.alwaysUpright = (chunk[cursor] & 2) === 2 - banner.quirks.tear = (chunk[cursor] & 4) === 4 - break - } - cursor += 1 - readBannerBytes += 1 - if (readBannerBytes === needBannerBytes) { - return resolve(banner) - } - } - else { - reject(new Error('Supposedly impossible error parsing banner')) - } - } - } - } - tryRead() - out.on('readable', tryRead) - }) - .finally(function() { - out.removeListener('readable', tryRead) - }) -} diff --git a/lib/units/device/plugins/screen/util/banner.ts b/lib/units/device/plugins/screen/util/banner.ts new file mode 100644 index 0000000000..cf5d857251 --- /dev/null +++ b/lib/units/device/plugins/screen/util/banner.ts @@ -0,0 +1,106 @@ +import { Readable } from 'stream' + +export interface BannerQuirks { + dumb: boolean + alwaysUpright: boolean + tear: boolean +} + +export interface Banner { + version: number + length: number + pid: number + realWidth: number + realHeight: number + virtualWidth: number + virtualHeight: number + orientation: number + quirks: BannerQuirks +} + +interface BannerStream extends Readable { + banner?: Banner +} + +export const read = (out: BannerStream) => + new Promise((resolve, reject) => { + let readBannerBytes = 0 + let needBannerBytes = 2 + + const banner: Banner = out.banner = { + version: 0, + length: 0, + pid: 0, + realWidth: 0, + realHeight: 0, + virtualWidth: 0, + virtualHeight: 0, + orientation: 0, + quirks: { + dumb: false, + alwaysUpright: false, + tear: false + } + } + + const tryRead = function() { + for (let chunk: Buffer | null; (chunk = out.read(needBannerBytes - readBannerBytes));) { + for (let cursor = 0, len = chunk.length; cursor < len;) { + if (readBannerBytes >= needBannerBytes) { + out.removeListener('readable', tryRead) + reject(new Error('Supposedly impossible error parsing banner')) + return + } + + if (readBannerBytes === 0) { + banner.version = chunk[cursor] + } + + else if (readBannerBytes === 1) { + banner.length = needBannerBytes = chunk[cursor] + } + + else if (readBannerBytes <= 5) { + banner.pid += (chunk[cursor] << ((readBannerBytes - 2) * 8)) >>> 0 + } + + else if (readBannerBytes <= 9) { + banner.realWidth += (chunk[cursor] << ((readBannerBytes - 6) * 8)) >>> 0 + } + + else if (readBannerBytes <= 13) { + banner.realHeight += (chunk[cursor] << ((readBannerBytes - 10) * 8)) >>> 0 + } + + else if (readBannerBytes <= 17) { + banner.virtualWidth += (chunk[cursor] << ((readBannerBytes - 14) * 8)) >>> 0 + } + + else if (readBannerBytes <= 21) { + banner.virtualHeight += (chunk[cursor] << ((readBannerBytes - 18) * 8)) >>> 0 + } + + else if (readBannerBytes === 22) { + banner.orientation += chunk[cursor] * 90 + } + + else if (readBannerBytes === 23) { + banner.quirks.dumb = (chunk[cursor] & 1) === 1 + banner.quirks.alwaysUpright = (chunk[cursor] & 2) === 2 + banner.quirks.tear = (chunk[cursor] & 4) === 4 + } + + cursor += 1 + readBannerBytes += 1 + + if (readBannerBytes === needBannerBytes) { + out.removeListener('readable', tryRead) + return resolve(banner) + } + } + } + } + + tryRead() + out.on('readable', tryRead) + }) diff --git a/lib/units/device/plugins/screen/util/broadcastset.js b/lib/units/device/plugins/screen/util/broadcastset.js deleted file mode 100644 index 24bba44dea..0000000000 --- a/lib/units/device/plugins/screen/util/broadcastset.js +++ /dev/null @@ -1,39 +0,0 @@ -import util from 'util' -import EventEmitter from 'eventemitter3' -function BroadcastSet() { - this.set = Object.create(null) - this.count = 0 -} -util.inherits(BroadcastSet, EventEmitter) -BroadcastSet.prototype.insert = function(id, ws) { - if (!(id in this.set)) { - this.set[id] = ws - this.count += 1 - this.emit('insert', id) - if (this.count === 1) { - this.emit('nonempty') - } - } -} -BroadcastSet.prototype.remove = function(id) { - if (id in this.set) { - delete this.set[id] - this.count -= 1 - this.emit('remove', id) - if (this.count === 0) { - this.emit('empty') - } - } -} -BroadcastSet.prototype.values = function() { - return Object.keys(this.set).map(function(id) { - return this.set[id] - }, this) -} -BroadcastSet.prototype.keys = function() { - return Object.keys(this.set) -} -BroadcastSet.prototype.get = function(id) { - return this.set[id] -} -export default BroadcastSet diff --git a/lib/units/device/plugins/screen/util/broadcastset.ts b/lib/units/device/plugins/screen/util/broadcastset.ts new file mode 100644 index 0000000000..6765082a67 --- /dev/null +++ b/lib/units/device/plugins/screen/util/broadcastset.ts @@ -0,0 +1,81 @@ +import EventEmitter from 'events' + +interface BroadcastSetEvents { + insert: (id: string) => void + remove: (id: string) => void + nonempty: () => void + empty: () => void +} + +export default class BroadcastSet extends EventEmitter { + private set: Record + public count: number + + constructor() { + super() + this.set = Object.create(null) + this.count = 0 + } + + on(event: K, listener: BroadcastSetEvents[K]): this { + return super.on(event, listener) + } + + once(event: K, listener: BroadcastSetEvents[K]): this { + return super.once(event, listener) + } + + emit( + event: K, + ...args: Parameters + ): boolean { + return super.emit(event, ...args) + } + + off(event: K, listener: BroadcastSetEvents[K]): this { + return super.off(event, listener) + } + + removeListener( + event: K, + listener: BroadcastSetEvents[K] + ): this { + return super.removeListener(event, listener) + } + + insert(id: string, ws: T): void { + if (!(id in this.set)) { + this.set[id] = ws + this.count += 1 + this.emit('insert', id) + if (this.count === 1) { + this.emit('nonempty') + } + } + } + + remove(id: string): void { + if (id in this.set) { + delete this.set[id] + this.count -= 1 + this.emit('remove', id) + if (this.count === 0) { + this.emit('empty') + } + } + } + + values(): T[] { + return Object.keys(this.set).map((id) => { + return this.set[id] + }) + } + + keys(): string[] { + return Object.keys(this.set) + } + + get(id: string): T | undefined { + return this.set[id] + } +} diff --git a/lib/units/device/plugins/screen/util/frameconfig.js b/lib/units/device/plugins/screen/util/frameconfig.js deleted file mode 100644 index 7e6b62af85..0000000000 --- a/lib/units/device/plugins/screen/util/frameconfig.js +++ /dev/null @@ -1,13 +0,0 @@ -import util from 'util' -function FrameConfig(real, virtual, quality) { - this.realWidth = real.width - this.realHeight = real.height - this.virtualWidth = virtual.width - this.virtualHeight = virtual.height - this.rotation = virtual.rotation - this.quality = quality -} -FrameConfig.prototype.toString = function() { - return util.format('%dx%d@%dx%d/%d', this.realWidth, this.realHeight, this.virtualWidth, this.virtualHeight, this.rotation) -} -export default FrameConfig diff --git a/lib/units/device/plugins/screen/util/frameconfig.ts b/lib/units/device/plugins/screen/util/frameconfig.ts new file mode 100644 index 0000000000..8a674a07ea --- /dev/null +++ b/lib/units/device/plugins/screen/util/frameconfig.ts @@ -0,0 +1,33 @@ +interface RealDimensions { + width: number + height: number +} + +interface VirtualDimensions { + width: number + height: number + rotation: number +} + +export default class FrameConfig { + public realWidth: number + public realHeight: number + public virtualWidth: number + public virtualHeight: number + public rotation: number + public quality: number + + constructor(real: RealDimensions, virtual: VirtualDimensions, quality: number) { + this.realWidth = real.width + this.realHeight = real.height + this.virtualWidth = virtual.width + this.virtualHeight = virtual.height + this.rotation = virtual.rotation + this.quality = quality + } + + toString(): string { + return `${this.realWidth}x${this.realHeight}@${this.virtualWidth}x${this.virtualHeight}/${this.rotation}` + } +} + diff --git a/lib/units/device/plugins/screen/util/frameparser.js b/lib/units/device/plugins/screen/util/frameparser.js deleted file mode 100644 index bb9094c0b9..0000000000 --- a/lib/units/device/plugins/screen/util/frameparser.js +++ /dev/null @@ -1,63 +0,0 @@ -function FrameParser() { - this.readFrameBytes = 0 - this.frameBodyLength = 0 - this.frameBody = null - this.cursor = 0 - this.chunk = null -} -FrameParser.prototype.push = function(chunk) { - if (this.chunk) { - throw new Error('Must consume pending frames before pushing more chunks') - } - this.chunk = chunk -} -FrameParser.prototype.nextFrame = function() { - if (!this.chunk) { - return null - } - for (var len = this.chunk.length; this.cursor < len;) { - if (this.readFrameBytes < 4) { - this.frameBodyLength += - (this.chunk[this.cursor] << (this.readFrameBytes * 8)) >>> 0 - this.cursor += 1 - this.readFrameBytes += 1 - } - else { - var bytesLeft = len - this.cursor - if (bytesLeft >= this.frameBodyLength) { - var completeBody - if (this.frameBody) { - completeBody = Buffer.concat([ - this.frameBody, - this.chunk.slice(this.cursor, this.cursor + this.frameBodyLength) - ]) - } - else { - completeBody = this.chunk.slice(this.cursor, this.cursor + this.frameBodyLength) - } - this.cursor += this.frameBodyLength - this.frameBodyLength = this.readFrameBytes = 0 - this.frameBody = null - return completeBody - } - else { - // @todo Consider/benchmark continuation frames to prevent - // potential Buffer thrashing. - if (this.frameBody) { - this.frameBody = - Buffer.concat([this.frameBody, this.chunk.slice(this.cursor, len)]) - } - else { - this.frameBody = this.chunk.slice(this.cursor, len) - } - this.frameBodyLength -= bytesLeft - this.readFrameBytes += bytesLeft - this.cursor = len - } - } - } - this.cursor = 0 - this.chunk = null - return null -} -export default FrameParser diff --git a/lib/units/device/plugins/screen/util/frameparser.ts b/lib/units/device/plugins/screen/util/frameparser.ts new file mode 100644 index 0000000000..e6d26db7c7 --- /dev/null +++ b/lib/units/device/plugins/screen/util/frameparser.ts @@ -0,0 +1,74 @@ +export default class FrameParser { + private readFrameBytes: number + private frameBodyLength: number + private frameBody: Buffer | null + private cursor: number + private chunk: Buffer | null + + constructor() { + this.readFrameBytes = 0 + this.frameBodyLength = 0 + this.frameBody = null + this.cursor = 0 + this.chunk = null + } + + push(chunk: Buffer): void { + if (this.chunk) { + throw new Error('Must consume pending frames before pushing more chunks') + } + this.chunk = chunk + } + + nextFrame(): Buffer | null { + if (!this.chunk) { + return null + } + + const len = this.chunk.length + while (this.cursor < len) { + if (this.readFrameBytes < 4) { + this.frameBodyLength += + (this.chunk[this.cursor] << (this.readFrameBytes * 8)) >>> 0 + this.cursor += 1 + this.readFrameBytes += 1 + } else { + const bytesLeft = len - this.cursor + if (bytesLeft >= this.frameBodyLength) { + let completeBody: Buffer + if (this.frameBody) { + completeBody = Buffer.concat([ + this.frameBody, + this.chunk.slice(this.cursor, this.cursor + this.frameBodyLength), + ]) + } else { + completeBody = this.chunk.slice(this.cursor, this.cursor + this.frameBodyLength) + } + this.cursor += this.frameBodyLength + this.frameBodyLength = this.readFrameBytes = 0 + this.frameBody = null + return completeBody + } else { + // @todo Consider/benchmark continuation frames to prevent + // potential Buffer thrashing. + if (this.frameBody) { + this.frameBody = Buffer.concat([ + this.frameBody, + this.chunk.slice(this.cursor, len), + ]) + } else { + this.frameBody = this.chunk.slice(this.cursor, len) + } + this.frameBodyLength -= bytesLeft + this.readFrameBytes += bytesLeft + this.cursor = len + } + } + } + + this.cursor = 0 + this.chunk = null + return null + } +} + diff --git a/lib/units/device/plugins/touch/index.ts b/lib/units/device/plugins/touch/index.ts index 13e961efa3..0af578f14a 100644 --- a/lib/units/device/plugins/touch/index.ts +++ b/lib/units/device/plugins/touch/index.ts @@ -113,7 +113,7 @@ class TouchConsumer extends EventEmitter { this._queueWrite(() => { const x = Math.ceil(this.touchConfig.origin.x(point) * this.banner!.maxX) const y = Math.ceil(this.touchConfig.origin.y(point) * this.banner!.maxY) - const p = Math.ceil((point.pressure || 0.5) * this.banner!.maxPressure) + const p = Math.max(1, Math.ceil((point.pressure || 0.5) * this.banner!.maxPressure)) return this._write(`d ${point.contact} ${x} ${y} ${p}\n`) }) } @@ -122,7 +122,7 @@ class TouchConsumer extends EventEmitter { this._queueWrite(() => { const x = Math.ceil(this.touchConfig.origin.x(point) * this.banner!.maxX) const y = Math.ceil(this.touchConfig.origin.y(point) * this.banner!.maxY) - const p = Math.ceil((point.pressure || 0.5) * this.banner!.maxPressure) + const p = Math.max(1, Math.ceil((point.pressure || 0.5) * this.banner!.maxPressure)) return this._write(`m ${point.contact} ${x} ${y} ${p}\n`) }) } @@ -151,7 +151,7 @@ class TouchConsumer extends EventEmitter { this.touchUp(point) this.touchCommit() } - + private async startState(): Promise { if (this.desiredState.next() !== STATE_STARTED) { this.ensureStateLock = false @@ -164,19 +164,19 @@ class TouchConsumer extends EventEmitter { const out = await this._startService() this.output = new RiskyStream(out) .on('unexpectedEnd', this._outputEnded.bind(this)) - + this._readOutput(this.output.stream) - + const socket = await this._connectService() this.socket = new RiskyStream(socket) .on('unexpectedEnd', this._socketEnded.bind(this)) - + const banner = await this._readBanner(this.socket.stream) this.banner = banner - + this._readUnexpected(this.socket.stream) this._processWriteQueue() - + this.runningState = STATE_STARTED this.emit('start') } catch (err: any) { @@ -217,7 +217,7 @@ class TouchConsumer extends EventEmitter { log.warn('Will not apply desired state due to too many failures') return } - + // Prevent concurrent execution if (this.ensureStateLock) { return @@ -295,7 +295,7 @@ class TouchConsumer extends EventEmitter { this.splitStream.removeAllListeners('data') this.splitStream.destroy() } - + this.splitStream = out.pipe(split()).on('data', (line: any) => { const trimmed = line.toString().trim() if (trimmed === '') { @@ -352,7 +352,7 @@ class TouchConsumer extends EventEmitter { this.splitStream.destroy() this.splitStream = null } - + this.output = null this.socket = null this.banner = null @@ -361,13 +361,13 @@ class TouchConsumer extends EventEmitter { private async _disconnectService(socket: RiskyStream | null): Promise { log.info('Disconnecting from minitouch service') - + if (!socket || socket.ended) { return true } socket.stream.removeListener('readable', this.readableListener) - + return new Promise((resolve) => { const endListener = () => { socket.removeListener('end', endListener) @@ -376,7 +376,7 @@ class TouchConsumer extends EventEmitter { socket.on('end', endListener) socket.stream.resume() socket.end() - + // Add timeout setTimeout(() => { socket.removeListener('end', endListener) @@ -387,7 +387,7 @@ class TouchConsumer extends EventEmitter { private async _stopService(output: RiskyStream | null): Promise { log.info('Stopping minitouch service') - + if (!output || output.ended) { return true } @@ -402,9 +402,9 @@ class TouchConsumer extends EventEmitter { SIGTERM: -15, SIGKILL: -9 }[signal] - + log.info('Sending %s to minitouch', signal) - + await Promise.race([ Promise.all([ output.waitForEnd(), @@ -413,7 +413,7 @@ class TouchConsumer extends EventEmitter { ]), new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 2000)) ]) - + return true } @@ -441,7 +441,7 @@ class TouchConsumer extends EventEmitter { private async _readBanner(socket: any): Promise { log.info('Reading minitouch banner') - + const parser = new Parser(socket) const banner: Banner = { pid: -1, @@ -521,14 +521,14 @@ class TouchConsumer extends EventEmitter { if (!this.socket?.stream) { return } - + // Handle backpressure const canWrite = this.socket.stream.write(chunk) if (!canWrite) { log.warn('Socket buffer is full, experiencing backpressure') } } - + destroy(): void { // Clean up all resources if (this.splitStream) { @@ -536,16 +536,16 @@ class TouchConsumer extends EventEmitter { this.splitStream.destroy() this.splitStream = null } - + if (this.socket) { this.socket.stream.removeListener('readable', this.readableListener) this.socket.removeAllListeners() } - + if (this.output) { this.output.removeAllListeners() } - + this.failCounter.removeAllListeners() this.removeAllListeners() this.writeQueue = [] @@ -583,7 +583,7 @@ export default syrup.serial() // Use Promise.race with once() for cleaner event handling touchConsumer.start() - + return Promise.race([ new Promise((resolve) => { touchConsumer.once('start', () => resolve(touchConsumer)) @@ -595,7 +595,9 @@ export default syrup.serial() } const touchConsumer = await startConsumer() - const queue = new SeqQueue(100, 4) + + // TODO: refactoring SeqQueue + // const queue = new SeqQueue(100, 4) touchConsumer.on('error', (err: Error) => { log.fatal('Touch consumer had an error %s: %s', err?.message, err?.stack) @@ -604,37 +606,25 @@ export default syrup.serial() router .on(GestureStartMessage, (channel: any, message: any) => { - queue.start(message.seq) + touchConsumer.start() }) .on(GestureStopMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - queue.stop() - }) + touchConsumer.stop() }) .on(TouchDownMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - touchConsumer.touchDown(message) - }) + touchConsumer.touchDown(message) }) .on(TouchMoveMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - touchConsumer.touchMove(message) - }) + touchConsumer.touchMove(message) }) .on(TouchUpMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - touchConsumer.touchUp(message) - }) + touchConsumer.touchUp(message) }) .on(TouchCommitMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - touchConsumer.touchCommit() - }) + touchConsumer.touchCommit() }) .on(TouchResetMessage, (channel: any, message: any) => { - queue.push(message.seq, () => { - touchConsumer.touchReset() - }) + touchConsumer.touchReset() }) return touchConsumer diff --git a/lib/units/device/plugins/vnc/index.js b/lib/units/device/plugins/vnc/index.js deleted file mode 100644 index f980a369df..0000000000 --- a/lib/units/device/plugins/vnc/index.js +++ /dev/null @@ -1,242 +0,0 @@ -import net from 'net' -import util from 'util' -import os from 'os' -import syrup from '@devicefarmer/stf-syrup' -import Promise from 'bluebird' -import {v4 as uuidv4} from 'uuid' -import * as jpeg from '@julusian/jpeg-turbo' -import logger from '../../../../util/logger.js' -import * as grouputil from '../../../../util/grouputil.js' -import wire from '../../../../wire/index.js' -import wireutil from '../../../../wire/util.js' -import lifecycle from '../../../../util/lifecycle.js' -import VncServer from './util/server.js' -import VncConnection from './util/connection.js' -import PointerTranslator from './util/pointertranslator.js' -import router from '../../../base-device/support/router.js' -import push from '../../../base-device/support/push.js' -import stream from '../screen/stream.js' -import touch from '../touch/index.js' -import group from '../group.js' -import solo from '../solo.js' -import {VncAuthResponsesUpdatedMessage} from '../../../../wire/wire.js' -export default syrup.serial() - .dependency(router) - .dependency(push) - .dependency(stream) - .dependency(touch) - .dependency(group) - .dependency(solo) - .define(function(options, router, push, screenStream, touch, group, solo) { - var log = logger.createLogger('device:plugins:vnc') - function vncAuthHandler(data) { - log.info('VNC authentication attempt using "%s"', data.response.toString('hex')) - var resolver = Promise.defer() - function notify() { - group.get() - .then(function(currentGroup) { - push.send([ - solo.channel, - wireutil.envelope(new wire.JoinGroupByVncAuthResponseMessage(options.serial, data.response.toString('hex'), currentGroup.group)) - ]) - }) - .catch(grouputil.NoGroupError, function() { - push.send([ - solo.channel, - wireutil.envelope(new wire.JoinGroupByVncAuthResponseMessage(options.serial, data.response.toString('hex'))) - ]) - }) - } - function joinListener(newGroup, identifier) { - if (!data.response.equals(Buffer.from(identifier || '', 'hex'))) { - resolver.reject(new Error('Someone else took the device')) - } - } - function autojoinListener(identifier, joined) { - if (data.response.equals(Buffer.from(identifier, 'hex'))) { - if (joined) { - resolver.resolve() - } - else { - resolver.reject(new Error('Device is already in use')) - } - } - } - group.on('join', joinListener) - group.on('autojoin', autojoinListener) - router.on(VncAuthResponsesUpdatedMessage, notify) - notify() - return resolver.promise - .timeout(5000) - .finally(function() { - group.removeListener('join', joinListener) - group.removeListener('autojoin', autojoinListener) - router.removeListener(wire.VncAuthResponsesUpdatedMessage, notify) - }) - } - function createServer() { - log.info('Starting VNC server on port %d', options.vncPort) - var opts = { - name: options.serial, - width: options.vncInitialSize[0], - height: options.vncInitialSize[1], - security: [{ - type: VncConnection.SECURITY_VNC, - challenge: Buffer.alloc(16).fill(0), - auth: vncAuthHandler - }] - } - var vnc = new VncServer(net.createServer({ - allowHalfOpen: true - }), opts) - var listeningListener, errorListener - return new Promise(function(resolve, reject) { - listeningListener = function() { - return resolve(vnc) - } - errorListener = function(err) { - return reject(err) - } - vnc.on('listening', listeningListener) - vnc.on('error', errorListener) - vnc.listen(options.vncPort) - }) - .finally(function() { - vnc.removeListener('listening', listeningListener) - vnc.removeListener('error', errorListener) - }) - } - return createServer() - .then(function(vnc) { - vnc.on('connection', function(conn) { - log.info('New VNC connection from %s', conn.conn.remoteAddress) - var id = util.format('vnc-%s', uuidv4()) - var connState = { - lastFrame: null, - lastFrameTime: null, - frameWidth: 0, - frameHeight: 0, - sentFrameTime: null, - updateRequests: 0, - frameConfig: { - format: jpeg.FORMAT_RGB - } - } - var pointerTranslator = new PointerTranslator() - pointerTranslator.on('touchdown', function(event) { - touch.touchDown(event) - }) - pointerTranslator.on('touchmove', function(event) { - touch.touchMove(event) - }) - pointerTranslator.on('touchup', function(event) { - touch.touchUp(event) - }) - pointerTranslator.on('touchcommit', function() { - touch.touchCommit() - }) - function maybeSendFrame() { - if (!connState.updateRequests) { - return - } - if (!connState.lastFrame) { - return - } - if (connState.lastFrameTime === connState.sentFrameTime) { - return - } - var decoded = jpeg.decompressSync(connState.lastFrame, connState.frameConfig) - conn.writeFramebufferUpdate([{ - xPosition: 0, - yPosition: 0, - width: decoded.width, - height: decoded.height, - encodingType: VncConnection.ENCODING_RAW, - data: decoded.data - }, - { - xPosition: 0, - yPosition: 0, - width: decoded.width, - height: decoded.height, - encodingType: VncConnection.ENCODING_DESKTOPSIZE - } - ]) - connState.updateRequests = 0 - connState.sentFrameTime = connState.lastFrameTime - } - function vncStartListener(frameProducer) { - return new Promise(function(resolve) { - connState.frameWidth = frameProducer.banner.virtualWidth - connState.frameHeight = frameProducer.banner.virtualHeight - resolve() - }) - } - function vncFrameListener(frame) { - return new Promise(function(resolve) { - connState.lastFrame = frame - connState.lastFrameTime = Date.now() - maybeSendFrame() - resolve() - }) - } - function groupLeaveListener() { - conn.end() - } - conn.on('authenticated', function() { - screenStream.updateProjection(options.vncInitialSize[0], options.vncInitialSize[1]) - screenStream.broadcastSet.insert(id, { - onStart: vncStartListener, - onFrame: vncFrameListener - }) - }) - conn.on('fbupdaterequest', function() { - connState.updateRequests += 1 - maybeSendFrame() - }) - conn.on('formatchange', function(format) { - var same = os.endianness() === 'BE' === - Boolean(format.bigEndianFlag) - var formatOrder = (format.redShift > format.blueShift) === same - switch (format.bitsPerPixel) { - case 8: - connState.frameConfig = { - format: jpeg.FORMAT_GRAY - } - break - case 24: - connState.frameConfig = { - format: formatOrder ? jpeg.FORMAT_BGR : jpeg.FORMAT_RGB - } - break - case 32: - var f - if (formatOrder) { - f = format.blueShift === 0 ? jpeg.FORMAT_BGRX : jpeg.FORMAT_XBGR - } - else { - f = format.redShift === 0 ? jpeg.FORMAT_RGBX : jpeg.FORMAT_XRGB - } - connState.frameConfig = { - format: f - } - break - } - }) - conn.on('pointer', function(event) { - pointerTranslator.push(event) - }) - conn.on('close', function() { - screenStream.broadcastSet.remove(id) - group.removeListener('leave', groupLeaveListener) - }) - conn.on('userActivity', function() { - group.keepalive() - }) - group.on('leave', groupLeaveListener) - }) - lifecycle.observe(function() { - vnc.close() - }) - }) - }) diff --git a/lib/units/device/plugins/vnc/index.ts b/lib/units/device/plugins/vnc/index.ts new file mode 100644 index 0000000000..da58e9f7d8 --- /dev/null +++ b/lib/units/device/plugins/vnc/index.ts @@ -0,0 +1,561 @@ +import util from 'util' +import os from 'os' +import syrup from '@devicefarmer/stf-syrup' +import {v4 as uuidv4} from 'uuid' +import jpeg from '@julusian/jpeg-turbo' +import webp from '@cwasm/webp' +import logger from '../../../../util/logger.js' +import lifecycle from '../../../../util/lifecycle.js' +import VncServer from './util/server.js' +import VncConnection from './util/connection.js' +import PointerTranslator from './util/pointertranslator.js' +import router from '../../../base-device/support/router.js' +import push from '../../../base-device/support/push.js' +import stream from '../screen/stream.js' +import touch from '../touch/index.js' +import group from '../group.js' +import solo from '../solo.js' + +interface VNCConnectionState { + lastFrame: Buffer | null + lastFrameTime: number | null + lastSentFrame: Buffer | null + frameWidth: number + frameHeight: number + lastSentTimestamp: number + sentFrameWidth: number + sentFrameHeight: number + updateRequests: number + lastRequestIncremental: boolean + pendingResponse: boolean + frameConfig: { + format: number + } + // Frame cache to avoid re-decoding identical frames + cachedRawFrame: Buffer | null + cachedDecodedFrame: {width: number, height: number, data: Buffer} | null + // Frame type detection (cached after first frame) + frameType: 'jpeg' | 'webp' | null + // FPS tracking + framesSent: number + framesDecoded: number + framesCached: number + framesThrottled: number + framesSkipped: number + lastStatsTime: number +} + +export default syrup.serial() + .dependency(router) + .dependency(push) + .dependency(stream) + .dependency(touch) + .dependency(group) + .dependency(solo) + .define((options, router, push, screenStream, touch, group) => { + const log = logger.createLogger('device:plugins:vnc') + + const MAX_FPS = 60 // Maximum fps for changing content + const STATIC_FPS = 2 // Fps for static content + const MAX_FRAME_INTERVAL = 1000 / MAX_FPS + const STATIC_FRAME_INTERVAL = 1000 / STATIC_FPS + + // const vncAuthHandler = (data: any) => new Promise((resolve, reject) => { + // log.info('VNC authentication attempt using "%s"', data.response.toString('hex')) + // const cleanup = () => { + // group.removeListener('join', joinListener) + // group.removeListener('autojoin', autojoinListener) + // router.removeListener(VncAuthResponsesUpdatedMessage, notify) + // } + // + // const notify = async() => { + // try { + // const currentGroup = await group.get() + // push.send([ + // solo.channel, + // wireutil.pack(JoinGroupByVncAuthResponseMessage, { + // serial: options.serial, + // response: data.response.toString('hex'), + // currentGroup: currentGroup?.group + // }) + // ]) + // } catch (e) { + // push.send([ + // solo.channel, + // wireutil.pack(JoinGroupByVncAuthResponseMessage, { + // serial: options.serial, + // response: data.response.toString('hex') + // }) + // ]) + // } + // } + // + // const joinListener = (newGroup: any, identifier: any) => { + // if (!data.response.equals(Buffer.from(identifier || '', 'hex'))) { + // cleanup() + // reject(new Error('Someone else took the device')) + // } + // } + // + // const autojoinListener = (identifier: any, joined: any) => { + // if (data.response.equals(Buffer.from(identifier, 'hex'))) { + // cleanup() + // if (joined) { + // resolve() + // } + // else { + // reject(new Error('Device is already in use')) + // } + // } + // } + // + // group.on('join', joinListener) + // group.on('autojoin', autojoinListener) + // router.on(VncAuthResponsesUpdatedMessage, notify) + // notify() + // }) + + log.info('Starting VNC server on port %s', options.vncPort) + + const vnc = new VncServer({ + name: options.serial, + width: options.vncInitialSize[0], + height: options.vncInitialSize[1], + // security: [{ + // type: VncConnection.SECURITY_VNC, + // challenge: Buffer.alloc(16).fill(0), + // auth: vncAuthHandler + // }] + }) + + vnc.on('error', (err: any) => { + log.error('VNC error: %s', err?.message || err) + }) + + vnc.on('connection', (conn: any) => { + log.info('New VNC connection from %s', conn.conn.remoteAddress) + + const id = util.format('vnc-%s', uuidv4()) + const connState: VNCConnectionState = { + lastFrame: null, + lastFrameTime: null, + lastSentFrame: null, + frameWidth: 0, + frameHeight: 0, + lastSentTimestamp: 0, + sentFrameWidth: 0, + sentFrameHeight: 0, + updateRequests: 0, + lastRequestIncremental: false, + pendingResponse: false, + frameConfig: { + format: jpeg.FORMAT_RGB + }, + cachedRawFrame: null, + cachedDecodedFrame: null, + frameType: null, + framesSent: 0, + framesDecoded: 0, + framesCached: 0, + framesThrottled: 0, + framesSkipped: 0, + lastStatsTime: Date.now() + } + + // Stats logging every 10 seconds + const statsInterval = setInterval(() => { + const now = Date.now() + const elapsed = (now - connState.lastStatsTime) / 1000 + const fps = (connState.framesSent / elapsed).toFixed(1) + const cacheHitRate = connState.framesSent > 0 + ? ((connState.framesCached / connState.framesSent) * 100).toFixed(1) + : '0.0' + + // Always log stats, even if no activity (shows 0 fps for static screens) + if (connState.framesSent > 0 || connState.framesThrottled > 0) { + log.info(`VNC Stats: ${fps} fps | sent: ${connState.framesSent}, decoded: ${connState.framesDecoded}, cached: ${cacheHitRate}%, throttled: ${connState.framesThrottled}`) + } + + // Reset counters + connState.framesSent = 0 + connState.framesDecoded = 0 + connState.framesCached = 0 + connState.framesThrottled = 0 + connState.framesSkipped = 0 + connState.lastStatsTime = now + }, 10000) + + const pointerTranslator = new PointerTranslator() + .on('touchdown', (event: any) => { + try { + // log.debug(`VNC pointer event: contact=${event.contact}, x=${event.x?.toFixed(3)}, y=${event.y?.toFixed(3)}`) + touch.touchDown(event) + } catch (err: any) { + log.error(`Error calling touch.touchDown(): ${err?.message} ${err?.stack}`) + } + }) + .on('touchmove', (event: any) => { + try { + // log.debug(`VNC touchmove: contact=${event.contact}, x=${event.x?.toFixed(3)}, y=${event.y?.toFixed(3)}`) + touch.touchMove(event) + } catch (err: any) { + log.error(`Error calling touch.touchMove(): ${err?.message}`) + } + }) + .on('touchup', (event: any) => { + try { + // log.debug(`VNC touchup: contact=${event.contact}`) + touch.touchUp(event) + } catch (err: any) { + log.error(`Error calling touch.touchUp(): ${err?.message}`) + } + }) + .on('touchcommit', () => { + try { + log.debug(`VNC touchcommit`) + touch.touchCommit() + } catch (err: any) { + log.error(`Error calling touch.touchCommit(): ${err?.message}`) + } + }) + .on('touchstart', () => { + try { + // log.debug(`VNC touchstart`) + touch.start() + } catch (err: any) { + log.error(`Error calling touch.touchStart(): ${err?.message}`) + } + }) + .on('touchstop', () => { + try { + // log.debug(`VNC touchstop`) + touch.stop() + } catch (err: any) { + log.error(`Error calling touch.touchStop(): ${err?.message}`) + } + }) + + const maybeSendFrame = () => { + // Must have a frame and pending update request + if (!connState.lastFrame || !connState.updateRequests) { + return + } + + const now = Date.now() + const isFirstFrame = !connState.lastSentFrame + + // Fast frame change detection: compare size first, then first/last bytes + // This is much faster than Buffer.equals() on large frames (20KB+) + let frameContentChanged = !connState.lastSentFrame + if (!frameContentChanged && connState.lastSentFrame) { + const current = connState.lastFrame + const last = connState.lastSentFrame + // Quick checks: size, first 4 bytes, last 4 bytes + frameContentChanged = + current.length !== last.length || + current[0] !== last[0] || current[1] !== last[1] || current[2] !== last[2] || current[3] !== last[3] || + current[current.length - 1] !== last[last.length - 1] || + current[current.length - 2] !== last[last.length - 2] + } + + const timeSinceLastSend = now - connState.lastSentTimestamp + + // For changing content: send as fast as possible (up to MAX_FPS) + // For static content: rate limit to STATIC_FPS to save bandwidth/CPU + if (frameContentChanged) { + // Content is changing - allow up to MAX_FPS + if (!isFirstFrame && timeSinceLastSend < MAX_FRAME_INTERVAL) { + // Too soon, but schedule immediate retry when interval passes + if (!connState.pendingResponse) { + connState.pendingResponse = true + connState.framesThrottled++ + setTimeout(() => { + connState.pendingResponse = false + maybeSendFrame() + }, MAX_FRAME_INTERVAL - timeSinceLastSend) + } + return + } + } else { + // Content is static - rate limit to STATIC_FPS + if (!isFirstFrame && connState.lastRequestIncremental && timeSinceLastSend < STATIC_FRAME_INTERVAL) { + // For static + incremental, use lower fps + if (!connState.pendingResponse) { + connState.pendingResponse = true + setTimeout(() => { + connState.pendingResponse = false + maybeSendFrame() + }, STATIC_FRAME_INTERVAL - timeSinceLastSend) + } + return + } + } + + try { + const frame = connState.lastFrame! + + let decoded: {width: number, height: number, data: Buffer} + + // Check if we can reuse cached decoded frame + // Use fast comparison: same object reference means same frame + const canUseCache = connState.cachedRawFrame === frame + + if (canUseCache && connState.cachedDecodedFrame) { + // Frame hasn't changed, reuse cached decode + decoded = connState.cachedDecodedFrame + connState.framesCached++ + } else { + // New frame, need to decode + // Detect frame type on first frame only + if (!connState.frameType) { + const isJpeg = frame[0] === 0xFF && frame[1] === 0xD8 + const isWebP = frame[0] === 0x52 && frame[1] === 0x49 && frame[2] === 0x46 && frame[3] === 0x46 // "RIFF" + + if (isWebP) { + connState.frameType = 'webp' + log.info('VNC: Detected WebP frame format') + } else if (isJpeg) { + connState.frameType = 'jpeg' + log.info('VNC: Detected JPEG frame format') + } else { + log.error(`Unknown frame format, first 4 bytes: ${frame.slice(0, 4).toString('hex')}`) + return + } + } + + // Decode based on detected frame type + if (connState.frameType === 'webp') { + const webpDecoded = webp.decode(frame) + decoded = { + width: webpDecoded.width, + height: webpDecoded.height, + data: Buffer.from(webpDecoded.data) + } + // WebP decoder returns RGBA, convert to client's expected format + decoded.data = convertRGBAToFormat(decoded.data, decoded.width, decoded.height, connState.frameConfig.format) + } else { + // JPEG + decoded = jpeg.decompressSync(frame, connState.frameConfig) + } + + connState.framesDecoded++ + + // Cache the decoded frame + connState.cachedRawFrame = frame + connState.cachedDecodedFrame = decoded + } + + // Build framebuffer update + const rectangles: any[] = [{ + xPosition: 0, + yPosition: 0, + width: decoded.width, + height: decoded.height, + encodingType: VncConnection.ENCODING_RAW, + data: decoded.data + }] + + // Send DESKTOPSIZE on first frame or when dimensions change + const isFirstFrame = connState.sentFrameWidth === 0 && connState.sentFrameHeight === 0 + const dimensionsChanged = decoded.width !== connState.sentFrameWidth || decoded.height !== connState.sentFrameHeight + + if (isFirstFrame || dimensionsChanged) { + if (isFirstFrame) { + log.info(`VNC: First frame, sending DESKTOPSIZE ${decoded.width}x${decoded.height}`) + } else { + log.info(`VNC: Dimensions changed from ${connState.sentFrameWidth}x${connState.sentFrameHeight} to ${decoded.width}x${decoded.height}`) + } + rectangles.push({ + xPosition: 0, + yPosition: 0, + width: decoded.width, + height: decoded.height, + encodingType: VncConnection.ENCODING_DESKTOPSIZE + }) + connState.sentFrameWidth = decoded.width + connState.sentFrameHeight = decoded.height + } + + try { + conn.writeFramebufferUpdate(rectangles) + connState.framesSent++ + connState.lastSentTimestamp = Date.now() + connState.lastSentFrame = connState.lastFrame + connState.updateRequests = 0 + } catch (writeErr: any) { + // Client likely disconnected, ignore EPIPE errors + if (writeErr.code === 'EPIPE' || writeErr.code === 'ECONNRESET') { + log.warn('VNC client disconnected while sending frame') + } else { + throw writeErr + } + } + } catch (err: any) { + log.error(`Error in maybeSendFrame: ${err?.message || 'Unknown error'}`) + log.error(err.stack) + // Don't let errors stop the broadcast + } + } + + // Convert RGBA (from WebP) to the format expected by VNC client + const convertRGBAToFormat = (rgba: Buffer, width: number, height: number, targetFormat: number): Buffer => { + const pixelCount = width * height + + // Most common case: client wants BGRX (format 3) or similar 32-bit format + if (targetFormat === jpeg.FORMAT_BGRX) { + // RGBA -> BGRX + const result = Buffer.alloc(pixelCount * 4) + for (let i = 0; i < pixelCount; i++) { + const src = i * 4 + const dst = i * 4 + result[dst] = rgba[src + 2] // B + result[dst + 1] = rgba[src + 1] // G + result[dst + 2] = rgba[src] // R + result[dst + 3] = 0 // X (padding) + } + return result + } else if (targetFormat === jpeg.FORMAT_RGBX || targetFormat === jpeg.FORMAT_RGB) { + // RGBA -> RGBX or RGB + const bytesPerPixel = targetFormat === jpeg.FORMAT_RGB ? 3 : 4 + const result = Buffer.alloc(pixelCount * bytesPerPixel) + for (let i = 0; i < pixelCount; i++) { + const src = i * 4 + const dst = i * bytesPerPixel + result[dst] = rgba[src] // R + result[dst + 1] = rgba[src + 1] // G + result[dst + 2] = rgba[src + 2] // B + if (bytesPerPixel === 4) { + result[dst + 3] = 0 // X + } + } + return result + } else { + // For other formats, just strip the alpha channel for now (RGB) + log.warn(`Unsupported target format ${targetFormat}, converting to RGB`) + const result = Buffer.alloc(pixelCount * 3) + for (let i = 0; i < pixelCount; i++) { + const src = i * 4 + const dst = i * 3 + result[dst] = rgba[src] // R + result[dst + 1] = rgba[src + 1] // G + result[dst + 2] = rgba[src + 2] // B + } + return result + } + } + + const vncStartListener = (frameProducer: any) => + new Promise((resolve) => { + const width = frameProducer.banner?.virtualWidth || 0 + const height = frameProducer.banner?.virtualHeight || 0 + log.info(`VNC: Frame producer started, updating dimensions to ${width}x${height}`) + connState.frameWidth = width + connState.frameHeight = height + conn.updateDimensions(width, height) + log.info(`VNC: Dimensions updated, pointer events will now use ${width}x${height} for normalization`) + resolve() + }) + + const vncFrameListener = (frame: any) => + new Promise((resolve) => { + connState.lastFrame = frame + connState.lastFrameTime = Date.now() + maybeSendFrame() + resolve() + }) + + const groupLeaveListener = () => conn.end() + + conn.on('authenticated', () => { + // Don't force projection update on VNC auth - use existing projection + // This prevents unnecessary minicap restarts that can fail on certain Android versions + // The VNC client can still request a size change later if needed + log.info('VNC authenticated, inserting into broadcastSet with id: %s', id) + + // If frame producer is already running, update dimensions before ServerInit is sent + if (screenStream.banner) { + const width = screenStream.banner.virtualWidth + const height = screenStream.banner.virtualHeight + log.info(`VNC: Setting dimensions to ${width}x${height} from running frame producer`) + conn.updateDimensions(width, height) + } + + screenStream.broadcastSet?.insert(id, { + onStart: vncStartListener, + onFrame: vncFrameListener + }) + }) + + conn.on('fbupdaterequest', (request: any) => { + connState.updateRequests += 1 + connState.lastRequestIncremental = request.incremental === 1 + maybeSendFrame() + }) + + conn.on('formatchange', (format: any) => { + const same = os.endianness() === 'BE' === Boolean(format.bigEndianFlag) + const formatOrder = (format.redShift > format.blueShift) === same + + let selectedFormat + switch (format.bitsPerPixel) { + case 8: + selectedFormat = jpeg.FORMAT_GRAY + connState.frameConfig = {format: selectedFormat} + break + case 24: + selectedFormat = formatOrder ? jpeg.FORMAT_BGR : jpeg.FORMAT_RGB + connState.frameConfig = {format: selectedFormat} + break + case 32: + selectedFormat = formatOrder + ? format.blueShift === 0 ? jpeg.FORMAT_BGRX : jpeg.FORMAT_XBGR + : format.redShift === 0 ? jpeg.FORMAT_RGBX : jpeg.FORMAT_XRGB + connState.frameConfig = {format: selectedFormat} + break + default: + log.warn(`Unsupported bitsPerPixel: ${format.bitsPerPixel}, using RGB`) + selectedFormat = jpeg.FORMAT_RGB + connState.frameConfig = {format: selectedFormat} + } + log.info(`VNC pixel format set: ${format.bitsPerPixel}bpp, format=${selectedFormat}`) + + // Clear cache when format changes since we need to re-convert + connState.cachedRawFrame = null + connState.cachedDecodedFrame = null + }) + + conn.on('pointer', (event: any) => { + // log.info(`VNC pointer event: button=${event.buttonMask}, x=${event.xPosition.toFixed(3)}, y=${event.yPosition.toFixed(3)}`) + pointerTranslator.push(event) + }) + + conn.on('close', () => { + log.info('VNC connection closed for device %s', options.serial) + clearInterval(statsInterval) + screenStream.broadcastSet?.remove(id) + group.removeListener('leave', groupLeaveListener) + }) + + conn.on('error', (err: Error) => { + log.warn('VNC connection error for device %s: %s', options.serial, err.message) + clearInterval(statsInterval) + // Clean up will happen in 'close' event + }) + + conn.on('userActivity', () => { + group.keepalive() + }) + + group.on('leave', groupLeaveListener) + clearInterval(statsInterval) + }) + + lifecycle.observe(() => { + vnc.close() + }) + + return { + start: () => vnc.listen(options.vncPort), + stop: () => vnc.close() + } + }) diff --git a/lib/units/device/plugins/vnc/util/connection.js b/lib/units/device/plugins/vnc/util/connection.js deleted file mode 100644 index 29a4e9bf7b..0000000000 --- a/lib/units/device/plugins/vnc/util/connection.js +++ /dev/null @@ -1,465 +0,0 @@ -import util from 'util' -import os from 'os' -import crypto from 'crypto' -import EventEmitter from 'eventemitter3' -import * as debug$0 from 'debug' -import Promise from 'bluebird' -import PixelFormat from './pixelformat.js' -var debug = debug$0('vnc:connection') -function VncConnection(conn, options) { - this.options = options - this._bound = { - _errorListener: this._errorListener.bind(this), - _readableListener: this._readableListener.bind(this), - _endListener: this._endListener.bind(this), - _closeListener: this._closeListener.bind(this) - } - this._buffer = null - this._state = 0 - this._changeState(VncConnection.STATE_NEED_CLIENT_VERSION) - this._serverVersion = VncConnection.V3_008 - this._serverSupportedSecurity = this.options.security - this._serverSupportedSecurityByType = - this.options.security.reduce(function(map, method) { - map[method.type] = method - return map - }, Object.create(null)) - this._serverWidth = this.options.width - this._serverHeight = this.options.height - this._serverPixelFormat = new PixelFormat({ - bitsPerPixel: 32, - depth: 24, - bigEndianFlag: os.endianness() === 'BE' ? 1 : 0, - trueColorFlag: 1, - redMax: 255, - greenMax: 255, - blueMax: 255, - redShift: 16, - greenShift: 8, - blueShift: 0 - }) - this._serverName = this.options.name - this._clientVersion = null - this._clientShare = false - this._clientPixelFormat = this._serverPixelFormat - this._clientEncodingCount = 0 - this._clientEncodings = [] - this._clientCutTextLength = 0 - this._authChallenge = this.options.challenge || crypto.randomBytes(16) - this.conn = conn - .on('error', this._bound._errorListener) - .on('readable', this._bound._readableListener) - .on('end', this._bound._endListener) - .on('close', this._bound._closeListener) - this._blockingOps = [] - this._writeServerVersion() - this._read() -} -util.inherits(VncConnection, EventEmitter) -VncConnection.V3_003 = 3003 -VncConnection.V3_007 = 3007 -VncConnection.V3_008 = 3008 -VncConnection.SECURITY_NONE = 1 -VncConnection.SECURITY_VNC = 2 -VncConnection.SECURITYRESULT_OK = 0 -VncConnection.SECURITYRESULT_FAIL = 1 -VncConnection.CLIENT_MESSAGE_SETPIXELFORMAT = 0 -VncConnection.CLIENT_MESSAGE_SETENCODINGS = 2 -VncConnection.CLIENT_MESSAGE_FBUPDATEREQUEST = 3 -VncConnection.CLIENT_MESSAGE_KEYEVENT = 4 -VncConnection.CLIENT_MESSAGE_POINTEREVENT = 5 -VncConnection.CLIENT_MESSAGE_CLIENTCUTTEXT = 6 -VncConnection.SERVER_MESSAGE_FBUPDATE = 0 -var StateReverse = Object.create(null) -var State = { - STATE_NEED_CLIENT_VERSION: 10, - STATE_NEED_CLIENT_SECURITY: 20, - STATE_NEED_CLIENT_INIT: 30, - STATE_NEED_CLIENT_VNC_AUTH: 31, - STATE_NEED_CLIENT_MESSAGE: 40, - STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT: 50, - STATE_NEED_CLIENT_MESSAGE_SETENCODINGS: 60, - STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE: 61, - STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST: 70, - STATE_NEED_CLIENT_MESSAGE_KEYEVENT: 80, - STATE_NEED_CLIENT_MESSAGE_POINTEREVENT: 90, - STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT: 100, - STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE: 101 -} -VncConnection.ENCODING_RAW = 0 -VncConnection.ENCODING_DESKTOPSIZE = -223 -Object.keys(State).map(function(name) { - VncConnection[name] = State[name] - StateReverse[State[name]] = name -}) -VncConnection.prototype.end = function() { - this.conn.end() -} -VncConnection.prototype.writeFramebufferUpdate = function(rectangles) { - var chunk = Buffer.alloc(4) - chunk[0] = VncConnection.SERVER_MESSAGE_FBUPDATE - chunk[1] = 0 - chunk.writeUInt16BE(rectangles.length, 2) - this._write(chunk) - rectangles.forEach(function(rect) { - var rchunk = Buffer.alloc(12) - rchunk.writeUInt16BE(rect.xPosition, 0) - rchunk.writeUInt16BE(rect.yPosition, 2) - rchunk.writeUInt16BE(rect.width, 4) - rchunk.writeUInt16BE(rect.height, 6) - rchunk.writeInt32BE(rect.encodingType, 8) - this._write(rchunk) - switch (rect.encodingType) { - case VncConnection.ENCODING_RAW: - this._write(rect.data) - break - case VncConnection.ENCODING_DESKTOPSIZE: - this._serverWidth = rect.width - this._serverHeight = rect.height - break - default: - throw new Error(util.format('Unsupported encoding type', rect.encodingType)) - } - }, this) -} -VncConnection.prototype._error = function(err) { - this.emit('error', err) - this.end() -} -VncConnection.prototype._errorListener = function(err) { - this._error(err) -} -VncConnection.prototype._endListener = function() { - this.emit('end') -} -VncConnection.prototype._closeListener = function() { - this.emit('close') -} -VncConnection.prototype._writeServerVersion = function() { - // Yes, we could just format the string instead. Didn't feel like it. - switch (this._serverVersion) { - case VncConnection.V3_003: - this._write(Buffer.from('RFB 003.003\n')) - break - case VncConnection.V3_007: - this._write(Buffer.from('RFB 003.007\n')) - break - case VncConnection.V3_008: - this._write(Buffer.from('RFB 003.008\n')) - break - } -} -VncConnection.prototype._writeSupportedSecurity = function() { - var chunk = Buffer.alloc(1 + this._serverSupportedSecurity.length) - chunk[0] = this._serverSupportedSecurity.length - this._serverSupportedSecurity.forEach(function(security, i) { - chunk[1 + i] = security.type - }) - this._write(chunk) -} -VncConnection.prototype._writeSecurityResult = function(result, reason) { - var chunk - switch (result) { - case VncConnection.SECURITYRESULT_OK: - chunk = Buffer.alloc(4) - chunk.writeUInt32BE(result, 0) - this._write(chunk) - break - case VncConnection.SECURITYRESULT_FAIL: - chunk = Buffer.alloc(4 + 4 + reason.length) - chunk.writeUInt32BE(result, 0) - chunk.writeUInt32BE(reason.length, 4) - chunk.write(reason, 8, reason.length) - this._write(chunk) - break - } -} -VncConnection.prototype._writeServerInit = function() { - debug('server pixel format', this._serverPixelFormat) - var chunk = Buffer.alloc(2 + 2 + 16 + 4 + this._serverName.length) - chunk.writeUInt16BE(this._serverWidth, 0) - chunk.writeUInt16BE(this._serverHeight, 2) - chunk[4] = this._serverPixelFormat.bitsPerPixel - chunk[5] = this._serverPixelFormat.depth - chunk[6] = this._serverPixelFormat.bigEndianFlag - chunk[7] = this._serverPixelFormat.trueColorFlag - chunk.writeUInt16BE(this._serverPixelFormat.redMax, 8) - chunk.writeUInt16BE(this._serverPixelFormat.greenMax, 10) - chunk.writeUInt16BE(this._serverPixelFormat.blueMax, 12) - chunk[14] = this._serverPixelFormat.redShift - chunk[15] = this._serverPixelFormat.greenShift - chunk[16] = this._serverPixelFormat.blueShift - chunk[17] = 0 // padding - chunk[18] = 0 // padding - chunk[19] = 0 // padding - chunk.writeUInt32BE(this._serverName.length, 20) - chunk.write(this._serverName, 24, this._serverName.length) - this._write(chunk) -} -VncConnection.prototype._writeVncAuthChallenge = function() { - var vncSec = this._serverSupportedSecurityByType[VncConnection.SECURITY_VNC] - debug('vnc auth challenge', vncSec.challenge) - this._write(vncSec.challenge) -} -VncConnection.prototype._readableListener = function() { - this._read() -} -VncConnection.prototype._read = function() { - Promise.all(this._blockingOps).bind(this) - .then(this._unguardedRead) -} -VncConnection.prototype._auth = function(type, data) { - var security = this._serverSupportedSecurityByType[type] - this._blockingOps.push(security.auth(data).bind(this) - .then(function() { - this._changeState(VncConnection.STATE_NEED_CLIENT_INIT) - this._writeSecurityResult(VncConnection.SECURITYRESULT_OK) - this.emit('authenticated') - this._read() - }) - .catch(function() { - this._writeSecurityResult(VncConnection.SECURITYRESULT_FAIL, 'Authentication failure') - this.end() - })) -} -VncConnection.prototype._unguardedRead = function() { - var chunk, lo, hi - while (this._append(this.conn.read())) { - do { - debug('state', StateReverse[this._state]) - chunk = null - switch (this._state) { - case VncConnection.STATE_NEED_CLIENT_VERSION: - if ((chunk = this._consume(12))) { - if ((this._clientVersion = this._parseVersion(chunk)) === null) { - this.end() - return - } - debug('client version', this._clientVersion) - this._writeSupportedSecurity() - this._changeState(VncConnection.STATE_NEED_CLIENT_SECURITY) - } - break - case VncConnection.STATE_NEED_CLIENT_SECURITY: - if ((chunk = this._consume(1))) { - if ((this._clientSecurity = this._parseSecurity(chunk)) === null) { - this._writeSecurityResult(VncConnection.SECURITYRESULT_FAIL, 'Unimplemented security type') - this.end() - return - } - debug('client security', this._clientSecurity) - if (!(this._clientSecurity in this._serverSupportedSecurityByType)) { - this._writeSecurityResult(VncConnection.SECURITYRESULT_FAIL, 'Unsupported security type') - this.end() - return - } - switch (this._clientSecurity) { - case VncConnection.SECURITY_NONE: - // TODO: investigate more elegant way of passing security challenge - // his._auth(VncConnection.SECURITY_NONE) - this._changeState(VncConnection.STATE_NEED_CLIENT_INIT) - this._writeSecurityResult(VncConnection.SECURITYRESULT_OK) - this.emit('authenticated') - return - case VncConnection.SECURITY_VNC: - this._writeVncAuthChallenge() - this._changeState(VncConnection.STATE_NEED_CLIENT_VNC_AUTH) - break - } - } - break - case VncConnection.STATE_NEED_CLIENT_VNC_AUTH: - if ((chunk = this._consume(16))) { - this._auth(VncConnection.SECURITY_VNC, { - response: chunk - }) - return - } - break - case VncConnection.STATE_NEED_CLIENT_INIT: - if ((chunk = this._consume(1))) { - this._clientShare = chunk[0] - debug('client shareFlag', this._clientShare) - this._writeServerInit() - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE: - if ((chunk = this._consume(1))) { - switch (chunk[0]) { - case VncConnection.CLIENT_MESSAGE_SETPIXELFORMAT: - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT) - break - case VncConnection.CLIENT_MESSAGE_SETENCODINGS: - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS) - break - case VncConnection.CLIENT_MESSAGE_FBUPDATEREQUEST: - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST) - break - case VncConnection.CLIENT_MESSAGE_KEYEVENT: - this.emit('userActivity') - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_KEYEVENT) - break - case VncConnection.CLIENT_MESSAGE_POINTEREVENT: - this.emit('userActivity') - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_POINTEREVENT) - break - case VncConnection.CLIENT_MESSAGE_CLIENTCUTTEXT: - this.emit('userActivity') - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT) - break - default: - this._error(new Error(util.format('Unsupported message type %d', chunk[0]))) - return - } - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT: - if ((chunk = this._consume(19))) { - // [0b, 3b) padding - this._clientPixelFormat = new PixelFormat({ - bitsPerPixel: chunk[3], - depth: chunk[4], - bigEndianFlag: chunk[5], - trueColorFlag: chunk[6], - redMax: chunk.readUInt16BE(7, true), - greenMax: chunk.readUInt16BE(9, true), - blueMax: chunk.readUInt16BE(11, true), - redShift: chunk[13], - greenShift: chunk[14], - blueShift: chunk[15] - }) - // [16b, 19b) padding - debug('client pixel format', this._clientPixelFormat) - this.emit('formatchange', this._clientPixelFormat) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS: - if ((chunk = this._consume(3))) { - // [0b, 1b) padding - this._clientEncodingCount = chunk.readUInt16BE(1, true) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE: - lo = 0 - hi = 4 * this._clientEncodingCount - if ((chunk = this._consume(hi))) { - this._clientEncodings = [] - while (lo < hi) { - this._clientEncodings.push(chunk.readInt32BE(lo, true)) - lo += 4 - } - debug('client encodings', this._clientEncodings) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST: - if ((chunk = this._consume(9))) { - this.emit('fbupdaterequest', { - incremental: chunk[0], - xPosition: chunk.readUInt16BE(1, true), - yPosition: chunk.readUInt16BE(3, true), - width: chunk.readUInt16BE(5, true), - height: chunk.readUInt16BE(7, true) - }) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_KEYEVENT: - if ((chunk = this._consume(7))) { - // downFlag = chunk[0] - // [1b, 3b) padding - // key = chunk.readUInt32BE(3, true) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_POINTEREVENT: - if ((chunk = this._consume(5))) { - this.emit('pointer', { - buttonMask: chunk[0], - xPosition: chunk.readUInt16BE(1, true) / this._serverWidth, - yPosition: chunk.readUInt16BE(3, true) / this._serverHeight - }) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT: - if ((chunk = this._consume(7))) { - // [0b, 3b) padding - this._clientCutTextLength = chunk.readUInt32BE(3) - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE) - } - break - case VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE: - if ((chunk = this._consume(this._clientCutTextLength))) { - // value = chunk - this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) - } - break - default: - throw new Error(util.format('Impossible state %d', this._state)) - } - } while (chunk) - } -} -VncConnection.prototype._parseVersion = function(chunk) { - if (chunk.equals(Buffer.from('RFB 003.008\n'))) { - return VncConnection.V3_008 - } - if (chunk.equals(Buffer.from('RFB 003.007\n'))) { - return VncConnection.V3_007 - } - if (chunk.equals(Buffer.from('RFB 003.003\n'))) { - return VncConnection.V3_003 - } - return null -} -VncConnection.prototype._parseSecurity = function(chunk) { - switch (chunk[0]) { - case VncConnection.SECURITY_NONE: - case VncConnection.SECURITY_VNC: - return chunk[0] - default: - return null - } -} -VncConnection.prototype._changeState = function(state) { - this._state = state -} -VncConnection.prototype._append = function(chunk) { - if (!chunk) { - return false - } - debug('in', chunk) - if (this._buffer) { - this._buffer = Buffer.concat([this._buffer, chunk], this._buffer.length + chunk.length) - } - else { - this._buffer = chunk - } - return true -} -VncConnection.prototype._consume = function(n) { - var chunk - if (!this._buffer) { - return null - } - if (n < this._buffer.length) { - chunk = this._buffer.slice(0, n) - this._buffer = this._buffer.slice(n) - return chunk - } - if (n === this._buffer.length) { - chunk = this._buffer - this._buffer = null - return chunk - } - return null -} -VncConnection.prototype._write = function(chunk) { - debug('out', chunk) - this.conn.write(chunk) -} -export default VncConnection diff --git a/lib/units/device/plugins/vnc/util/connection.ts b/lib/units/device/plugins/vnc/util/connection.ts new file mode 100644 index 0000000000..05c84eba20 --- /dev/null +++ b/lib/units/device/plugins/vnc/util/connection.ts @@ -0,0 +1,753 @@ +import util from 'util' +import os from 'os' +import crypto from 'crypto' +import EventEmitter from 'events' +import { Socket } from 'net' +import PixelFormat from './pixelformat.js' +import logger from '../../../../../util/logger.js' + +const _logger = logger.createLogger('vnc:connection') +const debug = _logger.debug.bind(_logger) + +interface SecurityMethod { + type: number + challenge?: Buffer + auth: (data: AuthData) => Promise +} + +interface VncConnectionOptions { + width: number + height: number + name: string + challenge?: Buffer + security?: SecurityMethod[] +} + +interface AuthData { + response: Buffer +} + +interface Rectangle { + xPosition: number + yPosition: number + width: number + height: number + encodingType: number + data?: Buffer +} + +interface FbUpdateRequest { + incremental: number + xPosition: number + yPosition: number + width: number + height: number +} + +interface PointerEvent { + buttonMask: number + xPosition: number + yPosition: number +} + +class VncConnection extends EventEmitter { + // Version constants + static readonly V3_003 = 3003 + static readonly V3_007 = 3007 + static readonly V3_008 = 3008 + + // Security constants + static readonly SECURITY_NONE = 1 + static readonly SECURITY_VNC = 2 + + // Security result constants + static readonly SECURITYRESULT_OK = 0 + static readonly SECURITYRESULT_FAIL = 1 + + // Client message constants + static readonly CLIENT_MESSAGE_SETPIXELFORMAT = 0 + static readonly CLIENT_MESSAGE_SETENCODINGS = 2 + static readonly CLIENT_MESSAGE_FBUPDATEREQUEST = 3 + static readonly CLIENT_MESSAGE_KEYEVENT = 4 + static readonly CLIENT_MESSAGE_POINTEREVENT = 5 + static readonly CLIENT_MESSAGE_CLIENTCUTTEXT = 6 + + // Server message constants + static readonly SERVER_MESSAGE_FBUPDATE = 0 + + // Encoding constants + static readonly ENCODING_RAW = 0 + static readonly ENCODING_TIGHT = 7 + static readonly ENCODING_DESKTOPSIZE = -223 + + // State constants + static readonly STATE_NEED_CLIENT_VERSION = 10 + static readonly STATE_NEED_CLIENT_SECURITY = 20 + static readonly STATE_NEED_CLIENT_INIT = 30 + static readonly STATE_NEED_CLIENT_VNC_AUTH = 31 + static readonly STATE_NEED_CLIENT_MESSAGE = 40 + static readonly STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT = 50 + static readonly STATE_NEED_CLIENT_MESSAGE_SETENCODINGS = 60 + static readonly STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE = 61 + static readonly STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST = 70 + static readonly STATE_NEED_CLIENT_MESSAGE_KEYEVENT = 80 + static readonly STATE_NEED_CLIENT_MESSAGE_POINTEREVENT = 90 + static readonly STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT = 100 + static readonly STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE = 101 + + options: VncConnectionOptions + conn: Socket + private _buffer: Buffer | null + private _state: number + private _serverVersion: number + private _serverSupportedSecurity: SecurityMethod[] + private _serverSupportedSecurityByType: Record + private _serverWidth: number + private _serverHeight: number + private _serverPixelFormat: PixelFormat + private _serverName: string + private _clientVersion: number | null + private _clientSecurity?: number + private _clientShare: number + private _clientPixelFormat: PixelFormat + private _clientEncodingCount: number + private _clientEncodings: number[] + private _clientCutTextLength: number + private _authChallenge: Buffer + private _blockingOps: Array> + + constructor(conn: Socket, options: VncConnectionOptions) { + super() + this.options = options + this._buffer = null + this._state = 0 + this._changeState(VncConnection.STATE_NEED_CLIENT_VERSION) + this._serverVersion = VncConnection.V3_008 + + // If no security is provided, default to accepting both SECURITY_VNC and SECURITY_NONE + // with an auth handler that always succeeds (accepts any password) + // IMPORTANT: SECURITY_VNC must be FIRST because RFB 3.003 clients (like macOS Screen Sharing) + // only use the first security type in the array (no negotiation), and macOS requires VNC auth + if (!this.options.security || this.options.security.length === 0) { + this._serverSupportedSecurity = [ + { + type: VncConnection.SECURITY_VNC, + challenge: crypto.randomBytes(16), + auth: async () => { + /* Accept any password - no verification */ + debug('VNC auth: accepting any password (no security configured)') + } + }, + { + type: VncConnection.SECURITY_NONE, + auth: async () => { /* No authentication needed */ } + } + ] + } else { + this._serverSupportedSecurity = this.options.security + } + + this._serverSupportedSecurityByType = this._serverSupportedSecurity.reduce( + (map: Record, method: SecurityMethod) => { + map[method.type] = method + return map + }, + Object.create(null) + ) + this._serverWidth = this.options.width + this._serverHeight = this.options.height + this._serverPixelFormat = new PixelFormat({ + bitsPerPixel: 32, + depth: 24, + bigEndianFlag: os.endianness() === 'BE' ? 1 : 0, + trueColorFlag: 1, + redMax: 255, + greenMax: 255, + blueMax: 255, + redShift: 16, + greenShift: 8, + blueShift: 0 + }) + this._serverName = this.options.name + this._clientVersion = null + this._clientShare = 0 + this._clientPixelFormat = this._serverPixelFormat + this._clientEncodingCount = 0 + this._clientEncodings = [] + this._clientCutTextLength = 0 + this._authChallenge = this.options.challenge || crypto.randomBytes(16) + this.conn = conn + .on('error', this._errorListener) + .on('readable', this._readableListener) + .on('end', this._endListener) + .on('close', this._closeListener) + this._blockingOps = [] + this._writeServerVersion() + this._read() + } + + end(): void { + if (!this.conn.destroyed) { + this.conn.end() + } + } + + updateDimensions(width: number, height: number): void { + debug(`Updating server dimensions from ${this._serverWidth}x${this._serverHeight} to ${width}x${height}`) + this._serverWidth = width + this._serverHeight = height + } + + writeFramebufferUpdate(rectangles: Rectangle[]): void { + const chunk = Buffer.alloc(4) + chunk[0] = VncConnection.SERVER_MESSAGE_FBUPDATE + chunk[1] = 0 + chunk.writeUInt16BE(rectangles.length, 2) + this._write(chunk) + rectangles.forEach((rect: any) => { + const rchunk = Buffer.alloc(12) + rchunk.writeUInt16BE(rect.xPosition, 0) + rchunk.writeUInt16BE(rect.yPosition, 2) + rchunk.writeUInt16BE(rect.width, 4) + rchunk.writeUInt16BE(rect.height, 6) + rchunk.writeInt32BE(rect.encodingType, 8) + this._write(rchunk) + switch (rect.encodingType) { + case VncConnection.ENCODING_RAW: + if (rect.data) { + this._write(rect.data) + } + break + case VncConnection.ENCODING_TIGHT: + // Tight encoding with JPEG compression + if (rect.jpegData) { + // Compression control byte (0x90 = JPEG compression) + const compressionControl = Buffer.alloc(1) + compressionControl[0] = rect.compressionControl || 0x90 + this._write(compressionControl) + + // Write JPEG data length in compact representation + const jpegLength = rect.jpegData.length + const lengthBuf = this._encodeCompactLength(jpegLength) + this._write(lengthBuf) + + // Write JPEG data + this._write(rect.jpegData) + } + break + case VncConnection.ENCODING_DESKTOPSIZE: + this._serverWidth = rect.width + this._serverHeight = rect.height + break + default: + throw new Error(util.format('Unsupported encoding type', rect.encodingType)) + } + }) + } + + private _encodeCompactLength(length: number): Buffer { + // Tight encoding uses compact length representation + // 0-127: 1 byte + // 128-16383: 2 bytes + // 16384+: 3 bytes + if (length < 128) { + const buf = Buffer.alloc(1) + buf[0] = length + return buf + } else if (length < 16384) { + const buf = Buffer.alloc(2) + buf[0] = (length & 0x7F) | 0x80 + buf[1] = (length >> 7) & 0xFF + return buf + } else { + const buf = Buffer.alloc(3) + buf[0] = (length & 0x7F) | 0x80 + buf[1] = ((length >> 7) & 0x7F) | 0x80 + buf[2] = (length >> 14) & 0xFF + return buf + } + } + + private _error(err: Error): void { + this.emit('error', err) + if (!this.conn.destroyed) { + this.end() + } + } + + private _errorListener = (err: Error): void => { + this._error(err) + } + + private _endListener = (): void => { + this.emit('end') + } + + private _closeListener = (): void => { + this.emit('close') + } + + private _writeServerVersion(): void { + switch (this._serverVersion) { + case VncConnection.V3_003: + this._write(Buffer.from('RFB 003.003\n')) + break + case VncConnection.V3_007: + this._write(Buffer.from('RFB 003.007\n')) + break + case VncConnection.V3_008: + this._write(Buffer.from('RFB 003.008\n')) + break + } + } + + private _writeSupportedSecurity(): void { + const chunk = Buffer.alloc(1 + this._serverSupportedSecurity.length) + chunk[0] = this._serverSupportedSecurity.length + this._serverSupportedSecurity.forEach((security, i) => { + chunk[1 + i] = security.type + }) + this._write(chunk) + } + + private _writeSupportedSecurityV3_003(): void { + // RFB 3.003: Server sends 4-byte UINT32 with security type (no negotiation) + const chunk = Buffer.alloc(4) + const secType = this._serverSupportedSecurity.length > 0 + ? this._serverSupportedSecurity[0].type + : VncConnection.SECURITY_NONE + chunk.writeUInt32BE(secType, 0) + this._write(chunk) + } + + private _writeSecurityResult(result: number, reason?: string): void { + let chunk: Buffer + switch (result) { + case VncConnection.SECURITYRESULT_OK: + chunk = Buffer.alloc(4) + chunk.writeUInt32BE(result, 0) + this._write(chunk) + break + case VncConnection.SECURITYRESULT_FAIL: + if (!reason) { + reason = 'Unknown error' + } + chunk = Buffer.alloc(4 + 4 + reason.length) + chunk.writeUInt32BE(result, 0) + chunk.writeUInt32BE(reason.length, 4) + chunk.write(reason, 8, reason.length) + this._write(chunk) + break + } + } + + private _writeServerInit(): void { + debug('server pixel format %s', this._serverPixelFormat) + debug(`ServerInit: ${this._serverWidth}x${this._serverHeight}, name=${this._serverName}`) + const chunk = Buffer.alloc(2 + 2 + 16 + 4 + this._serverName.length) + chunk.writeUInt16BE(this._serverWidth, 0) + chunk.writeUInt16BE(this._serverHeight, 2) + chunk[4] = this._serverPixelFormat.bitsPerPixel + chunk[5] = this._serverPixelFormat.depth + chunk[6] = this._serverPixelFormat.bigEndianFlag + chunk[7] = this._serverPixelFormat.trueColorFlag + chunk.writeUInt16BE(this._serverPixelFormat.redMax, 8) + chunk.writeUInt16BE(this._serverPixelFormat.greenMax, 10) + chunk.writeUInt16BE(this._serverPixelFormat.blueMax, 12) + chunk[14] = this._serverPixelFormat.redShift + chunk[15] = this._serverPixelFormat.greenShift + chunk[16] = this._serverPixelFormat.blueShift + chunk[17] = 0 // padding + chunk[18] = 0 // padding + chunk[19] = 0 // padding + chunk.writeUInt32BE(this._serverName.length, 20) + chunk.write(this._serverName, 24, this._serverName.length) + this._write(chunk) + } + + private _writeVncAuthChallenge(): void { + const vncSec = this._serverSupportedSecurityByType[VncConnection.SECURITY_VNC] + debug('vnc auth challenge %s', vncSec.challenge) + if (vncSec.challenge) { + this._write(vncSec.challenge) + } + } + + private _readableListener = (): void => { + this._read() + } + + private _read(): void { + Promise.all(this._blockingOps) + .then(() => this._unguardedRead()) + .catch((err) => { + debug('_read() promise rejected: %s', err?.message || err) + }) + } + + private _auth(type: number, data: AuthData): void { + const security = this._serverSupportedSecurityByType[type] + const success = () => { + this._changeState(VncConnection.STATE_NEED_CLIENT_INIT) + // RFB 3.003 spec says not to send security result, but many clients (especially macOS Screen Sharing) + // expect it anyway. Send it for compatibility. + this._writeSecurityResult(VncConnection.SECURITYRESULT_OK) + debug('VNC authenticated successfully') + this.emit('authenticated') + // Don't call _read() here - let the promise completion trigger it + } + + if (!security) { + success() + // Manually trigger read after synchronous success + this._read() + return + } + + const authPromise = security + .auth(data) + .then(() => { + success() + }) + .catch((err) => { + debug('auth failed: %s', err?.message || err) + // Send security result for compatibility (see success case) + this._writeSecurityResult( + VncConnection.SECURITYRESULT_FAIL, + 'Authentication failure' + ) + this.end() + }) + .finally(() => { + // Remove this promise from blocking ops after completion + const index = this._blockingOps.indexOf(authPromise) + if (index > -1) { + this._blockingOps.splice(index, 1) + } + // Trigger next read cycle after auth completes + // Use setImmediate to break out of the promise context + setImmediate(() => { + this._read() + }) + }) + + this._blockingOps.push(authPromise) + } + + private _unguardedRead(): void { + let chunk: Buffer | null + let lo: number + let hi: number + while (this._append(this.conn.read())) { + do { + chunk = null + switch (this._state) { + case VncConnection.STATE_NEED_CLIENT_VERSION: + if ((chunk = this._consume(12))) { + const parsedVersion = this._parseVersion(chunk) + if (parsedVersion === null) { + debug('ERROR: Invalid client version string: %s', chunk.toString()) + this.end() + return + } + this._clientVersion = parsedVersion + const versionString = parsedVersion === VncConnection.V3_003 ? '3.003' : + parsedVersion === VncConnection.V3_007 ? '3.007' : '3.008' + debug(`Client version: RFB ${versionString} (${parsedVersion})`) + + // RFB 3.003 uses a different security handshake than 3.007/3.008 + if (this._clientVersion === VncConnection.V3_003) { + this._writeSupportedSecurityV3_003() + // For 3.003, no client selection - move based on security type + if (this._serverSupportedSecurity.length === 0) { + this._error(new Error('No security methods available')) + return + } + const secType = this._serverSupportedSecurity[0].type + this._clientSecurity = secType + + if (secType === VncConnection.SECURITY_NONE) { + this._changeState(VncConnection.STATE_NEED_CLIENT_INIT) + this.emit('authenticated') + } else if (secType === VncConnection.SECURITY_VNC) { + this._writeVncAuthChallenge() + this._changeState(VncConnection.STATE_NEED_CLIENT_VNC_AUTH) + } else { + this._error(new Error('Unsupported security type for RFB 3.003')) + return + } + } else { + // RFB 3.007 and 3.008 + this._writeSupportedSecurity() + this._changeState(VncConnection.STATE_NEED_CLIENT_SECURITY) + } + } + break + case VncConnection.STATE_NEED_CLIENT_SECURITY: + if ((chunk = this._consume(1))) { + const parsedSecurity = this._parseSecurity(chunk) + if (parsedSecurity === null) { + this._writeSecurityResult( + VncConnection.SECURITYRESULT_FAIL, + 'Unimplemented security type' + ) + this.end() + return + } + this._clientSecurity = parsedSecurity + debug('client security %s', this._clientSecurity) + if (!(this._clientSecurity in this._serverSupportedSecurityByType)) { + this._writeSecurityResult( + VncConnection.SECURITYRESULT_FAIL, + 'Unsupported security type' + ) + this.end() + return + } + switch (this._clientSecurity) { + case VncConnection.SECURITY_NONE: + this._changeState(VncConnection.STATE_NEED_CLIENT_INIT) + // RFB 3.007/3.008 send security result, 3.003 doesn't (but won't reach here) + if (this._clientVersion !== VncConnection.V3_003) { + this._writeSecurityResult(VncConnection.SECURITYRESULT_OK) + } + this.emit('authenticated') + return + case VncConnection.SECURITY_VNC: + this._writeVncAuthChallenge() + this._changeState(VncConnection.STATE_NEED_CLIENT_VNC_AUTH) + break + } + } + break + case VncConnection.STATE_NEED_CLIENT_VNC_AUTH: + if ((chunk = this._consume(16))) { + this._auth(VncConnection.SECURITY_VNC, { + response: chunk + }) + return + } + break + case VncConnection.STATE_NEED_CLIENT_INIT: + if ((chunk = this._consume(1))) { + this._clientShare = chunk[0] + debug('client shareFlag %s', this._clientShare) + this._writeServerInit() + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE: + if ((chunk = this._consume(1))) { + const messageType = chunk[0] + // debug(`Client message type: ${messageType}`) + switch (messageType) { + case VncConnection.CLIENT_MESSAGE_SETPIXELFORMAT: + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT) + break + case VncConnection.CLIENT_MESSAGE_SETENCODINGS: + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS) + break + case VncConnection.CLIENT_MESSAGE_FBUPDATEREQUEST: + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST) + break + case VncConnection.CLIENT_MESSAGE_KEYEVENT: + this.emit('userActivity') + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_KEYEVENT) + break + case VncConnection.CLIENT_MESSAGE_POINTEREVENT: + this.emit('userActivity') + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_POINTEREVENT) + break + case VncConnection.CLIENT_MESSAGE_CLIENTCUTTEXT: + this.emit('userActivity') + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT) + break + default: + this._error(new Error(util.format('Unsupported message type %d', messageType))) + return + } + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT: + if ((chunk = this._consume(19))) { + // [0b, 3b) padding + this._clientPixelFormat = new PixelFormat({ + bitsPerPixel: chunk[3], + depth: chunk[4], + bigEndianFlag: chunk[5], + trueColorFlag: chunk[6], + redMax: chunk.readUInt16BE(7), + greenMax: chunk.readUInt16BE(9), + blueMax: chunk.readUInt16BE(11), + redShift: chunk[13], + greenShift: chunk[14], + blueShift: chunk[15] + }) + // [16b, 19b) padding + debug('client pixel format %s', this._clientPixelFormat) + this.emit('formatchange', this._clientPixelFormat) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS: + if ((chunk = this._consume(3))) { + // [0b, 1b) padding + this._clientEncodingCount = chunk.readUInt16BE(1) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_SETENCODINGS_VALUE: + lo = 0 + hi = 4 * this._clientEncodingCount + if ((chunk = this._consume(hi))) { + this._clientEncodings = [] + while (lo < hi) { + this._clientEncodings.push(chunk.readInt32BE(lo)) + lo += 4 + } + debug('client encodings %s', this._clientEncodings) + this.emit('encodings', this._clientEncodings) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST: + if ((chunk = this._consume(9))) { + this.emit('fbupdaterequest', { + incremental: chunk[0], + xPosition: chunk.readUInt16BE(1), + yPosition: chunk.readUInt16BE(3), + width: chunk.readUInt16BE(5), + height: chunk.readUInt16BE(7) + } as FbUpdateRequest) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_KEYEVENT: + if ((chunk = this._consume(7))) { + // downFlag = chunk[0] + // [1b, 3b) padding + // key = chunk.readUInt32BE(3) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_POINTEREVENT: + if ((chunk = this._consume(5))) { + const buttonMask = chunk[0] + const xPixel = chunk.readUInt16BE(1) + const yPixel = chunk.readUInt16BE(3) + + // Prevent division by zero - if dimensions are not set, use pixel coordinates as normalized (assuming 0-1 range) + if (this._serverWidth === 0 || this._serverHeight === 0) { + debug(`WARNING: Server dimensions not set (${this._serverWidth}x${this._serverHeight}), cannot normalize pointer coordinates`) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + break + } + + const xNorm = xPixel / this._serverWidth + const yNorm = yPixel / this._serverHeight + + debug(`Pointer event received: button=${buttonMask}, x=${xPixel}/${this._serverWidth}=${xNorm.toFixed(3)}, y=${yPixel}/${this._serverHeight}=${yNorm.toFixed(3)}`) + + this.emit('pointer', { + buttonMask: buttonMask, + xPosition: xNorm, + yPosition: yNorm + } as PointerEvent) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT: + if ((chunk = this._consume(7))) { + // [0b, 3b) padding + this._clientCutTextLength = chunk.readUInt32BE(3) + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE) + } + break + case VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT_VALUE: + if ((chunk = this._consume(this._clientCutTextLength))) { + // value = chunk + this._changeState(VncConnection.STATE_NEED_CLIENT_MESSAGE) + } + break + default: + throw new Error(util.format('Impossible state %d', this._state)) + } + } while (chunk) + } + } + + private _parseVersion(chunk: Buffer): number | null { + if (chunk.equals(Buffer.from('RFB 003.008\n'))) { + return VncConnection.V3_008 + } + if (chunk.equals(Buffer.from('RFB 003.007\n'))) { + return VncConnection.V3_007 + } + if (chunk.equals(Buffer.from('RFB 003.003\n'))) { + return VncConnection.V3_003 + } + return null + } + + private _parseSecurity(chunk: Buffer): number | null { + switch (chunk[0]) { + case VncConnection.SECURITY_NONE: + case VncConnection.SECURITY_VNC: + return chunk[0] + default: + return null + } + } + + private _changeState(state: number): void { + this._state = state + } + + private _append(chunk: Buffer | null): boolean { + if (!chunk) { + return false + } + // debug('in %s', chunk) + if (this._buffer) { + this._buffer = Buffer.concat([this._buffer, chunk], this._buffer.length + chunk.length) + } else { + this._buffer = chunk + } + return true + } + + private _consume(n: number): Buffer | null { + let chunk: Buffer + if (!this._buffer) { + return null + } + if (n < this._buffer.length) { + chunk = this._buffer.slice(0, n) + this._buffer = this._buffer.slice(n) + return chunk + } + if (n === this._buffer.length) { + chunk = this._buffer + this._buffer = null + return chunk + } + return null + } + + private _write(chunk: Buffer): void { + try { + if (!this.conn.destroyed && this.conn.writable) { + this.conn.write(chunk) + } + } catch (err: any) { + // Ignore EPIPE and ECONNRESET errors - client disconnected + if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') { + debug(`Write error: ${err?.message || err}`) + throw err + } + } + } +} + +export default VncConnection + diff --git a/lib/units/device/plugins/vnc/util/pixelformat.js b/lib/units/device/plugins/vnc/util/pixelformat.js deleted file mode 100644 index 0827192d48..0000000000 --- a/lib/units/device/plugins/vnc/util/pixelformat.js +++ /dev/null @@ -1,13 +0,0 @@ -function PixelFormat(values) { - this.bitsPerPixel = values.bitsPerPixel - this.depth = values.depth - this.bigEndianFlag = values.bigEndianFlag - this.trueColorFlag = values.trueColorFlag - this.redMax = values.redMax - this.greenMax = values.greenMax - this.blueMax = values.blueMax - this.redShift = values.redShift - this.greenShift = values.greenShift - this.blueShift = values.blueShift -} -export default PixelFormat diff --git a/lib/units/device/plugins/vnc/util/pixelformat.ts b/lib/units/device/plugins/vnc/util/pixelformat.ts new file mode 100644 index 0000000000..549f472b4e --- /dev/null +++ b/lib/units/device/plugins/vnc/util/pixelformat.ts @@ -0,0 +1,41 @@ +interface PixelFormatValues { + bitsPerPixel: number + depth: number + bigEndianFlag: number + trueColorFlag: number + redMax: number + greenMax: number + blueMax: number + redShift: number + greenShift: number + blueShift: number +} + +class PixelFormat { + bitsPerPixel: number + depth: number + bigEndianFlag: number + trueColorFlag: number + redMax: number + greenMax: number + blueMax: number + redShift: number + greenShift: number + blueShift: number + + constructor(values: PixelFormatValues) { + this.bitsPerPixel = values.bitsPerPixel + this.depth = values.depth + this.bigEndianFlag = values.bigEndianFlag + this.trueColorFlag = values.trueColorFlag + this.redMax = values.redMax + this.greenMax = values.greenMax + this.blueMax = values.blueMax + this.redShift = values.redShift + this.greenShift = values.greenShift + this.blueShift = values.blueShift + } +} + +export default PixelFormat + diff --git a/lib/units/device/plugins/vnc/util/pointertranslator.js b/lib/units/device/plugins/vnc/util/pointertranslator.js deleted file mode 100644 index 511c8df1bc..0000000000 --- a/lib/units/device/plugins/vnc/util/pointertranslator.js +++ /dev/null @@ -1,58 +0,0 @@ -import util from 'util' -import EventEmitter from 'eventemitter3' -function PointerTranslator() { - this.previousEvent = null -} -util.inherits(PointerTranslator, EventEmitter) -PointerTranslator.prototype.push = function(event) { - if (event.buttonMask & 0xFE) { - // Non-primary buttons included, ignore. - return - } - if (this.previousEvent) { - var buttonChanges = event.buttonMask ^ this.previousEvent.buttonMask - // If the primary button changed, we have an up/down event. - if (buttonChanges & 1) { - // If it's pressed now, that's a down event. - if (event.buttonMask & 1) { - this.emit('touchdown', { - contact: 1, - x: event.xPosition, - y: event.yPosition - }) - this.emit('touchcommit') - } - // It's not pressed, so we have an up event. - else { - this.emit('touchup', { - contact: 1 - }) - this.emit('touchcommit') - } - } - // Otherwise, if we're still holding the primary button down, - // that's a move event. - else if (event.buttonMask & 1) { - this.emit('touchmove', { - contact: 1, - x: event.xPosition, - y: event.yPosition - }) - this.emit('touchcommit') - } - } - else { - // If it's the first event we get and the primary button's pressed, - // it's a down event. - if (event.buttonMask & 1) { - this.emit('touchdown', { - contact: 1, - x: event.xPosition, - y: event.yPosition - }) - this.emit('touchcommit') - } - } - this.previousEvent = event -} -export default PointerTranslator diff --git a/lib/units/device/plugins/vnc/util/pointertranslator.ts b/lib/units/device/plugins/vnc/util/pointertranslator.ts new file mode 100644 index 0000000000..12a15c4fb6 --- /dev/null +++ b/lib/units/device/plugins/vnc/util/pointertranslator.ts @@ -0,0 +1,79 @@ +import EventEmitter from 'events' + +interface PointerEvent { + buttonMask: number + xPosition: number + yPosition: number +} + +interface TouchEvent { + seq: number + contact: number + x?: number + y?: number + pressure?: number +} + +class PointerTranslator extends EventEmitter { + private gestureStarted = false + private seq = 0 + + push(event: PointerEvent): void { + if (!this.gestureStarted) { + if (!event.buttonMask) { + return + } + + this.emit('touchstart', { + seq: this.seq++ + }) + + this.emit('touchdown', { + seq: this.seq++, + contact: 0, + x: event.xPosition, + y: event.yPosition, + pressure: 0.5 + } as TouchEvent) + + this.emit('touchcommit', { + seq: this.seq++ + }) + + this.gestureStarted = true + return + } + + if (event.buttonMask) { + this.emit('touchmove', { + seq: this.seq++, + contact: 0, + x: event.xPosition, + y: event.yPosition, + pressure: 0.5 + } as TouchEvent) + + this.emit('touchcommit', { + seq: this.seq++ + }) + } else { + this.emit('touchup', { + seq: this.seq++, + contact: 0 + } as TouchEvent) + + this.emit('touchcommit', { + seq: this.seq++ + }) + + this.emit('touchstop', { + seq: this.seq++ + }) + + this.gestureStarted = false + } + } +} + +export default PointerTranslator + diff --git a/lib/units/device/plugins/vnc/util/server.js b/lib/units/device/plugins/vnc/util/server.js deleted file mode 100644 index dc2cb7df00..0000000000 --- a/lib/units/device/plugins/vnc/util/server.js +++ /dev/null @@ -1,40 +0,0 @@ -import util from 'util' -import EventEmitter from 'eventemitter3' -import * as debug$0 from 'debug' -import VncConnection from './connection.js' -var debug = debug$0('vnc:server') -function VncServer(server, options) { - this.options = options - this._bound = { - _listeningListener: this._listeningListener.bind(this), - _connectionListener: this._connectionListener.bind(this), - _closeListener: this._closeListener.bind(this), - _errorListener: this._errorListener.bind(this) - } - this.server = server - .on('listening', this._bound._listeningListener) - .on('connection', this._bound._connectionListener) - .on('close', this._bound._closeListener) - .on('error', this._bound._errorListener) -} -util.inherits(VncServer, EventEmitter) -VncServer.prototype.close = function() { - this.server.close() -} -VncServer.prototype.listen = function() { - this.server.listen.apply(this.server, arguments) -} -VncServer.prototype._listeningListener = function() { - this.emit('listening') -} -VncServer.prototype._connectionListener = function(conn) { - debug('connection', conn.remoteAddress, conn.remotePort) - this.emit('connection', new VncConnection(conn, this.options)) -} -VncServer.prototype._closeListener = function() { - this.emit('close') -} -VncServer.prototype._errorListener = function(err) { - this.emit('error', err) -} -export default VncServer diff --git a/lib/units/device/plugins/vnc/util/server.ts b/lib/units/device/plugins/vnc/util/server.ts new file mode 100644 index 0000000000..5ee4124107 --- /dev/null +++ b/lib/units/device/plugins/vnc/util/server.ts @@ -0,0 +1,66 @@ +import EventEmitter from 'eventemitter3' +import net, { Server, Socket } from 'net' +import VncConnection from './connection.js' +import logger from '../../../../../util/logger.js' + +const _logger = logger.createLogger('vnc:server') +const debug = _logger.debug.bind(_logger) + +interface SecurityMethod { + type: number + challenge?: Buffer + auth: (data: any) => Promise +} + +interface VncServerOptions { + width: number + height: number + name: string + challenge?: Buffer + security?: SecurityMethod[] +} + +class VncServer extends EventEmitter { + options: VncServerOptions + server: Server + + constructor(options: VncServerOptions) { + super() + this.options = options + this.server = net.createServer({ + allowHalfOpen: true + }) + .on('listening', this._listeningListener) + .on('connection', this._connectionListener) + .on('close', this._closeListener) + .on('error', this._errorListener) + } + + close(): void { + this.server.close() + } + + listen(...args: any[]): void { + this.server.listen(...args) + } + + private _listeningListener = (): void => { + this.emit('listening') + } + + private _connectionListener = (conn: Socket): void => { + debug('connection %s %s', conn.remoteAddress, conn.remotePort) + this.emit('connection', new VncConnection(conn, this.options)) + } + + private _closeListener = (): void => { + this.emit('close') + } + + private _errorListener = (err: Error): void => { + this.emit('error', err) + } +} + +export default VncServer + diff --git a/lib/units/device/resources/scrcpy.js b/lib/units/device/resources/scrcpy.js index 886057490e..8e215e943e 100644 --- a/lib/units/device/resources/scrcpy.js +++ b/lib/units/device/resources/scrcpy.js @@ -38,7 +38,7 @@ export default syrup.serial() */ async start() { // Transfer server... - await this.adbClient.getDevice(options.serial).push(path.join(__dirname, 'scrcpy-server.jar'), '/data/local/tmp/scrcpy-server.jar') + await this.adbClient.getDevice(options.serial).push(path.join(import.meta.dirname, 'scrcpy-server.jar'), '/data/local/tmp/scrcpy-server.jar') .then(transfer => new Promise(((resolve, reject) => { transfer.on('progress', (stats) => { console.log('[%s] Pushed %d bytes so far', options.serial, stats.bytesTransferred) diff --git a/lib/wire/util.ts b/lib/wire/util.ts index 748c4b04d7..a772dfc219 100644 --- a/lib/wire/util.ts +++ b/lib/wire/util.ts @@ -6,7 +6,7 @@ import { createLogger } from '../util/logger.ts'; import {MessageType} from "@protobuf-ts/runtime"; import { ADBDeviceType } from '../units/provider/ADBObserver.js'; -const DEVICE_STATUS_MAP = { +export const DEVICE_STATUS_MAP = { device: 'ONLINE', // emulator: 'ONLINE', unauthorized: 'UNAUTHORIZED', From 93a2bfef5e6c779197842755e73c83c3844795fc Mon Sep 17 00:00:00 2001 From: "e.khalilov" Date: Mon, 17 Nov 2025 16:46:18 +0300 Subject: [PATCH 5/5] add dep --- package-lock.json | 16 ++++++++++++++++ package.json | 1 + 2 files changed, 17 insertions(+) diff --git a/package-lock.json b/package-lock.json index bb8bed333a..f0dc00aedb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.772.0", "@aws-sdk/credential-providers": "^3.772.0", + "@cwasm/webp": "^0.1.5", "@devicefarmer/adbkit-apkreader": "3.2.4", "@devicefarmer/adbkit-monkey": "1.2.1", "@devicefarmer/minicap-prebuilt": "file:minicap-prebuilt", @@ -1197,6 +1198,21 @@ "node": ">=14.17" } }, + "node_modules/@canvas/image-data": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.1.0.tgz", + "integrity": "sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==", + "license": "MIT" + }, + "node_modules/@cwasm/webp": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@cwasm/webp/-/webp-0.1.5.tgz", + "integrity": "sha512-ceIZQkyxK+s7mmItNcWqqHdOBiJAxYxTnrnPNgUNjldB1M9j+Bp/3eVIVwC8rUFyN/zoFwuT0331pyY3ackaNA==", + "license": "MIT", + "dependencies": { + "@canvas/image-data": "^1.0.0" + } + }, "node_modules/@devicefarmer/adbkit-apkreader": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-apkreader/-/adbkit-apkreader-3.2.4.tgz", diff --git a/package.json b/package.json index 6ed1237c03..6c98aa815f 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.772.0", "@aws-sdk/credential-providers": "^3.772.0", + "@cwasm/webp": "^0.1.5", "@devicefarmer/adbkit-apkreader": "3.2.4", "@devicefarmer/adbkit-monkey": "1.2.1", "@devicefarmer/minicap-prebuilt": "file:minicap-prebuilt",