@lazycatcloud/lzc-cli 1.2.28 → 1.2.30
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.
- package/lib/app/apkshell.js +3 -8
- package/lib/app/index.js +17 -6
- package/lib/app/lpk_create_generator.js +2 -0
- package/lib/app/lpk_debug_bridge.js +21 -25
- package/lib/app/lpk_devshell.js +2 -1
- package/lib/app/lpk_installer.js +10 -5
- package/lib/appstore/login.js +5 -10
- package/lib/shellapi.js +18 -0
- package/lib/utils.js +15 -0
- package/package.json +2 -1
package/lib/app/apkshell.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs"
|
|
2
|
-
import fetch from "node-fetch"
|
|
3
2
|
import logger from "loglevel"
|
|
3
|
+
import { api } from "../utils.js"
|
|
4
4
|
|
|
5
5
|
export async function triggerApk(id, name, iconPath) {
|
|
6
6
|
if (!id) {
|
|
@@ -15,16 +15,11 @@ export async function triggerApk(id, name, iconPath) {
|
|
|
15
15
|
if (iconPath) {
|
|
16
16
|
form.append("app_icon", new Blob([fs.readFileSync(iconPath)]))
|
|
17
17
|
}
|
|
18
|
-
const resp = await
|
|
18
|
+
const resp = await api.post(
|
|
19
19
|
"https://appstore.lazycat.cloud/api/trigger_latest_for_app",
|
|
20
|
-
|
|
21
|
-
method: "POST",
|
|
22
|
-
body: form
|
|
23
|
-
}
|
|
20
|
+
form
|
|
24
21
|
)
|
|
25
22
|
if (resp.status == 304) {
|
|
26
|
-
// 没有修改
|
|
27
|
-
logger.info(`APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`)
|
|
28
23
|
} else if (resp.status == 201) {
|
|
29
24
|
logger.info(`APK构建任务已创建成功,如需使用安卓端,请耐心等待1分钟左右`)
|
|
30
25
|
} else if (resp.status >= 400) {
|
package/lib/app/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path"
|
|
|
2
2
|
import lpkCreate from "./lpk_create.js"
|
|
3
3
|
import { LpkBuild } from "./lpk_build.js"
|
|
4
4
|
import { AppDevShell } from "./lpk_devshell.js"
|
|
5
|
-
import { LpkInstaller } from "./lpk_installer.js"
|
|
5
|
+
import { LpkInstaller, installConfig } from "./lpk_installer.js"
|
|
6
6
|
import logger from "loglevel"
|
|
7
7
|
import { sleep } from "../utils.js"
|
|
8
8
|
import { DebugBridge } from "./lpk_debug_bridge.js"
|
|
@@ -14,8 +14,6 @@ export function lpkProjectCommand(program) {
|
|
|
14
14
|
command: "create <name>",
|
|
15
15
|
desc: "创建懒猫云应用",
|
|
16
16
|
handler: async ({ name }) => {
|
|
17
|
-
await shellApi.init()
|
|
18
|
-
|
|
19
17
|
await lpkCreate(name)
|
|
20
18
|
}
|
|
21
19
|
},
|
|
@@ -68,10 +66,15 @@ export function lpkProjectCommand(program) {
|
|
|
68
66
|
describe: "同时打包 lzc-build.yml 中指定的 contentdir 目录",
|
|
69
67
|
type: "boolean"
|
|
70
68
|
})
|
|
69
|
+
args.option("apk", {
|
|
70
|
+
describe: "是否生成APK(y/n)",
|
|
71
|
+
type: "string",
|
|
72
|
+
default: "y"
|
|
73
|
+
})
|
|
71
74
|
},
|
|
72
|
-
handler: async ({ context, force, config, contentdir }) => {
|
|
75
|
+
handler: async ({ context, force, config, contentdir, apk }) => {
|
|
73
76
|
await shellApi.init()
|
|
74
|
-
|
|
77
|
+
installConfig.apk = apk == "y"
|
|
75
78
|
const cwd = context ? path.resolve(context) : process.cwd()
|
|
76
79
|
const lpkBuild = await new LpkBuild(cwd, config).init()
|
|
77
80
|
lpkBuild.onBeforeBuildPackage(async (options) => {
|
|
@@ -107,8 +110,16 @@ export function lpkAppCommand(program) {
|
|
|
107
110
|
{
|
|
108
111
|
command: "install [pkgPath]",
|
|
109
112
|
desc: "部署应用至设备, pkgPath 可以为路径,或者https://,http://请求地址, 如果不填写,将默认为当前目录下的lpk",
|
|
110
|
-
|
|
113
|
+
builder: (args) => {
|
|
114
|
+
args.option("apk", {
|
|
115
|
+
describe: "是否生成APK(y/n)",
|
|
116
|
+
type: "string",
|
|
117
|
+
default: "y"
|
|
118
|
+
})
|
|
119
|
+
},
|
|
120
|
+
handler: async ({ pkgPath, apk }) => {
|
|
111
121
|
await shellApi.init()
|
|
122
|
+
installConfig.apk = apk == "y"
|
|
112
123
|
|
|
113
124
|
pkgPath = pkgPath ?? process.cwd()
|
|
114
125
|
const installer = new LpkInstaller()
|
|
@@ -2,7 +2,8 @@ import { spawn, spawnSync } from "child_process"
|
|
|
2
2
|
import fs from "node:fs"
|
|
3
3
|
import shellApi from "../shellapi.js"
|
|
4
4
|
import inquirer from "inquirer"
|
|
5
|
-
import { isDebugMode, resolveDomain } from "../utils.js"
|
|
5
|
+
import { isDebugMode, resolveDomain, sleep } from "../utils.js"
|
|
6
|
+
import logger from "loglevel"
|
|
6
7
|
|
|
7
8
|
export class DebugBridge {
|
|
8
9
|
constructor() {
|
|
@@ -18,7 +19,7 @@ export class DebugBridge {
|
|
|
18
19
|
const ssh = spawnSync(sshCmd, args, {
|
|
19
20
|
shell: true,
|
|
20
21
|
encoding: "utf-8",
|
|
21
|
-
stdio: ["pipe", "pipe", "
|
|
22
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22
23
|
})
|
|
23
24
|
return new Promise((resolve, reject) => {
|
|
24
25
|
ssh.status == 0
|
|
@@ -31,6 +32,7 @@ export class DebugBridge {
|
|
|
31
32
|
|
|
32
33
|
async install(lpkPath, pkgId) {
|
|
33
34
|
if (!(await this.canPublicKey())) {
|
|
35
|
+
// 如果不能 ssh public key 登录则直接调用 ssh-copy-id 复制,否则后面可能会出现 rsync 询问密码的问题
|
|
34
36
|
await this.sshCopyId()
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -53,29 +55,13 @@ export class DebugBridge {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
async canPublicKey() {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return true
|
|
59
|
-
} catch {
|
|
60
|
-
return false
|
|
61
|
-
}
|
|
58
|
+
// FIXME: 目前没有找到在允许空密码的情况下,检测是否只能通过 publickey 登录的方法。
|
|
59
|
+
return false
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
async sshCopyId() {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
name: "upload",
|
|
68
|
-
type: "input",
|
|
69
|
-
default: "y",
|
|
70
|
-
message:
|
|
71
|
-
"检测到你目前使用的密码帐号登录,是否使用 ssh-copy-id 上传密钥 (y/n): "
|
|
72
|
-
}
|
|
73
|
-
]
|
|
74
|
-
const answers = await inquirer.prompt(questions)
|
|
75
|
-
if (answers.upload.toLowerCase() == "y") {
|
|
76
|
-
const resolvedIp = await resolveDomain(this.domain)
|
|
77
|
-
return this.common(`ssh-copy-id`, [`-f -p 22222 box@${resolvedIp}`])
|
|
78
|
-
}
|
|
63
|
+
const resolvedIp = await resolveDomain(this.domain)
|
|
64
|
+
return this.common(`ssh-copy-id`, [`-f -p 22222 box@${resolvedIp}`])
|
|
79
65
|
}
|
|
80
66
|
|
|
81
67
|
async status(appId) {
|
|
@@ -100,6 +86,16 @@ export class DebugBridge {
|
|
|
100
86
|
|
|
101
87
|
async devshell(appId, isUserApp, onconnect = null) {
|
|
102
88
|
const resolvedIp = await resolveDomain(this.domain)
|
|
89
|
+
let waiting = true
|
|
90
|
+
while (waiting) {
|
|
91
|
+
if (await this.isDevshell(appId)) {
|
|
92
|
+
waiting = false
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
logger.debug("wait app container to running...")
|
|
96
|
+
await sleep(100)
|
|
97
|
+
}
|
|
98
|
+
|
|
103
99
|
const stream = spawn(
|
|
104
100
|
`ssh -p 22222 box@${resolvedIp}`,
|
|
105
101
|
[
|
|
@@ -119,9 +115,9 @@ export class DebugBridge {
|
|
|
119
115
|
stream.on("close", (code) => {
|
|
120
116
|
code == 0 ? resolve() : reject()
|
|
121
117
|
})
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
// spawn 事件只是进程启动成功的事件,并不是ssh成功连接上的事件。所以这里使
|
|
119
|
+
// 用前面的一个 isDevshell 判断是否已经启动这个容器,再使用 spawn
|
|
120
|
+
stream.on("spawn", onconnect)
|
|
125
121
|
})
|
|
126
122
|
}
|
|
127
123
|
|
package/lib/app/lpk_devshell.js
CHANGED
package/lib/app/lpk_installer.js
CHANGED
|
@@ -7,6 +7,7 @@ import { DebugBridge } from "./lpk_debug_bridge.js"
|
|
|
7
7
|
import shellapi from "../shellapi.js"
|
|
8
8
|
import { triggerApk } from "./apkshell.js"
|
|
9
9
|
|
|
10
|
+
export const installConfig = { apk: true }
|
|
10
11
|
// 从一个目录中找出修改时间最新的包
|
|
11
12
|
function findOnceLpkByDir(dir = process.cwd()) {
|
|
12
13
|
const pkg = fs
|
|
@@ -95,11 +96,14 @@ export class LpkInstaller {
|
|
|
95
96
|
try {
|
|
96
97
|
spawnSync("unzip", ["-d", tempDir, pkgPath])
|
|
97
98
|
manifest = loadFromYaml(path.join(tempDir, "manifest.yml"))
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
logger.debug("是否生成APK:", installConfig.apk)
|
|
100
|
+
if (installConfig.apk) {
|
|
101
|
+
await triggerApk(
|
|
102
|
+
manifest["package"],
|
|
103
|
+
manifest["name"],
|
|
104
|
+
path.resolve(path.join(tempDir, "icon.png"))
|
|
105
|
+
)
|
|
106
|
+
}
|
|
103
107
|
logger.debug("lpk manifest", manifest)
|
|
104
108
|
} finally {
|
|
105
109
|
fs.rmSync(tempDir, { recursive: true })
|
|
@@ -113,5 +117,6 @@ export class LpkInstaller {
|
|
|
113
117
|
logger.info(
|
|
114
118
|
`👉 请在浏览器中访问 https://${manifest["application"]["subdomain"]}.${shellapi.boxname}.heiyu.space`
|
|
115
119
|
)
|
|
120
|
+
logger.info(`👉 并使用微服的用户名和密码登录`)
|
|
116
121
|
}
|
|
117
122
|
}
|
package/lib/appstore/login.js
CHANGED
|
@@ -3,7 +3,6 @@ import path from "path"
|
|
|
3
3
|
import logger from "loglevel"
|
|
4
4
|
import env from "../env.js"
|
|
5
5
|
import inquirer from "inquirer"
|
|
6
|
-
import FormData from "form-data"
|
|
7
6
|
|
|
8
7
|
const accountServerUrl = "https://account.lazycat.cloud"
|
|
9
8
|
|
|
@@ -12,17 +11,13 @@ function join(...params) {
|
|
|
12
11
|
return x
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
function login(username, password) {
|
|
16
|
-
const form = new FormData()
|
|
17
|
-
form.append("username", username)
|
|
18
|
-
form.append("password", password)
|
|
19
|
-
|
|
14
|
+
async function login(username, password) {
|
|
20
15
|
return fetch(join(accountServerUrl, "/api/login/signin"), {
|
|
21
16
|
method: "POST",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
body: new URLSearchParams({
|
|
18
|
+
username: username,
|
|
19
|
+
password: password
|
|
20
|
+
})
|
|
26
21
|
})
|
|
27
22
|
.then(async (res) => {
|
|
28
23
|
let bodyText = await res.text()
|
package/lib/shellapi.js
CHANGED
|
@@ -32,6 +32,11 @@ class ShellApi {
|
|
|
32
32
|
const { addr, cred } = this.readShellApiInfo()
|
|
33
33
|
this.client = new pbShell.ShellCore(addr, grpc.credentials.createInsecure())
|
|
34
34
|
|
|
35
|
+
// 检查当前 shell 环境上下文是否配置 HTTP_PROXY
|
|
36
|
+
if (this.checkEnvProxy()) {
|
|
37
|
+
logger.warn(`WARN:: 当前终端环境已配置 HTTP_PROXY 代理,可能会导致访问懒猫微服失败,如果未影响功能可以忽略该警告`)
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
const md = new grpc.Metadata()
|
|
36
41
|
md.add("lzc-shellapi-cred", cred)
|
|
37
42
|
this.metadata = md
|
|
@@ -115,6 +120,19 @@ class ShellApi {
|
|
|
115
120
|
})
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
checkEnvProxy() {
|
|
124
|
+
if(process.env.HTTPS_PROXY ||
|
|
125
|
+
process.env.HTTP_PROXY ||
|
|
126
|
+
process.env.ALL_PROXY ||
|
|
127
|
+
process.env.https_proxy ||
|
|
128
|
+
process.env.http_proxy ||
|
|
129
|
+
process.env.all_proxy
|
|
130
|
+
){
|
|
131
|
+
return true
|
|
132
|
+
}
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
|
|
118
136
|
async setDefaultBox(boxname) {
|
|
119
137
|
const boxes = await this.boxList()
|
|
120
138
|
const box = boxes.find((b) => b.box_name === boxname)
|
package/lib/utils.js
CHANGED
|
@@ -16,6 +16,21 @@ import { spawnSync } from "node:child_process"
|
|
|
16
16
|
import logger from "loglevel"
|
|
17
17
|
import * as tar from "tar"
|
|
18
18
|
import dns from "node:dns/promises"
|
|
19
|
+
import axios from "axios"
|
|
20
|
+
|
|
21
|
+
// 创建 Axios 实例
|
|
22
|
+
export const api = axios.create()
|
|
23
|
+
|
|
24
|
+
// 添加响应拦截器
|
|
25
|
+
api.interceptors.response.use(
|
|
26
|
+
(response) => response, // 直接返回响应
|
|
27
|
+
(error) => {
|
|
28
|
+
if (error.response && error.response.status === 304) {
|
|
29
|
+
return Promise.resolve(error.response) // 返回响应以便后续处理
|
|
30
|
+
}
|
|
31
|
+
return Promise.reject(error) // 其他错误继续抛出
|
|
32
|
+
}
|
|
33
|
+
)
|
|
19
34
|
|
|
20
35
|
export const envsubstr = async (templateContents, args) => {
|
|
21
36
|
const parse = await importDefault("envsub/js/envsub-parser.js")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazycatcloud/lzc-cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.30",
|
|
4
4
|
"description": "lazycat cloud developer kit",
|
|
5
5
|
"files": [
|
|
6
6
|
"template",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@grpc/grpc-js": "^1.11.1",
|
|
22
22
|
"@grpc/proto-loader": "^0.7.13",
|
|
23
23
|
"archiver": "^7.0.1",
|
|
24
|
+
"axios": "^1.7.7",
|
|
24
25
|
"chalk": "^5.3.0",
|
|
25
26
|
"chokidar": "^3.6.0",
|
|
26
27
|
"command-exists": "^1.2.9",
|