-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxupload
More file actions
executable file
·212 lines (178 loc) · 6.12 KB
/
Copy pathxupload
File metadata and controls
executable file
·212 lines (178 loc) · 6.12 KB
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
#!/usr/bin/env node
// don't care if the certificate of an https is valid
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
// node modules
var fs = require('fs');
var path = require('path');
var program = require('commander');
var Q = require('q');
var Request = require('request');
var request = Request.defaults({jar: true});
function upload(options, requestObj) {
var deferred = Q.defer();
// default: true -> do not log
var verbose = true;
var callbackCalled = false;
// use other request implementation
if (typeof requestObj === 'function' || typeof requestObj === 'object') {
request = requestObj;
}
// configure the options
options = options || {};
// do set headers
options.headers = options.headers || {};
// configure verbose
verbose = options.verbose || verbose;
// delete to be require option ready
delete options.verbose;
var filePath = options.file || false;
// delete to be require option ready
delete options.file;
if (filePath) {
filePath = path.normalize(filePath);
var fileName = path.basename(filePath);
var formName = options.param;
}
var progress = options.progress || function (progress, chunk, totalFileSize) {
log('upload progress', progress, '%', 'uploaded', chunk, 'totalFileSize', totalFileSize);
};
var error = options.error || function (e) {
log('problem with request: ' + e.message);
};
// delete to be require option ready
delete options.error;
/**
* Call error callback only once
* If an async call throws an error after an error accoures do not fire it.
* @param arguments
*/
var errorCallback = function (arguments) {
if (!callbackCalled) {
callbackCalled = true;
error(arguments);
}
};
/**
* Use console.log with verbose option.
*/
var log = function () {
if (!verbose) {
console.log.apply(console, arguments);
}
};
// delete to be require option ready
delete options.progress;
// return if the file doesn't exist
if (filePath !== false && !fs.existsSync(filePath)) {
var e = 'Error: ENOENT, no such file or directory' + filePath;
errorCallback(e);
deferred.reject(e);
return deferred.promise;
}
// random string
var boundaryKey = Math.random().toString(16);
// total chunk size
var chunk = 0;
// formdata content
var content = '';
if (options.fields) {
var keys = Object.keys(options.fields);
for (var i = 0; i < keys.length; i++) {
var name = keys[i];
var value = options.fields[name];
content += '--' + boundaryKey + '\r\n';
content += 'Content-Disposition: form-data; name="' + name + '" \r\n\r\n' + value + '\r\n';
}
}
// the header for the one and only part (need to use CRLF here)
var r = request.post(options,function (e, http, response) {
if (e) {
log('error', e);
errorCallback(e);
deferred.reject(e);
return;
}
if (http.statusCode >= 300) {
errorCallback(http);
deferred.reject(http);
return;
}
return deferred.resolve(response);
});
if (typeof options.configure === 'function') {
options.configure(r);
}
if (filePath) {
var fsStat = fs.statSync(filePath);
var totalFileSize = fsStat.size;
try {
content += '--' + boundaryKey + '\r\n';
content += 'Content-Type: application/octet-stream\r\n';
content += 'Content-Disposition: form-data; name="' + formName + '"; filename="' + fileName + '"\r\n' + 'Content-Transfer-Encoding: binary\r\n\r\n';
// set the correct header
r.setHeader('Content-Type', 'multipart/form-data; boundary="' + boundaryKey + '"');
// write the content
r.write(content);
r.on('error', function (e) {
log('error', e);
errorCallback(e);
deferred.reject(e);
});
var fileStream = fs.createReadStream(filePath, { bufferSize: 4 * 1024 });
fileStream.on('error', function (e) {
log('error on filestream', e);
errorCallback(e);
deferred.reject(e);
});
fileStream.on('end', function () {
// mark the end of the one and only part
r.end('\r\n--' + boundaryKey + '--');
});
fileStream.on('data', function (data) {
// mark the end of the one and only part
chunk += data.length;
var percentage = 0;
if (totalFileSize !== 0) {
percentage = Math.floor((100 * chunk) / totalFileSize);
}
progress(percentage, chunk, totalFileSize);
deferred.notify(percentage);
});
// set "end" to false in the options so .end() isn't called on the request
fileStream.pipe(r, { end: false });
} catch (e) {
log('error', e);
errorCallback(e);
deferred.reject(e);
}
}
return deferred.promise;
}
program
.version('0.0.1')
.option('-u, --url [http://127.0.0.1:8888/uploadUserHead]', 'set upload url', 'http://127.0.0.1:8888/uploadUserHead')
.option('-f, --file <required>', 'the filepath to upload')
.option('-p, --param [file]', 'upload file field, default: file', 'file')
.option('-d, --data [{}]', 'data must be json format', (v)=>eval('v='+v), {})
.parse(process.argv);
let {url, file, param, data} = program;
if (!file) {
console.log('error: the filepath to upload must be set');
return;
}
var options = {
url,
method: 'POST',
verbose: true,
param, //文件上传字段名
file, //文件位置
fields:data,
};
upload(options).then(function(data) {
console.log(data);
console.log('end');
}, function() {
console.log('error', arguments);
}, function( progress ) {
console.log('upload progress', progress);
});