piclist 1.8.9 → 1.8.11
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/.eslintignore +4 -0
- package/.eslintrc.js +50 -29
- package/.prettierrc +18 -0
- package/CHANGELOG.md +18 -0
- package/bin/picgo +25 -25
- package/bin/picgo-server +522 -491
- package/dist/core/Lifecycle.d.ts +1 -1
- package/dist/core/PicGo.d.ts +4 -4
- package/dist/i18n/en.d.ts +1 -1
- package/dist/i18n/index.d.ts +3 -4
- package/dist/i18n/zh-TW.d.ts +1 -1
- package/dist/index.cjs.js +2 -2
- package/dist/index.esm.js +2 -2
- package/dist/lib/Commander.d.ts +2 -2
- package/dist/lib/LifecyclePlugins.d.ts +1 -1
- package/dist/lib/Logger.d.ts +1 -1
- package/dist/lib/PluginHandler.d.ts +1 -1
- package/dist/lib/PluginLoader.d.ts +1 -1
- package/dist/lib/Request.d.ts +1 -1
- package/dist/plugins/beforetransformer/compress.d.ts +1 -1
- package/dist/plugins/beforetransformer/watermark.d.ts +1 -1
- package/dist/plugins/beforeupload/buildInRename.d.ts +1 -1
- package/dist/plugins/commander/config.d.ts +1 -1
- package/dist/plugins/commander/i18n.d.ts +1 -1
- package/dist/plugins/commander/index.d.ts +1 -1
- package/dist/plugins/commander/init.d.ts +1 -1
- package/dist/plugins/commander/pluginHandler.d.ts +1 -1
- package/dist/plugins/commander/proxy.d.ts +1 -1
- package/dist/plugins/commander/setting.d.ts +1 -1
- package/dist/plugins/commander/upload.d.ts +1 -1
- package/dist/plugins/commander/use.d.ts +1 -1
- package/dist/plugins/transformer/base64.d.ts +1 -1
- package/dist/plugins/transformer/index.d.ts +1 -1
- package/dist/plugins/transformer/path.d.ts +1 -1
- package/dist/plugins/uploader/aliyun.d.ts +1 -1
- package/dist/plugins/uploader/awss3plist.d.ts +1 -1
- package/dist/plugins/uploader/github.d.ts +1 -1
- package/dist/plugins/uploader/imgur.d.ts +1 -1
- package/dist/plugins/uploader/index.d.ts +1 -1
- package/dist/plugins/uploader/local.d.ts +1 -1
- package/dist/plugins/uploader/lsky.d.ts +1 -1
- package/dist/plugins/uploader/piclist.d.ts +1 -1
- package/dist/plugins/uploader/qiniu.d.ts +1 -1
- package/dist/plugins/uploader/s3/uploader.d.ts +1 -1
- package/dist/plugins/uploader/s3/utils.d.ts +1 -1
- package/dist/plugins/uploader/sftp.d.ts +1 -1
- package/dist/plugins/uploader/smms.d.ts +1 -1
- package/dist/plugins/uploader/tcyun.d.ts +1 -1
- package/dist/plugins/uploader/telegraph.d.ts +1 -1
- package/dist/plugins/uploader/upyun.d.ts +1 -1
- package/dist/plugins/uploader/webdav.d.ts +1 -1
- package/dist/types/index.d.ts +5 -5
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/createContext.d.ts +1 -1
- package/dist/utils/db.d.ts +2 -2
- package/dist/utils/getClipboardImage.d.ts +1 -1
- package/dist/utils/initUtils.d.ts +1 -1
- package/dist/utils/interfaces.d.ts +3 -3
- package/dist/utils/sshClient.d.ts +10 -11
- package/package.json +10 -7
- package/rollup.config.js +93 -93
package/bin/picgo-server
CHANGED
|
@@ -1,491 +1,522 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const http = require('http')
|
|
3
|
-
const multer = require('multer')
|
|
4
|
-
const axios = require('axios')
|
|
5
|
-
const minimist = require('minimist')
|
|
6
|
-
const fs = require('fs-extra')
|
|
7
|
-
const path = require('path')
|
|
8
|
-
const os = require('os')
|
|
9
|
-
|
|
10
|
-
const tempDir = path.join(os.homedir(), '.piclist', 'serverTemp')
|
|
11
|
-
fs.ensureDirSync(tempDir)
|
|
12
|
-
|
|
13
|
-
const argv = minimist(process.argv.slice(2))
|
|
14
|
-
|
|
15
|
-
let key = ''
|
|
16
|
-
let defaultPort = 36677
|
|
17
|
-
let defaultHost = '0.0.0.0'
|
|
18
|
-
|
|
19
|
-
if (argv.h || argv.help) {
|
|
20
|
-
showHelp()
|
|
21
|
-
process.exit(0)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (argv.v || argv.version) {
|
|
25
|
-
showVersion()
|
|
26
|
-
process.exit(0)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (argv.k || argv.key) {
|
|
30
|
-
key = String(argv.k || argv.key)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (argv.p || argv.port) {
|
|
34
|
-
defaultPort = Number(argv.p || argv.port) || defaultPort
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (argv.host) {
|
|
38
|
-
defaultHost = String(argv.host)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function showVersion() {
|
|
42
|
-
const pkg = require('../package.json')
|
|
43
|
-
console.log(`PicList-Core ${pkg.version}`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function showHelp() {
|
|
47
|
-
console.log(`
|
|
48
|
-
Usage: picgo-server [options]
|
|
49
|
-
Options:
|
|
50
|
-
-h, --help Print this help message
|
|
51
|
-
-c, --config Set config path
|
|
52
|
-
-p, --port Set port, default port is 36677
|
|
53
|
-
--host Set host, default host is 0.0.0.0
|
|
54
|
-
-k, --key Set secret key to avoid unauthorized access
|
|
55
|
-
-v, --version Print version number
|
|
56
|
-
|
|
57
|
-
Example:
|
|
58
|
-
picgo-server -c /path/to/config.json
|
|
59
|
-
picgo-server -k 123456
|
|
60
|
-
picgo-server -c /path/to/config.json -k 123456
|
|
61
|
-
`)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let configPath = argv.c || argv.config || ''
|
|
65
|
-
if (configPath !== true && configPath !== '') {
|
|
66
|
-
configPath = configPath.replace(/^~/, os.homedir())
|
|
67
|
-
configPath = path.resolve(configPath)
|
|
68
|
-
} else {
|
|
69
|
-
configPath = ''
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const { PicGo } = require('..')
|
|
73
|
-
const picgo = new PicGo(configPath)
|
|
74
|
-
const errorMessage = 'Upload failed, please check your network and config'
|
|
75
|
-
|
|
76
|
-
handleResponse = ({
|
|
77
|
-
response,
|
|
78
|
-
statusCode = 200,
|
|
79
|
-
header = {
|
|
80
|
-
'Content-Type': 'application/json',
|
|
81
|
-
'access-control-allow-headers': '*',
|
|
82
|
-
'access-control-allow-methods': 'POST, GET, OPTIONS',
|
|
83
|
-
'access-control-allow-origin': '*'
|
|
84
|
-
},
|
|
85
|
-
body = {
|
|
86
|
-
success: false
|
|
87
|
-
}
|
|
88
|
-
}) => {
|
|
89
|
-
if (body && body.success === false) {
|
|
90
|
-
console.log('[PicList Server] upload failed, see log for more detail ↑')
|
|
91
|
-
}
|
|
92
|
-
response.writeHead(statusCode, header)
|
|
93
|
-
response.write(JSON.stringify(body))
|
|
94
|
-
response.end()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
ensureHTTPLink = url => {
|
|
98
|
-
return url.startsWith('http') ? url : `http://${url}`
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
class Router {
|
|
102
|
-
constructor() {
|
|
103
|
-
this.router = new Map()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
addRoute
|
|
107
|
-
if (!this.router.has(url)) {
|
|
108
|
-
this.router.set(url, new Map())
|
|
109
|
-
}
|
|
110
|
-
this.router.get(url).set(method, { handler: callback, urlparams })
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
get
|
|
114
|
-
this.addRoute('GET', url, callback, urlparams)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
post(url, callback, urlparams) {
|
|
118
|
-
this.addRoute('POST', url, callback, urlparams)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
any(url, callback, urlparams) {
|
|
122
|
-
this.addRoute('GET', url, callback, urlparams)
|
|
123
|
-
this.addRoute('POST', url, callback, urlparams)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
getHandler
|
|
127
|
-
if (this.router.has(url)) {
|
|
128
|
-
const methods = this.router.get(url)
|
|
129
|
-
if (methods.has(method)) {
|
|
130
|
-
return methods.get(method)
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return null
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
let router = new Router()
|
|
138
|
-
|
|
139
|
-
const multerStorage = multer.diskStorage({
|
|
140
|
-
destination: function (_req, _file, cb) {
|
|
141
|
-
if (!fs.existsSync(tempDir)) {
|
|
142
|
-
fs.mkdirSync(tempDir)
|
|
143
|
-
}
|
|
144
|
-
cb(null, tempDir)
|
|
145
|
-
},
|
|
146
|
-
filename: function (_req, file, cb) {
|
|
147
|
-
if (!/[^\u0000-\u00ff]/.test(file.originalname)) {
|
|
148
|
-
file.originalname = Buffer.from(file.originalname, 'latin1').toString(
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
<
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
<
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
<p
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
</
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
console.log('[PicList Server]', err)
|
|
406
|
-
return handleResponse({
|
|
407
|
-
response,
|
|
408
|
-
body: {
|
|
409
|
-
success: false,
|
|
410
|
-
message: '
|
|
411
|
-
}
|
|
412
|
-
})
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
} else {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
this.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const http = require('http')
|
|
3
|
+
const multer = require('multer')
|
|
4
|
+
const axios = require('axios')
|
|
5
|
+
const minimist = require('minimist')
|
|
6
|
+
const fs = require('fs-extra')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
const os = require('os')
|
|
9
|
+
|
|
10
|
+
const tempDir = path.join(os.homedir(), '.piclist', 'serverTemp')
|
|
11
|
+
fs.ensureDirSync(tempDir)
|
|
12
|
+
|
|
13
|
+
const argv = minimist(process.argv.slice(2))
|
|
14
|
+
|
|
15
|
+
let key = ''
|
|
16
|
+
let defaultPort = 36677
|
|
17
|
+
let defaultHost = '0.0.0.0'
|
|
18
|
+
|
|
19
|
+
if (argv.h || argv.help) {
|
|
20
|
+
showHelp()
|
|
21
|
+
process.exit(0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (argv.v || argv.version) {
|
|
25
|
+
showVersion()
|
|
26
|
+
process.exit(0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (argv.k || argv.key) {
|
|
30
|
+
key = String(argv.k || argv.key)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (argv.p || argv.port) {
|
|
34
|
+
defaultPort = Number(argv.p || argv.port) || defaultPort
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (argv.host) {
|
|
38
|
+
defaultHost = String(argv.host)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function showVersion() {
|
|
42
|
+
const pkg = require('../package.json')
|
|
43
|
+
console.log(`PicList-Core ${pkg.version}`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function showHelp() {
|
|
47
|
+
console.log(`
|
|
48
|
+
Usage: picgo-server [options]
|
|
49
|
+
Options:
|
|
50
|
+
-h, --help Print this help message
|
|
51
|
+
-c, --config Set config path
|
|
52
|
+
-p, --port Set port, default port is 36677
|
|
53
|
+
--host Set host, default host is 0.0.0.0
|
|
54
|
+
-k, --key Set secret key to avoid unauthorized access
|
|
55
|
+
-v, --version Print version number
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
picgo-server -c /path/to/config.json
|
|
59
|
+
picgo-server -k 123456
|
|
60
|
+
picgo-server -c /path/to/config.json -k 123456
|
|
61
|
+
`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let configPath = argv.c || argv.config || ''
|
|
65
|
+
if (configPath !== true && configPath !== '') {
|
|
66
|
+
configPath = configPath.replace(/^~/, os.homedir())
|
|
67
|
+
configPath = path.resolve(configPath)
|
|
68
|
+
} else {
|
|
69
|
+
configPath = ''
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { PicGo } = require('..')
|
|
73
|
+
const picgo = new PicGo(configPath)
|
|
74
|
+
const errorMessage = 'Upload failed, please check your network and config'
|
|
75
|
+
|
|
76
|
+
handleResponse = ({
|
|
77
|
+
response,
|
|
78
|
+
statusCode = 200,
|
|
79
|
+
header = {
|
|
80
|
+
'Content-Type': 'application/json',
|
|
81
|
+
'access-control-allow-headers': '*',
|
|
82
|
+
'access-control-allow-methods': 'POST, GET, OPTIONS',
|
|
83
|
+
'access-control-allow-origin': '*'
|
|
84
|
+
},
|
|
85
|
+
body = {
|
|
86
|
+
success: false
|
|
87
|
+
}
|
|
88
|
+
}) => {
|
|
89
|
+
if (body && body.success === false) {
|
|
90
|
+
console.log('[PicList Server] upload failed, see log for more detail ↑')
|
|
91
|
+
}
|
|
92
|
+
response.writeHead(statusCode, header)
|
|
93
|
+
response.write(JSON.stringify(body))
|
|
94
|
+
response.end()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
ensureHTTPLink = url => {
|
|
98
|
+
return url.startsWith('http') ? url : `http://${url}`
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
class Router {
|
|
102
|
+
constructor() {
|
|
103
|
+
this.router = new Map()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
addRoute(method, url, callback, urlparams) {
|
|
107
|
+
if (!this.router.has(url)) {
|
|
108
|
+
this.router.set(url, new Map())
|
|
109
|
+
}
|
|
110
|
+
this.router.get(url).set(method, { handler: callback, urlparams })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get(url, callback, urlparams) {
|
|
114
|
+
this.addRoute('GET', url, callback, urlparams)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
post(url, callback, urlparams) {
|
|
118
|
+
this.addRoute('POST', url, callback, urlparams)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
any(url, callback, urlparams) {
|
|
122
|
+
this.addRoute('GET', url, callback, urlparams)
|
|
123
|
+
this.addRoute('POST', url, callback, urlparams)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getHandler(url, method) {
|
|
127
|
+
if (this.router.has(url)) {
|
|
128
|
+
const methods = this.router.get(url)
|
|
129
|
+
if (methods.has(method)) {
|
|
130
|
+
return methods.get(method)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let router = new Router()
|
|
138
|
+
|
|
139
|
+
const multerStorage = multer.diskStorage({
|
|
140
|
+
destination: function (_req, _file, cb) {
|
|
141
|
+
if (!fs.existsSync(tempDir)) {
|
|
142
|
+
fs.mkdirSync(tempDir)
|
|
143
|
+
}
|
|
144
|
+
cb(null, tempDir)
|
|
145
|
+
},
|
|
146
|
+
filename: function (_req, file, cb) {
|
|
147
|
+
if (!/[^\u0000-\u00ff]/.test(file.originalname)) {
|
|
148
|
+
file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8')
|
|
149
|
+
}
|
|
150
|
+
cb(null, file.originalname)
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const uploadMulter = multer({
|
|
155
|
+
storage: multerStorage
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const changeCurrentUploader = (type, config, id) => {
|
|
159
|
+
if (!type) return
|
|
160
|
+
if (id) {
|
|
161
|
+
picgo.saveConfig({
|
|
162
|
+
[`uploader.${type}.defaultId`]: id
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
if (config) {
|
|
166
|
+
picgo.saveConfig({
|
|
167
|
+
[`picBed.${type}`]: config
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
picgo.saveConfig({
|
|
171
|
+
'picBed.current': type,
|
|
172
|
+
'picBed.uploader': type
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
router.get('/', responseForGet)
|
|
177
|
+
router.get('/upload', responseForGet)
|
|
178
|
+
|
|
179
|
+
router.post('/upload', async ({ response, list = [], urlparams }) => {
|
|
180
|
+
try {
|
|
181
|
+
const picbed = urlparams?.get('picbed')
|
|
182
|
+
const passedKey = urlparams?.get('key')
|
|
183
|
+
if (key && key !== passedKey) {
|
|
184
|
+
console.log('[PicList Server] Unauthorized access')
|
|
185
|
+
return handleResponse({
|
|
186
|
+
response,
|
|
187
|
+
body: {
|
|
188
|
+
success: false,
|
|
189
|
+
message: 'Unauthorized access'
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
let currentPicBedType = ''
|
|
194
|
+
let currentPicBedConfig = {}
|
|
195
|
+
let currentPicBedConfigId = ''
|
|
196
|
+
const currentPicBed = picgo.getConfig('picBed') || {}
|
|
197
|
+
let needRestore = false
|
|
198
|
+
if (picbed) {
|
|
199
|
+
currentPicBedType = currentPicBed.uploader || currentPicBed.current || 'smms'
|
|
200
|
+
currentPicBedConfig = currentPicBed[currentPicBedType] || {}
|
|
201
|
+
currentPicBedConfigId = currentPicBedConfig._id
|
|
202
|
+
const configName = urlparams?.get('configName') || currentPicBed[picbed]?._configName
|
|
203
|
+
if (picbed === currentPicBedType && currentPicBedConfig._configName === configName) {
|
|
204
|
+
// do nothing
|
|
205
|
+
} else {
|
|
206
|
+
if (picbed !== currentPicBedType) {
|
|
207
|
+
needRestore = true
|
|
208
|
+
picgo.saveConfig({
|
|
209
|
+
'picBed.current': picbed,
|
|
210
|
+
'picBed.uploader': picbed
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
if (currentPicBed[picbed]?._configName) {
|
|
214
|
+
needRestore = true
|
|
215
|
+
const picBeds = picgo.getConfig('uploader')
|
|
216
|
+
const currentPicBedList = picBeds?.[picbed]?.configList
|
|
217
|
+
if (currentPicBedList) {
|
|
218
|
+
const currentConfig = currentPicBedList?.find((item) => item._configName === configName)
|
|
219
|
+
changeCurrentUploader(picbed, currentConfig, currentConfig._id)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (list.length === 0) {
|
|
225
|
+
// upload with clipboard
|
|
226
|
+
console.log('[PicList Server] upload clipboard file')
|
|
227
|
+
const result = await picgo.upload()
|
|
228
|
+
const res = result[0].imgUrl
|
|
229
|
+
console.log('[PicList Server] upload result:', res)
|
|
230
|
+
if (res) {
|
|
231
|
+
handleResponse({
|
|
232
|
+
response,
|
|
233
|
+
body: {
|
|
234
|
+
success: true,
|
|
235
|
+
result: [res]
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
} else {
|
|
239
|
+
handleResponse({
|
|
240
|
+
response,
|
|
241
|
+
body: {
|
|
242
|
+
success: false,
|
|
243
|
+
message: errorMessage
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
console.log('[PicList Server] upload files in list')
|
|
249
|
+
// upload with files
|
|
250
|
+
const result = await picgo.upload(list)
|
|
251
|
+
const res = result.map(item => {
|
|
252
|
+
return item.imgUrl
|
|
253
|
+
})
|
|
254
|
+
console.log('[PicList Server] upload result\n', res.join('\n'))
|
|
255
|
+
if (res.length) {
|
|
256
|
+
handleResponse({
|
|
257
|
+
response,
|
|
258
|
+
body: {
|
|
259
|
+
success: true,
|
|
260
|
+
result: res
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
} else {
|
|
264
|
+
handleResponse({
|
|
265
|
+
response,
|
|
266
|
+
body: {
|
|
267
|
+
success: false,
|
|
268
|
+
message: errorMessage
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
fs.emptyDirSync(tempDir)
|
|
274
|
+
if (needRestore) {
|
|
275
|
+
picgo.saveConfig({
|
|
276
|
+
'picBed.current': currentPicBedType,
|
|
277
|
+
'picBed.uploader': currentPicBedType
|
|
278
|
+
})
|
|
279
|
+
if (currentPicBed[picbed]?._configName) {
|
|
280
|
+
changeCurrentUploader(currentPicBedType, currentPicBedConfig, currentPicBedConfigId)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
} catch (err) {
|
|
284
|
+
console.log(err)
|
|
285
|
+
handleResponse({
|
|
286
|
+
response,
|
|
287
|
+
body: {
|
|
288
|
+
success: false,
|
|
289
|
+
message: errorMessage
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
async function responseForGet({ response }) {
|
|
296
|
+
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
|
|
297
|
+
response.write(`
|
|
298
|
+
<!DOCTYPE html>
|
|
299
|
+
<html lang="en">
|
|
300
|
+
<head>
|
|
301
|
+
<meta charset="UTF-8">
|
|
302
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
303
|
+
<title>Picgo-Server Usage</title>
|
|
304
|
+
<style>
|
|
305
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
306
|
+
pre { background-color: #f4f4f4; padding: 10px; }
|
|
307
|
+
.tip { padding: 10px; background-color: #f0f9ff; border-left: 5px solid #2196F3; margin-bottom: 20px; }
|
|
308
|
+
</style>
|
|
309
|
+
</head>
|
|
310
|
+
<body>
|
|
311
|
+
<h2>picgo-server的使用</h2>
|
|
312
|
+
<p><code>picgo-server</code>命令用于启动web服务,接收来自其他应用或其他主机的HTTP请求来上传图片。</p>
|
|
313
|
+
<p>默认监听地址:<code>0.0.0.0</code>,默认监听端口:<code>36677</code></p>
|
|
314
|
+
|
|
315
|
+
<h3>接口鉴权</h3>
|
|
316
|
+
<p>当将接口暴露于公网时,为了防止恶意上传,可以使用接口鉴权功能。通过在运行<code>picgo-server</code>时添加<code>-k</code>或<code>--key</code>参数来设置一个密钥。</p>
|
|
317
|
+
<p>发送请求时添加URL查询参数<code>key</code>即可,例如:<code>http://xxx:36677/upload?key=xxx</code>。</p>
|
|
318
|
+
|
|
319
|
+
<h3>表单上传</h3>
|
|
320
|
+
<ul>
|
|
321
|
+
<li>请求方法: <code>POST</code></li>
|
|
322
|
+
<li>url: <code>http://127.0.0.1:36677/upload</code> (此处以默认配置为例)</li>
|
|
323
|
+
<li>请求body: <code>multipart/form-data</code>格式,key任选,value为图片文件</li>
|
|
324
|
+
</ul>
|
|
325
|
+
|
|
326
|
+
<h3>HTTP调用上传剪贴板图片</h3>
|
|
327
|
+
<ul>
|
|
328
|
+
<li>请求方法: <code>POST</code></li>
|
|
329
|
+
<li>url: <code>http://127.0.0.1:36677/upload</code> (此处以默认配置为例)</li>
|
|
330
|
+
<li>请求body: <code>{list: ['xxx.jpg']}</code> 必须是JSON格式</li>
|
|
331
|
+
</ul>
|
|
332
|
+
|
|
333
|
+
<div class="tip">Tip: PicList支持通过设置<code>picbed</code>和<code>configName</code>两个URL查询参数来指定上传图床和配置文件。例如:<code>http://127.0.0.1:36677/upload?picbed=aws-s3&configName=piclist-test</code> 该配置将会使用<code>aws-s3</code>图床,并且使用<code>piclist-test</code>配置文件。</div>
|
|
334
|
+
|
|
335
|
+
<p>返回的数据:</p>
|
|
336
|
+
<pre>{
|
|
337
|
+
"success": true, // or false
|
|
338
|
+
"result": ["url"]
|
|
339
|
+
}</pre>
|
|
340
|
+
|
|
341
|
+
<h3>HTTP调用上传具体路径图片</h3>
|
|
342
|
+
<ul>
|
|
343
|
+
<li>method: <code>POST</code></li>
|
|
344
|
+
<li>url: <code>http://127.0.0.1:36677/upload</code> (此处以默认配置为例)</li>
|
|
345
|
+
<li>request body: <code>{list: ['xxx.jpg']}</code> 必须是JSON格式</li>
|
|
346
|
+
</ul>
|
|
347
|
+
|
|
348
|
+
<p>返回的数据:</p>
|
|
349
|
+
<pre>{
|
|
350
|
+
"success": true, // or false
|
|
351
|
+
"result": ["url"]
|
|
352
|
+
}</pre>
|
|
353
|
+
|
|
354
|
+
</body>
|
|
355
|
+
</html>
|
|
356
|
+
`)
|
|
357
|
+
response.end()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
router.any('/heartbeat', async ({ response }) => {
|
|
361
|
+
handleResponse({
|
|
362
|
+
response,
|
|
363
|
+
body: {
|
|
364
|
+
success: true,
|
|
365
|
+
result: 'alive'
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
class Server {
|
|
371
|
+
constructor() {
|
|
372
|
+
this.httpServer = http.createServer(this.handleRequest)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
handleRequest(request, response) {
|
|
376
|
+
if (request.method === 'OPTIONS') {
|
|
377
|
+
handleResponse({ response })
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (request.method === 'POST') {
|
|
382
|
+
const [url, query] = (request.url || '').split('?')
|
|
383
|
+
if (!router.getHandler(url, 'POST')) {
|
|
384
|
+
console.log(`[PicList Server] don't support [${url}] endpoint`)
|
|
385
|
+
handleResponse({
|
|
386
|
+
response,
|
|
387
|
+
statusCode: 404,
|
|
388
|
+
body: {
|
|
389
|
+
success: false
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
} else {
|
|
393
|
+
let urlSP = query ? new URLSearchParams(query) : undefined
|
|
394
|
+
console.log('[PicList Server] get the request from IP:', request.socket.remoteAddress)
|
|
395
|
+
if (request.socket.remoteAddress === '127.0.0.1' || request.socket.remoteAddress === '::1') {
|
|
396
|
+
if (urlSP) {
|
|
397
|
+
urlSP.set('key', key)
|
|
398
|
+
} else {
|
|
399
|
+
urlSP = new URLSearchParams('key=' + key)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (request.headers['content-type'] && request.headers['content-type'].startsWith('multipart/form-data')) {
|
|
403
|
+
uploadMulter.any()(request, response, err => {
|
|
404
|
+
if (err) {
|
|
405
|
+
console.log('[PicList Server]', err)
|
|
406
|
+
return handleResponse({
|
|
407
|
+
response,
|
|
408
|
+
body: {
|
|
409
|
+
success: false,
|
|
410
|
+
message: 'Error processing formData'
|
|
411
|
+
}
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const list = request.files.map(file => file.path)
|
|
416
|
+
|
|
417
|
+
const handler = router.getHandler(url, 'POST')?.handler
|
|
418
|
+
if (handler) {
|
|
419
|
+
handler({
|
|
420
|
+
list: list,
|
|
421
|
+
response,
|
|
422
|
+
urlparams: urlSP
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
} else {
|
|
427
|
+
let body = ''
|
|
428
|
+
let postObj
|
|
429
|
+
request.on('data', chunk => {
|
|
430
|
+
body += chunk
|
|
431
|
+
})
|
|
432
|
+
request.on('end', () => {
|
|
433
|
+
try {
|
|
434
|
+
postObj = body === '' ? {} : JSON.parse(body)
|
|
435
|
+
} catch (err) {
|
|
436
|
+
console.log('[PicList Server]', err)
|
|
437
|
+
return handleResponse({
|
|
438
|
+
response,
|
|
439
|
+
body: {
|
|
440
|
+
success: false,
|
|
441
|
+
message: 'Not sending data in JSON format'
|
|
442
|
+
}
|
|
443
|
+
})
|
|
444
|
+
}
|
|
445
|
+
console.log('[PicList Server] get the request', body)
|
|
446
|
+
const handler = router.getHandler(url, 'POST')?.handler
|
|
447
|
+
if (handler) {
|
|
448
|
+
handler({
|
|
449
|
+
...postObj,
|
|
450
|
+
response,
|
|
451
|
+
urlparams: urlSP
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
} else if (request.method === 'GET') {
|
|
458
|
+
const [url, query] = (request.url || '').split('?')
|
|
459
|
+
if (!router.getHandler(url, 'GET')) {
|
|
460
|
+
console.log(`[PicList Server] don't support [${url}] endpoint`)
|
|
461
|
+
response.statusCode = 404
|
|
462
|
+
response.end()
|
|
463
|
+
} else {
|
|
464
|
+
const handler = router.getHandler(url, 'GET')?.handler
|
|
465
|
+
if (handler) {
|
|
466
|
+
handler({
|
|
467
|
+
response,
|
|
468
|
+
urlparams: query ? new URLSearchParams(query) : undefined
|
|
469
|
+
})
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
console.log(`[PicList Server] don't support [${request.method}] method`)
|
|
474
|
+
response.statusCode = 405
|
|
475
|
+
response.end()
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
listen(port) {
|
|
480
|
+
console.log(`[PicList Server] is listening at ${port}`)
|
|
481
|
+
if (typeof port === 'string') {
|
|
482
|
+
port = parseInt(port, 10)
|
|
483
|
+
}
|
|
484
|
+
this.httpServer.listen(port, defaultHost).on('error', async err => {
|
|
485
|
+
if (err.code === 'EADDRINUSE') {
|
|
486
|
+
try {
|
|
487
|
+
await axios.post(ensureHTTPLink(`${defaultHost}:${port}/heartbeat`))
|
|
488
|
+
console.log(`[PicList Server] server is already running at ${port}, no need to start again`)
|
|
489
|
+
this.shutdown(true)
|
|
490
|
+
} catch (e) {
|
|
491
|
+
console.log(`[PicList Server] ${port} is busy, trying with port ${port + 1}`)
|
|
492
|
+
this.listen(port + 1)
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
console.log(`[PicList Server] failed to start server at ${port}`)
|
|
496
|
+
console.log(`[PicList Server] ${err}`)
|
|
497
|
+
}
|
|
498
|
+
})
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
startup() {
|
|
502
|
+
console.log('startup')
|
|
503
|
+
this.listen(defaultPort)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
shutdown(hasStarted) {
|
|
507
|
+
this.httpServer.close()
|
|
508
|
+
if (!hasStarted) {
|
|
509
|
+
console.log('[PicList Server] shutdown')
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
restart() {
|
|
514
|
+
this.shutdown()
|
|
515
|
+
this.startup()
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const server = new Server()
|
|
520
|
+
server.startup()
|
|
521
|
+
|
|
522
|
+
module.exports = server
|