@lazycatcloud/lzc-cli 1.2.1 → 1.2.3

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.
@@ -71,7 +71,10 @@ export class DebugBridge {
71
71
  }
72
72
 
73
73
  async isDevshell(appId) {
74
- const stdout = await this.common(this.sshCmd, [`isDevshell`, appId]);
74
+ const stdout = await this.common(this.sshCmd, [
75
+ `isDevshell --uid ${this.uid}`,
76
+ appId,
77
+ ]);
75
78
  return stdout == "true";
76
79
  }
77
80
 
@@ -83,10 +86,17 @@ export class DebugBridge {
83
86
  return this.common(this.sshCmd, [`uninstall --uid ${this.uid}`, appId]);
84
87
  }
85
88
 
86
- async devshell(appId) {
89
+ async devshell(appId, isUserApp) {
87
90
  const stream = spawn(
88
91
  this.sshCmd,
89
- ["-t", "devshell", appId, "/lzcapp/pkg/content/devshell/exec.sh"],
92
+ [
93
+ "-t",
94
+ "devshell",
95
+ `--uid ${this.uid}`,
96
+ isUserApp ? "--userapp" : "",
97
+ appId,
98
+ "/lzcapp/pkg/content/devshell/exec.sh",
99
+ ],
90
100
  {
91
101
  shell: true,
92
102
  stdio: "inherit",
@@ -15,12 +15,12 @@ import {
15
15
  md5File,
16
16
  loadFromYaml,
17
17
  FileLocker,
18
+ isUserApp,
18
19
  } from "../utils.js";
19
20
  import os from "node:os";
20
21
  import commandExists from "command-exists";
21
22
  import chokidar from "chokidar";
22
23
  import _ from "lodash";
23
- import { getUidByManifest } from "../lzc_sdk.js";
24
24
  import { DebugBridge } from "./lpk_debug_bridge.js";
25
25
  import shellApi from "../shellapi.js";
26
26
 
@@ -107,16 +107,16 @@ export class AppDevShell {
107
107
  this.lpkBuild = lpkBuild;
108
108
  this.monitor = undefined;
109
109
  this.forceBuild = forceBuild;
110
+ this.isUserApp = false;
110
111
  }
111
112
 
112
113
  async init() {
113
114
  const manifest = await this.lpkBuild.getManifest();
114
- const uid = await getUidByManifest(manifest);
115
115
  this.monitor = await new AppDevShellMonitor(
116
116
  this.cwd,
117
- manifest["package"],
118
- uid
117
+ manifest["package"]
119
118
  ).init();
119
+ this.isUserApp = isUserApp(manifest);
120
120
  }
121
121
 
122
122
  async build() {
@@ -337,8 +337,7 @@ export class AppDevShell {
337
337
  logger.debug(err);
338
338
  }
339
339
 
340
- const uid = await getUidByManifest(manifest);
341
- const devshell = new DevShell(pkgId, uid);
340
+ const devshell = new DevShell(pkgId, this.isUserApp);
342
341
  if (isSync) {
343
342
  await devshell.shell();
344
343
  } else {
@@ -352,9 +351,9 @@ export class AppDevShell {
352
351
  }
353
352
 
354
353
  class DevShell {
355
- constructor(appId, uid = "") {
354
+ constructor(appId, isUserApp) {
356
355
  this.appId = appId;
357
- this.uid = uid;
356
+ this.isUserApp = isUserApp;
358
357
  }
359
358
 
360
359
  async syncProject(appId) {
@@ -377,7 +376,10 @@ class DevShell {
377
376
  }
378
377
 
379
378
  const rsyncDebug = process.env.RSYNCDEBUG ? "-P" : "";
380
- const dest = `root@app.${appId}.lzcapp:/lzcapp/cache/devshell`;
379
+ const host = this.isUserApp
380
+ ? `${shellApi.uid}.app.${appId}.lzcapp`
381
+ : `app.${appId}.lzcapp`;
382
+ const dest = `root@${host}:/lzcapp/cache/devshell`;
381
383
  try {
382
384
  execSync(
383
385
  `rsync ${rsyncDebug} --rsh='${rsh}' --recursive --relative --perms --update --filter=':- .gitignore' --ignore-errors --usermap=:nobody --groupmap=*:nobody . ${dest}`,
@@ -466,6 +468,6 @@ class DevShell {
466
468
 
467
469
  async connectShell() {
468
470
  const bridge = new DebugBridge();
469
- await bridge.devshell(this.appId);
471
+ await bridge.devshell(this.appId, this.isUserApp);
470
472
  }
471
473
  }
package/lib/box/index.js CHANGED
@@ -1,10 +1,47 @@
1
+ import shellapi from "../shellapi.js";
2
+
1
3
  export function boxCommand(box) {
2
4
  let subCommands = [
3
5
  {
4
- command: "switch <boxName>",
6
+ command: "switch <boxname>",
5
7
  desc: "设置默认的盒子",
6
- handler: async () => {
7
- throw "暂时不支持设置默认盒子,请通过在客户端上点击默认的盒子进行设置。";
8
+ handler: async ({ boxname }) => {
9
+ await shellapi.init();
10
+ await shellapi.setDefaultBox(boxname);
11
+ },
12
+ },
13
+ {
14
+ command: "list",
15
+ desc: "查看盒子列表",
16
+ builder: (args) => {
17
+ args.option("v", {
18
+ alias: "verbose",
19
+ describe: "查看详细输出",
20
+ type: "boolean",
21
+ });
22
+ },
23
+ handler: async ({ verbose }) => {
24
+ await shellapi.init();
25
+ const boxes = await shellapi.boxList();
26
+ if (boxes.length === 0) {
27
+ console.log("没有找到任何盒子,赶紧添加一个吧!");
28
+ return;
29
+ }
30
+ if (verbose) {
31
+ console.log(JSON.stringify(boxes, undefined, "\t"));
32
+ return;
33
+ }
34
+
35
+ const list = boxes.map((b) => {
36
+ return {
37
+ 名称: b.box_name,
38
+ 状态: b.status,
39
+ 登录用户: b.login_user,
40
+ 是否管理员: b.is_admin_login ? "✔" : "✖",
41
+ 是否默认盒子: b.is_default_box ? "✔" : "✖",
42
+ };
43
+ });
44
+ console.table(list);
8
45
  },
9
46
  },
10
47
  ];
package/lib/shellapi.js CHANGED
@@ -71,25 +71,43 @@ class ShellApi {
71
71
  return grpc.loadPackageDefinition(coreDefinition).space.heiyu.hportal.shell;
72
72
  }
73
73
 
74
- async initBoxInfo() {
74
+ async boxList() {
75
75
  return new Promise((resolve, reject) => {
76
76
  this.client.queryBoxList({}, this.metadata, function (err, response) {
77
77
  if (err) {
78
78
  reject(err);
79
79
  return;
80
80
  }
81
- for (let box of response.boxes) {
82
- if (box.is_default_box) {
83
- resolve({ uid: box.login_user, boxname: box.box_name });
84
- return;
85
- }
86
- }
87
- reject(
88
- "没有默认盒子信息, 请先使用 lzc-cli box switch 设置默认的盒子信息"
89
- );
81
+ resolve(response.boxes);
90
82
  });
91
83
  });
92
84
  }
85
+
86
+ async initBoxInfo() {
87
+ const boxes = await this.boxList();
88
+ const box = boxes.find((b) => b.is_default_box);
89
+ if (box) {
90
+ return { uid: box.login_user, boxname: box.box_name };
91
+ }
92
+ throw "没有默认盒子信息, 请先使用 lzc-cli box switch 设置默认的盒子信息";
93
+ }
94
+
95
+ async setDefaultBox(boxname) {
96
+ const boxes = await this.boxList();
97
+ const box = boxes.find((b) => b.box_name === boxname);
98
+ if (!box) {
99
+ throw `${boxname} 盒子不存在`;
100
+ }
101
+ return new Promise((resolve, reject) => {
102
+ this.client.modifyBoxConfig(
103
+ { id: box.id, name: box.box_name, set_as_default_box: true },
104
+ this.metadata,
105
+ function (err) {
106
+ err ? reject(err) : resolve();
107
+ }
108
+ );
109
+ });
110
+ }
93
111
  }
94
112
 
95
113
  export default new ShellApi();
package/lib/utils.js CHANGED
@@ -294,3 +294,7 @@ export function isValidPackageName(packageName) {
294
294
  const regex = new RegExp("^(?:[a-z][a-z0-9_]*\\.)+[a-z][a-z0-9_]*$");
295
295
  return regex.test(packageName);
296
296
  }
297
+
298
+ export function isUserApp(manifest) {
299
+ return !!manifest["application"]["user_app"];
300
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazycatcloud/lzc-cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "lazycat cloud developer kit",
5
5
  "scripts": {
6
6
  "test": "tap",
@@ -9,5 +9,6 @@ fi
9
9
  set -e
10
10
 
11
11
  # 切换目录
12
+ mkdir -p /lzcapp/cache/devshell
12
13
  cd /lzcapp/cache/devshell
13
14
  exec /bin/sh
@@ -7,18 +7,25 @@ BUSYBOX=/lzcapp/pkg/content/devshell/busybox
7
7
  mkdir -p /root/.ssh
8
8
  mkdir -p /etc/debug.bridge
9
9
 
10
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/dropbearmulti -O /usr/bin/dropbearmulti
11
- chmod +x /usr/bin/dropbearmulti
10
+ if ! [ -f /usr/bin/dropbearmulti ]; then
11
+ ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/dropbearmulti -O /usr/bin/dropbearmulti
12
+ chmod +x /usr/bin/dropbearmulti
13
+ fi
12
14
 
13
- ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/rsync -O /usr/bin/rsync
14
- chmod +x /usr/bin/rsync
15
+ if ! [ -f /usr/bin/rsync ]; then
16
+ ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/rsync -O /usr/bin/rsync
17
+ chmod +x /usr/bin/rsync
18
+ fi
15
19
 
16
20
  ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/resources/authorized_keys -O /root/.ssh/authorized_keys
17
21
  chmod 0644 /root/.ssh/authorized_keys
18
22
 
19
23
  ${BUSYBOX} wget ${DEBUG_BRIDGE_LZCAPP}/bannerfile -O /etc/debug.bridge/bannerfile
20
24
 
21
-
22
- mkdir -p /etc/dropbear
23
-
24
- exec dropbearmulti dropbear -R -F -E -B -p 22222
25
+ if ${BUSYBOX} netstat -tln | grep ':22222' >/dev/null; then
26
+ echo "端口22222正在监听"
27
+ ${BUSYBOX} sleep infinity
28
+ else
29
+ mkdir -p /etc/dropbear
30
+ exec dropbearmulti dropbear -R -F -E -B -p 22222
31
+ fi
package/lib/lzc_sdk.js DELETED
@@ -1,83 +0,0 @@
1
- import grpc from "@grpc/grpc-js";
2
- import protoLoader from "@grpc/proto-loader";
3
- import { contextDirname } from "./utils.js";
4
- import path from "node:path";
5
- import env from "./env.js";
6
- import logger from "loglevel";
7
- import os from "node:os";
8
- import fs from "node:fs";
9
-
10
- /**
11
- * @link {https://www.npmjs.com/package/appdirs}
12
- */
13
- function getShellAPIConfigDir() {
14
- const home = os.homedir();
15
- const isMacos = process.platform == "darwin";
16
- let sufix = "/.config/hportal-client";
17
- if (isMacos) {
18
- sufix = "/Library/Application Support/hportal-client";
19
- } // TODO: need reimpl fetch windows
20
- const SHELLAPI_CONFIG_DIR = path.join(home, sufix);
21
- return SHELLAPI_CONFIG_DIR;
22
- }
23
-
24
- const coreDefinition = protoLoader.loadSync(
25
- path.join(contextDirname(), "./shellapi.proto"),
26
- {
27
- keepCase: true,
28
- longs: String,
29
- enums: String,
30
- defaults: true,
31
- oneofs: true,
32
- }
33
- );
34
- const core =
35
- grpc.loadPackageDefinition(coreDefinition).space.heiyu.hportal.shell;
36
-
37
- let client;
38
-
39
- function readShellApiInfo() {
40
- const SHELLAPI_CONFIG_DIR = getShellAPIConfigDir();
41
- const addr = fs.readFileSync(
42
- path.resolve(SHELLAPI_CONFIG_DIR, "shellapi_addr"),
43
- { encoding: "utf-8" }
44
- );
45
- const cred = fs.readFileSync(
46
- path.resolve(SHELLAPI_CONFIG_DIR, "shellapi_cred"),
47
- { encoding: "utf-8" }
48
- );
49
- return { addr, cred };
50
- }
51
-
52
- export async function getUidByManifest(manifest) {
53
- if (!manifest["application"]["user_app"]) {
54
- return "";
55
- }
56
-
57
- const { addr, cred } = readShellApiInfo();
58
-
59
- if (!client) {
60
- client = new core.ShellCore(addr, grpc.credentials.createInsecure());
61
- }
62
-
63
- const metadata = new grpc.Metadata();
64
- metadata.add("lzc-shellapi-cred", cred);
65
-
66
- const boxName = env.get("DEFAULT_BOXNAME");
67
- return new Promise((resolve, reject) => {
68
- client.queryBoxList({}, metadata, function (err, response) {
69
- if (err) {
70
- reject(err);
71
- return;
72
- }
73
- for (let box of response.boxes) {
74
- if (box.box_name == boxName) {
75
- logger.debug("当前登录用户: ", box.login_user);
76
- resolve(box.login_user);
77
- return;
78
- }
79
- }
80
- reject("没有默认盒子信息");
81
- });
82
- });
83
- }