@lazycatcloud/lzc-cli 1.1.13 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/lib/app/index.js +33 -35
  2. package/lib/app/lpk_debug_bridge.js +101 -0
  3. package/lib/app/lpk_devshell.js +55 -114
  4. package/lib/app/lpk_installer.js +43 -40
  5. package/lib/appstore/login.js +1 -1
  6. package/lib/appstore/publish.js +18 -8
  7. package/lib/box/index.js +2 -86
  8. package/lib/env.js +18 -178
  9. package/lib/lzc_sdk.js +16 -2
  10. package/lib/shellapi.js +95 -0
  11. package/lib/shellapi.proto +301 -0
  12. package/lib/utils.js +2 -103
  13. package/package.json +3 -24
  14. package/template/_lpk/busybox-1.35.0 +0 -0
  15. package/template/_lpk/exec.sh +1 -10
  16. package/template/_lpk/init_debug_bridge.sh +24 -0
  17. package/template/_lpk/vue.lzc-build.yml.in +0 -16
  18. package/template/golang/lzc-build.yml +0 -15
  19. package/template/ionic_vue3/lzc-build.yml +0 -16
  20. package/template/ionic_vue3/package-lock.json +8100 -0
  21. package/template/lite/lzc-build.yml +0 -28
  22. package/lib/api.js +0 -155
  23. package/lib/app/lpk_devshell_docker.js +0 -211
  24. package/lib/app/lpk_log.js +0 -68
  25. package/lib/app/lpk_status.js +0 -18
  26. package/lib/app/lpk_uninstall.js +0 -19
  27. package/lib/box/api/clientapi.js +0 -1322
  28. package/lib/box/api/empty.js +0 -35
  29. package/lib/box/check_qemu.js +0 -51
  30. package/lib/box/qemu_vm_mgr.js +0 -608
  31. package/lib/box/schemes/vm_box_system_debian.json +0 -47
  32. package/lib/core.proto +0 -118
  33. package/lib/docker/promise.js +0 -91
  34. package/lib/docker-compose.js +0 -50
  35. package/lib/fetch.js +0 -50
  36. package/lib/git/git-commit.sh +0 -7
  37. package/lib/git/git-reset.sh +0 -15
  38. package/lib/key.js +0 -102
  39. package/lib/sdk.js +0 -135
@@ -1,47 +0,0 @@
1
- {
2
- "name": "home-cloud",
3
- "uuid": "047dac31-b75b-46ed-aedb-a31fa46a6503",
4
- "memory": 4096,
5
- "kernel": "debian",
6
- "uefi": true,
7
- "path": "${HOME}/.cache/box-emulator",
8
- "volume": {
9
- "config": "/etc/home-cloud"
10
- },
11
- "disks": [
12
- {
13
- "id": "system",
14
- "size": "8G",
15
- "system": true,
16
- "partitions": [
17
- {
18
- "fs_type": "vfat",
19
- "size": "100M",
20
- "mount_point": "/boot/ESP"
21
- },
22
- {
23
- "fs_type": "ext4",
24
- "size": "4G",
25
- "mount_point": "/"
26
- },
27
- {
28
- "fs_type": "ext4",
29
- "size": "full",
30
- "mount_point": "/mnt"
31
- }
32
- ]
33
- },
34
- {
35
- "id": "data1",
36
- "size": "64G",
37
- "system": false,
38
- "partitions": []
39
- },
40
- {
41
- "id": "data2",
42
- "size": "64G",
43
- "rebuild": false,
44
- "partitions": []
45
- }
46
- ]
47
- }
package/lib/core.proto DELETED
@@ -1,118 +0,0 @@
1
- syntax = "proto3";
2
-
3
- package space.heiyu.hportal.shell;
4
-
5
- import "google/protobuf/empty.proto";
6
-
7
- // 此接口为hclient&hserver曝露给管理界面、命令行客户端等使用的API
8
- service ShellCore {
9
- // 查询当前盒子列表的状态
10
- rpc QueryBoxList(google.protobuf.Empty) returns(BoxList) {}
11
- // 添加、修改盒子的登陆信息、开启、关闭盒子等
12
- rpc ModifyBox(BoxSetting) returns (google.protobuf.Empty);
13
- }
14
-
15
- // 盒子只会处于以下四种状态之一
16
- enum BoxStatus {
17
- // 此盒子当前未激活
18
- DISABLED = 0;
19
-
20
- // 正在连接中,此过程持续时间无法评估,
21
- // 可能瞬间结束也可能持续一两分钟(在确实可以连接上的前提下)
22
- CONNECTING = 1;
23
-
24
- // 成功连接上了
25
- CONNECTED = 2;
26
-
27
- // 确定无法连接,此时不会继续重试,需要客户端
28
- // 修正环境后,重新调用ModifyBox后继续尝试。
29
- FAILED = 3;
30
- }
31
-
32
- enum ConnectingStatus {
33
- AWAIT_NEW_DEVICE_AUTH = 0;
34
- }
35
-
36
- enum FailedStatus {
37
- // 未知原因失败
38
- FAILED_UNKNOWN = 0;
39
-
40
- // 当前盒子无管理员帐号,需要调用CreateUser创建管理员帐号
41
- FAILED_NO_ADMINUSER = 1;
42
-
43
- // 当前盒子未注册盒子名称,需要调用SetupNewBox向horigin申请盒子名称以及配套资源
44
- FAILED_NO_BOXNAME = 2;
45
-
46
- // 当前登陆信息不正确,需要调用ModifyBox设置新的auth信息
47
- FAILED_INVALID_PASSWORD = 3;
48
-
49
- // 当前客户端与服务器版本不匹配,无法连接,需要升级盒子系统或客户端软件
50
- FAILED_MISMATCH_BOX_VERSION = 4;
51
-
52
- // 当前设备被拒绝登录
53
- FAILED_DEVICE_AUTH_REJECT = 5;
54
-
55
-
56
- //------ 100+的失败状态一般为本机特有错误状态
57
-
58
- //调用LoginBox的过程中,此盒子的状态被其他API请求转换为disabled了
59
- FAILED_LOCAL_DISABLED_BOX = 100;
60
-
61
- //调用LoginBox时使用了一个不存在的盒子名称。(若只是本地不盒子列表不存在此盒子,会自动添加到盒子列表)
62
- FAILED_LOCAL_NO_SUCH_BOX_IN_THE_WORLD = 101;
63
-
64
- //使用LoginBox时,登陆超时
65
- FAILED_LOCAL_CONNECTING_TIMEOUT = 102;
66
- }
67
-
68
- enum ExceptionStatus {
69
- OK = 0;
70
- Error = 1;
71
- Booting = 2;
72
- }
73
-
74
- message BoxInfo {
75
- string box_id = 1;
76
- string box_name = 2;
77
- string box_home_url = 3 [deprecated = true];
78
- string box_domain = 14;
79
- string box_virtual_ip = 10;
80
-
81
- BoxStatus status = 4;
82
- string status_reason = 5;
83
- optional FailedStatus failed_status = 6;
84
- optional ConnectingStatus connecting_status = 12; // deprecated
85
- ExceptionStatus exception_status = 11;
86
-
87
- bool is_relay_connection = 13;
88
-
89
- string login_user = 7;
90
- bool is_admin_login = 8;
91
- string auth_token = 9;
92
-
93
- bool is_default_box = 15;
94
- }
95
-
96
- message BoxList {
97
- repeated BoxInfo boxes = 1;
98
- }
99
-
100
- message BoxSetting {
101
- string id = 1;
102
-
103
- optional string name = 2;
104
-
105
- // 若不设置则使用当前值
106
- optional bool enabled = 3;
107
-
108
- message AuthInfo {
109
- string user = 3;
110
- string password = 4;
111
- optional string verification_code = 5;
112
- }
113
- optional AuthInfo auth = 4;
114
-
115
- //设置此盒子为默认盒子,会覆盖其他(如果有)默认盒子的配置
116
- //第一个添加的盒子会自动成为默认盒子
117
- optional bool set_as_default_box = 5;
118
- }
@@ -1,91 +0,0 @@
1
- import Docker from "dockerode";
2
-
3
- var wrappedProto = Docker.prototype;
4
-
5
- function denodeify(func) {
6
- return function (...args) {
7
- return new Promise((resolve, reject) => {
8
- let input = [...args, (err, val) => (err ? reject(err) : resolve(val))];
9
- func.apply(this, input);
10
- });
11
- };
12
- }
13
-
14
- function proxyPromise(method) {
15
- var promisey = denodeify(method);
16
- return function () {
17
- return promisey.apply(this.$subject, arguments);
18
- };
19
- }
20
-
21
- function promiseObj(target, input) {
22
- for (var key in input) {
23
- if (typeof input[key] !== "function") continue;
24
- target[key] = proxyPromise(input[key]);
25
- }
26
- return target;
27
- }
28
-
29
- function PromiseProxy(subject) {
30
- var result = Object.create(subject);
31
- result.$subject = subject;
32
- return promiseObj(result, subject);
33
- }
34
-
35
- function ContainerProxy(subject) {
36
- var result = PromiseProxy(subject);
37
- var exec = result.exec;
38
- result.exec = function () {
39
- return exec.apply(this, arguments).then(function (exec) {
40
- return PromiseProxy(exec);
41
- });
42
- };
43
- return result;
44
- }
45
-
46
- function DockerProxy(options) {
47
- this.$subject = new Docker(options);
48
- }
49
-
50
- promiseObj(DockerProxy.prototype, wrappedProto);
51
-
52
- // sadly we need to wrap run directly as a promise to consolidate both
53
- // of the resulting arguments.
54
- DockerProxy.prototype.run = function (image, command, stream) {
55
- var subject = this.$subject;
56
- return new Promise(function (accept, reject) {
57
- subject.run(image, command, stream, function (err, result, container) {
58
- if (err) return reject(err);
59
- accept({
60
- result: result,
61
- // re-wrap
62
- container: ContainerProxy(container),
63
- });
64
- });
65
- });
66
- };
67
-
68
- // We also have wrap createContainer manually as it returns
69
- DockerProxy.prototype.createContainer = function (opts) {
70
- var subject = this.$subject;
71
- return new Promise(function (accept, reject) {
72
- subject.createContainer(opts, function (err, container) {
73
- if (err) return reject(err);
74
- accept(ContainerProxy(container));
75
- });
76
- });
77
- };
78
-
79
- DockerProxy.prototype.getImage = function (id) {
80
- return PromiseProxy(this.$subject.getImage(id));
81
- };
82
-
83
- DockerProxy.prototype.getContainer = function (id) {
84
- return ContainerProxy(this.$subject.getContainer(id));
85
- };
86
-
87
- DockerProxy.prototype.getVolume = function (name) {
88
- return PromiseProxy(this.$subject.getVolume(name));
89
- };
90
-
91
- export default DockerProxy;
@@ -1,50 +0,0 @@
1
- import yaml from "js-yaml";
2
- import fs from "fs";
3
- import mergeWith from "lodash.mergewith";
4
-
5
- export function load(filePath) {
6
- return yaml.load(fs.readFileSync(filePath, "utf8"));
7
- }
8
-
9
- // 用于合并多个 DockerCompose 文件
10
- export default class DockerCompose {
11
- constructor(basefile) {
12
- this.basefile = basefile;
13
- this.obj = load(basefile);
14
- }
15
- // 直接修改 yaml 内容
16
- pipe(cb) {
17
- cb.apply(this, [this.obj]);
18
- return this;
19
- }
20
-
21
- // mergeFile({file: ""}) or merge({content: ""})
22
- merge(context) {
23
- let newObj;
24
- if (context.file) {
25
- newObj = load(context.file);
26
- }
27
- if (context.content) {
28
- newObj = yaml.load(context.content);
29
- }
30
-
31
- this.obj = mergeWith(this.obj, newObj, (objValue, srcValue) => {
32
- if (Array.isArray(objValue)) {
33
- return objValue.concat(srcValue);
34
- }
35
- });
36
- return this;
37
- }
38
-
39
- // to: optional
40
- save(to) {
41
- fs.writeFileSync(
42
- to || this.basefile,
43
- yaml.dump(this.obj, {
44
- styles: {
45
- "!!null": "empty", // dump null as ""
46
- },
47
- })
48
- );
49
- }
50
- }
package/lib/fetch.js DELETED
@@ -1,50 +0,0 @@
1
- import nodeFetch from "node-fetch";
2
- import makeFetchCookie from "fetch-cookie";
3
- import { FileCookieStore } from "tough-cookie-file-store";
4
- import inquirer from "inquirer";
5
- import env from "./env.js";
6
- import path from "node:path";
7
- import { GLOBAL_CONFIG_DIR } from "./utils.js";
8
-
9
- const cookieFetch = makeFetchCookie(
10
- nodeFetch,
11
- new makeFetchCookie.toughCookie.CookieJar(
12
- new FileCookieStore(path.resolve(GLOBAL_CONFIG_DIR, "cookie.json"))
13
- )
14
- );
15
- const fetch = async (url, options) => {
16
- const resp = await cookieFetch(url, options);
17
- if (resp.status == 401) {
18
- await login();
19
- }
20
- return resp;
21
- };
22
-
23
- export async function login() {
24
- const boxname = env.get("DEFAULT_BOXNAME");
25
- const boxUrl = `https://${boxname}.heiyu.space`;
26
-
27
- const questions = [
28
- {
29
- name: "username",
30
- type: "input",
31
- message: "请输入帐号名",
32
- },
33
- {
34
- type: "password",
35
- mask: "*",
36
- name: "password",
37
- message: "请输入登录密码",
38
- },
39
- ];
40
- const answers = await inquirer.prompt(questions);
41
- await fetch(`${boxUrl}/sys/login?type=plain`, {
42
- headers: {
43
- "content-type": "application/x-www-form-urlencoded",
44
- },
45
- body: `username=${answers.username}&password=${answers.password}`,
46
- method: "POST",
47
- });
48
- }
49
-
50
- export default fetch;
@@ -1,7 +0,0 @@
1
- # executed under appdb
2
-
3
- # git fetch origin
4
- # git reset --hard
5
- #
6
- git add ${APP_ID}
7
- git commit -m "[lzc-cli publish] bump ${APP_ID} version to ${APP_VERSION}"
@@ -1,15 +0,0 @@
1
- #!/bin/bash
2
-
3
- FOLDER="$APPDB_DIR"
4
-
5
- if [ ! -d "$FOLDER" ] ; then
6
- git clone --depth 1 git@gitee.com:lazycatcloud/appdb.git $FOLDER
7
- fi
8
- #
9
- cd $FOLDER
10
- #
11
- git fetch && git reset --hard origin/v0.1
12
- #
13
- #
14
-
15
-
package/lib/key.js DELETED
@@ -1,102 +0,0 @@
1
- import inquirer from "inquirer";
2
- import glob from "fast-glob";
3
- import path from "path";
4
- import { Client } from "ssh2";
5
- import process from "process";
6
- import fs from "fs";
7
- import execa from "execa";
8
- import API from "./api.js";
9
- import { ensureDir } from "./utils.js";
10
- import os from "os";
11
-
12
- const KEY_NAME = "id_ed25519";
13
- const SSH_CONFIG_DIR = path.join(os.homedir(), ".ssh");
14
-
15
- export default class Key {
16
- // 确保该秘钥可以工作
17
- async ensure(host) {
18
- const pairs = await this.getKeyPair();
19
- await this.validationCheck(host, pairs);
20
- }
21
-
22
- async generate() {
23
- const privateKeyFile = path.join(SSH_CONFIG_DIR, KEY_NAME);
24
- ensureDir(privateKeyFile);
25
- await execa(
26
- "ssh-keygen",
27
- ["-t", "ed25519", "-P", "", "-f", privateKeyFile],
28
- {
29
- stdio: "inherit",
30
- }
31
- );
32
- return {
33
- private: privateKeyFile,
34
- public: privateKeyFile + ".pub",
35
- };
36
- }
37
-
38
- async validationCheck(host, pair) {
39
- const hostname = new URL(host).hostname;
40
- const client = new Client();
41
- return new Promise((resolve, reject) => {
42
- client
43
- .on("ready", () => {
44
- resolve(true);
45
- client.end();
46
- })
47
- .on("error", (err) => {
48
- if (err.level == "client-authentication") {
49
- inquirer
50
- .prompt([
51
- {
52
- name: "key",
53
- type: "confirm",
54
- message: "发布应用需要上传公钥, 确定上传?",
55
- },
56
- ])
57
- .then(({ key }) => {
58
- if (key) {
59
- const api = new API("", host);
60
- api
61
- .postPublicKey(fs.readFileSync(pair["public"]))
62
- .then(() => {
63
- resolve(true);
64
- });
65
- } else {
66
- process.exit(1);
67
- }
68
- });
69
- } else {
70
- reject(err);
71
- }
72
- })
73
- .connect({
74
- host: hostname,
75
- port: 2222,
76
- username: "box",
77
- retry: 3,
78
- wait: 500,
79
- authHandler: [
80
- {
81
- type: "publickey",
82
- username: "box",
83
- key: fs.readFileSync(pair["private"]),
84
- },
85
- ],
86
- keepaliveInterval: 60000, // 60s
87
- });
88
- });
89
- }
90
-
91
- async getKeyPair() {
92
- const privateKey = path.join(SSH_CONFIG_DIR, KEY_NAME);
93
- const publicKey = path.join(SSH_CONFIG_DIR, `${KEY_NAME}.pub`);
94
- if (fs.existsSync(privateKey) && fs.existsSync(publicKey)) {
95
- return {
96
- private: privateKey,
97
- public: publicKey,
98
- };
99
- }
100
- return await this.generate();
101
- }
102
- }
package/lib/sdk.js DELETED
@@ -1,135 +0,0 @@
1
- import ssh from "docker-modem/lib/ssh.js";
2
- // import Docker from "./docker/promise.js";
3
- import Docker from "dockerode";
4
- import process from "process";
5
- import fs from "fs";
6
- import { Client } from "ssh2";
7
- import Key from "./key.js";
8
- import logger from "loglevel";
9
-
10
- const sshDebug = function () {
11
- if (process.env["SSH2_DEBUG"]) {
12
- return logger.debug;
13
- } else {
14
- return function () {};
15
- }
16
- };
17
-
18
- export async function connectOptions(host) {
19
- const pairs = await new Key().getKeyPair();
20
- return {
21
- host: host,
22
- port: 2222,
23
- username: "box",
24
- retry: 3,
25
- wait: 500,
26
- authHandler: [
27
- {
28
- type: "publickey",
29
- username: "box",
30
- key: fs.readFileSync(pairs["private"]),
31
- },
32
- {
33
- type: "agent",
34
- username: "box",
35
- agent: process.env.SSH_AUTH_SOCK,
36
- },
37
- ],
38
- keepaliveInterval: 60000, // 60s
39
- debug: sshDebug(),
40
- };
41
- }
42
-
43
- export class DockerClient {
44
- constructor(host) {
45
- this.host = host;
46
- }
47
-
48
- async init() {
49
- this.docker = !!this.host
50
- ? new Docker({
51
- protocal: "ssh",
52
- agent: ssh(await connectOptions(this.host)),
53
- })
54
- : new Docker();
55
-
56
- const host = this.host;
57
-
58
- async function onUncaughtException(e) {
59
- if (e.code == "ECONNREFUSED") {
60
- logger.error(`无法连接 sdk 服务, 请确保 ${host} 可以访问`);
61
- process.exit(1);
62
- } else {
63
- throw e;
64
- }
65
- }
66
- process.on("uncaughtException", onUncaughtException);
67
- await this.docker.ping();
68
- process.off("uncaughtException", onUncaughtException);
69
- return this.docker;
70
- }
71
- }
72
-
73
- export class SSHClient {
74
- // arg can be a simple host name or a ssh connectOptions
75
- constructor(arg) {
76
- if (typeof arg == "string") {
77
- this.opts = connectOptions(arg);
78
- } else {
79
- this.opts = arg;
80
- }
81
- this.con = new Client();
82
- }
83
-
84
- connect() {
85
- return new Promise((resolve, reject) => {
86
- this.con
87
- .on("ready", () => resolve(this.con))
88
- .on("error", (err) => {
89
- logger.error("ssh client ", err);
90
- reject(err);
91
- })
92
- .on("close", () => resolve(null))
93
- .connect(this.opts);
94
- });
95
- }
96
-
97
- close() {
98
- this.con.end();
99
- }
100
-
101
- exec(command, options = {}) {
102
- return new Promise((resolve, reject) => {
103
- this.con.exec(command, options, (err, chan) => {
104
- if (err) return reject(err);
105
- resolve(chan);
106
- });
107
- });
108
- }
109
-
110
- async shell() {
111
- this.con.shell(
112
- {
113
- term: process.env.TERM,
114
- rows: process.stdout.rows,
115
- cols: process.stdout.columns,
116
- },
117
- (err, stream) => {
118
- if (err) throw err;
119
-
120
- stream.on("close", () => {
121
- process.exit();
122
- });
123
- process.stdin.setRawMode(true);
124
- process.stdin.pipe(stream);
125
-
126
- // Connect remote output to local stdout
127
- stream.pipe(process.stdout);
128
- process.stdout.on("resize", () => {
129
- // Let the remote end know when the local terminal has been resized
130
- stream.setWindow(process.stdout.rows, process.stdout.columns, 0, 0);
131
- });
132
- }
133
- );
134
- }
135
- }