-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathhosting.ts
263 lines (228 loc) · 7.26 KB
/
hosting.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import path from 'path'
import {
CloudApiService,
firstLetterToLowerCase,
isDirectory,
genClickableLink,
checkReadable,
getStorageService,
logger
} from './utils'
import { CloudBaseError } from './error'
import inquirer from 'inquirer'
import { EnvType } from './constant'
interface IBaseOptions {
envId: string
}
interface IHostingFileOptions extends IBaseOptions {
filePath: string
cloudPath: string
isDir: boolean
onProgress?: (data: any) => void
onFileFinish?: (...args) => void
}
interface IHostingCloudOptions extends IBaseOptions {
cloudPath: string
isDir: boolean
}
const HostingStatusMap = {
init: '初始化中',
process: '处理中',
online: '上线',
destroying: '销毁中',
offline: '下线',
create_fail: '初始化失败', // eslint-disable-line
destroy_fail: '销毁失败' // eslint-disable-line
}
const tcbService = CloudApiService.getInstance('tcb')
export async function getHostingInfo(options: IBaseOptions) {
const { envId } = options
const res = await tcbService.request('DescribeStaticStore', {
EnvId: envId
})
const data = firstLetterToLowerCase(res)
return data
}
export async function initHosting(options: IBaseOptions) {
const { envId } = options
const envInfo = await getEnvInfoByEnvId({ envId })
if (envInfo.EnvType === EnvType.BAAS) {
// 开通静态托管
const { confirm } = await inquirer.prompt({
type: 'confirm',
name: 'confirm',
message: '您还未开通静态托管,是否立即开通?'
})
if (confirm) {
const res = await subscribeHosting({ envId })
if (!res.code) {
logger.success('开通静态托管成功!资源正在初始化中,请稍候3~5分钟再试...')
return
} else {
throw new CloudBaseError(`开通静态托管失败\n request id: ${res.requestId}`)
}
} else return
} else {
const link = genClickableLink('https://console.cloud.tencent.com/tcb')
throw new CloudBaseError(
`您还没有开启静态网站服务,请先到云开发控制台开启静态网站服务!\n👉 ${link}`,
{
code: 'INVALID_OPERATION'
}
)
}
}
export async function checkHostingStatus(envId: string) {
const hostings = await getHostingInfo({ envId })
if (!hostings.data || !hostings.data.length) {
await initHosting({ envId })
return
}
const website = hostings.data[0]
if (website.status !== 'online') {
throw new CloudBaseError(
`静态网站服务【${HostingStatusMap[website.status]}】,无法进行此操作!`,
{
code: 'INVALID_OPERATION'
}
)
}
return website
}
export async function enableHosting(options: IBaseOptions) {
const { envId } = options
const hostings = await getHostingInfo(options)
if (hostings?.data?.length) {
const website = hostings.data[0]
// offline 状态的服务可重新开启
if (website.status !== 'offline') {
throw new CloudBaseError('静态网站服务已开启,请勿重复操作!')
}
}
const res = await tcbService.request('CreateStaticStore', {
EnvId: envId
})
const code = res.Result === 'succ' ? 0 : -1
return {
code,
requestId: res.RequestId
}
}
// 获取指定环境信息
export async function getEnvInfoByEnvId(options: IBaseOptions) {
const { envId } = options
const res = await tcbService.request('DescribeEnvs', {
EnvId: envId
})
return res?.EnvList?.filter(item => item.EnvId === envId)[0]
}
// 开通静态网站托管
export async function subscribeHosting(options: IBaseOptions) {
const { envId } = options
const res = await tcbService.request('DescribeStaticStore', {
EnvId: envId
})
const code = res.Result === 'succ' ? 0 : -1
return {
code,
requestId: res.RequestId
}
}
// 展示文件信息
export async function hostingList(options: IBaseOptions) {
const { envId } = options
const hosting = await checkHostingStatus(envId)
const { bucket, regoin } = hosting
const storageService = await getStorageService(envId)
const list = await storageService.walkCloudDirCustom({
prefix: '',
bucket,
region: regoin
})
return list
}
export async function destroyHosting(options: IBaseOptions) {
const { envId } = options
const files = await hostingList(options)
if (files?.length) {
throw new CloudBaseError('静态网站文件不为空,无法销毁!', {
code: 'INVALID_OPERATION'
})
}
const hostings = await getHostingInfo(options)
if (!hostings.data || !hostings.data.length) {
throw new CloudBaseError('静态网站服务未开启!', {
code: 'INVALID_OPERATION'
})
}
const website = hostings.data[0]
// destroy_fail 状态可重试
if (website.status !== 'online' && website.status !== 'destroy_fail') {
throw new CloudBaseError(
`静态网站服务【${HostingStatusMap[website.status]}】,无法进行此操作!`,
{
code: 'INVALID_OPERATION'
}
)
}
const res = await tcbService.request('DestroyStaticStore', {
EnvId: envId
})
const code = res.Result === 'succ' ? 0 : -1
return {
code,
requestId: res.RequestId
}
}
// 上传文件
export async function hostingDeploy(options: IHostingFileOptions) {
const { envId, filePath, cloudPath, onProgress, onFileFinish } = options
const resolvePath = path.resolve(filePath)
// 检查路径是否存在
checkReadable(resolvePath, true)
const hosting = await checkHostingStatus(envId)
const { bucket, regoin } = hosting
const storageService = await getStorageService(envId)
if (isDirectory(resolvePath)) {
await storageService.uploadDirectoryCustom({
localPath: resolvePath,
cloudPath,
bucket,
region: regoin,
onProgress,
onFileFinish,
fileId: false
})
} else {
const assignCloudPath = cloudPath || path.parse(resolvePath).base
await storageService.uploadFileCustom({
localPath: resolvePath,
cloudPath: assignCloudPath,
bucket,
region: regoin,
onProgress,
fileId: false
})
}
}
// 删除文件
export async function hostingDelete(options: IHostingCloudOptions) {
const { envId, cloudPath, isDir } = options
const hosting = await checkHostingStatus(envId)
const { bucket, regoin } = hosting
const storageService = await getStorageService(envId)
if (isDir) {
await storageService.deleteDirectoryCustom({
cloudPath,
bucket,
region: regoin
})
} else {
await storageService.deleteFileCustom([cloudPath], bucket, regoin)
}
}
// 删除文件
export async function walkLocalDir(envId: string, dir: string) {
const storageService = await getStorageService(envId)
return storageService.walkLocalDir(dir)
}