forked from cojs/multipart
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
112 lines (92 loc) · 2.43 KB
/
index.js
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
var fs = require('fs')
var os = require('os')
var path = require('path')
var archan = require('archan')
var Busboy = require('busboy')
var rimraf = require('rimraf')
var saveTo = require('save-to')
var slice = [].slice
module.exports = function* (req, options) {
// KOA MAGIC SAUCE
req = req.req || req
options = options || {}
options.headers = req.headers
options.concurrency = options.concurrency || 2
var ch = archan(options)
var tmp = options.tmp || os.tmpdir()
var folder = path.join(tmp, uid())
// lets pray there are no issues here
yield fs.mkdir.bind(null, folder)
var baby = new Busboy(options)
var obj = new Output(folder)
req.on('close', abort)
baby
.on('close', abort)
.on('field', onField)
.on('file', onFile)
.on('error', onEnd)
.on('finish', onEnd)
req.pipe(baby)
var part
while (part = yield* ch.read(true)) {
// a file just got saved. yay!
if (typeof part === 'string')
continue
yield* ch.drain()
// it's a stream now
if (!part.filename)
part.filename = uid()
part.path = path.join(folder, part.filename)
saveTo(part, part.path, ch.push())
}
yield* ch.flush(false)
return obj
function onField() {
var args = slice.call(arguments)
obj.fields.push(args)
if (Object.getOwnPropertyDescriptor(Object.prototype, args[0])) return
obj.field[args[0]] = args[1]
}
function onFile(fieldname, file, filename, encoding, mimetype) {
// opinionated, but 5 arguments is ridiculous
file.fieldname = fieldname
file.filename = filename
file.transferEncoding = file.encoding = encoding
file.mimeType = file.mime = mimetype
obj.file[fieldname] = file
obj.files.push(file)
ch.push(file)
}
function onEnd(err) {
cleanup()
ch.push(err || null)
}
function abort() {
cleanup()
// noop? i dunno
rimraf(folder, noop)
}
function cleanup() {
req.removeListener('close', abort)
baby.removeListener('close', abort)
baby.removeListener('field', onField)
baby.removeListener('file', onFile)
baby.removeListener('error', onEnd)
baby.removeListener('finish', onEnd)
}
}
function Output(folder) {
this.file = {}
this.files = []
this.field = {}
this.fields = []
this.path = folder
}
Output.prototype.rimraf =
Output.prototype.dispose = function dispose(cb) {
rimraf(this.path, cb || noop)
}
function uid() {
return Math.random().toString(36).slice(2)
}
function noop() {}