@yvhitxcel/opencode-remote 0.15.0
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/README.md +82 -0
- package/bin/opencode-remote.js +70 -0
- package/bin/opencode-weixin.js +10 -0
- package/dist/AGENTS.md +20 -0
- package/dist/MEMORY.md +21 -0
- package/dist/bot-runner.js +180 -0
- package/dist/cli.js +256 -0
- package/dist/core/approval.js +95 -0
- package/dist/core/auth.js +119 -0
- package/dist/core/config.js +61 -0
- package/dist/core/notifications.js +134 -0
- package/dist/core/qiniu.js +267 -0
- package/dist/core/registry.js +86 -0
- package/dist/core/router.js +344 -0
- package/dist/core/session.js +403 -0
- package/dist/core/setup.js +418 -0
- package/dist/core/types.js +16 -0
- package/dist/feishu/adapter.js +72 -0
- package/dist/feishu/bot.js +168 -0
- package/dist/feishu/commands.js +601 -0
- package/dist/feishu/handler.js +380 -0
- package/dist/index.js +60 -0
- package/dist/opencode/client.js +823 -0
- package/dist/package-lock.json +762 -0
- package/dist/patch_spawn.js +28 -0
- package/dist/plugins/agents/acp/acp-adapter.js +42 -0
- package/dist/plugins/agents/claude-code/index.js +69 -0
- package/dist/plugins/agents/codex/index.js +44 -0
- package/dist/plugins/agents/copilot/index.js +44 -0
- package/dist/plugins/agents/opencode/index.js +66 -0
- package/dist/telegram/bot.js +288 -0
- package/dist/utils/message-split.js +38 -0
- package/dist/web/code-viewer.js +266 -0
- package/dist/weixin/adapter.js +135 -0
- package/dist/weixin/api.js +179 -0
- package/dist/weixin/bot.js +183 -0
- package/dist/weixin/commands.js +758 -0
- package/dist/weixin/handler.js +577 -0
- package/dist/weixin/node_modules/encodeurl/LICENSE +22 -0
- package/dist/weixin/node_modules/encodeurl/README.md +109 -0
- package/dist/weixin/node_modules/encodeurl/index.js +60 -0
- package/dist/weixin/node_modules/encodeurl/package.json +40 -0
- package/dist/weixin/node_modules/qiniu/.claude/settings.local.json +7 -0
- package/dist/weixin/node_modules/qiniu/.github/workflows/ci-test.yml +36 -0
- package/dist/weixin/node_modules/qiniu/.github/workflows/npm-publish.yml +20 -0
- package/dist/weixin/node_modules/qiniu/.github/workflows/version-check.yml +19 -0
- package/dist/weixin/node_modules/qiniu/.idea/MarsCodeWorkspaceAppSettings.xml +7 -0
- package/dist/weixin/node_modules/qiniu/.idea/codeStyles/Project.xml +44 -0
- package/dist/weixin/node_modules/qiniu/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/dist/weixin/node_modules/qiniu/.idea/git_toolbox_blame.xml +6 -0
- package/dist/weixin/node_modules/qiniu/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/dist/weixin/node_modules/qiniu/.idea/jsLibraryMappings.xml +6 -0
- package/dist/weixin/node_modules/qiniu/.idea/modules.xml +8 -0
- package/dist/weixin/node_modules/qiniu/.idea/nodejs-sdk.iml +12 -0
- package/dist/weixin/node_modules/qiniu/.idea/vcs.xml +6 -0
- package/dist/weixin/node_modules/qiniu/CHANGELOG.md +292 -0
- package/dist/weixin/node_modules/qiniu/README.md +56 -0
- package/dist/weixin/node_modules/qiniu/StorageResponseInterface.d.ts +239 -0
- package/dist/weixin/node_modules/qiniu/codecov.yml +28 -0
- package/dist/weixin/node_modules/qiniu/index.d.ts +1995 -0
- package/dist/weixin/node_modules/qiniu/index.js +32 -0
- package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/HISTORY.md +14 -0
- package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/LICENSE +22 -0
- package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/README.md +128 -0
- package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/index.js +60 -0
- package/dist/weixin/node_modules/qiniu/node_modules/encodeurl/package.json +40 -0
- package/dist/weixin/node_modules/qiniu/package.json +80 -0
- package/dist/weixin/node_modules/qiniu/qiniu/auth/digest.js +13 -0
- package/dist/weixin/node_modules/qiniu/qiniu/cdn.js +149 -0
- package/dist/weixin/node_modules/qiniu/qiniu/conf.js +254 -0
- package/dist/weixin/node_modules/qiniu/qiniu/fop.js +112 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/client.js +253 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpoint.js +66 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpointsProvider.js +27 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/endpointsRetryPolicy.js +76 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/base.js +31 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/index.js +9 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/qiniuAuth.js +53 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/retryDomains.js +101 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/middleware/ua.js +36 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/region.js +349 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/regionsProvider.js +788 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/regionsRetryPolicy.js +242 -0
- package/dist/weixin/node_modules/qiniu/qiniu/httpc/responseWrapper.js +40 -0
- package/dist/weixin/node_modules/qiniu/qiniu/retry/index.js +4 -0
- package/dist/weixin/node_modules/qiniu/qiniu/retry/retrier.js +99 -0
- package/dist/weixin/node_modules/qiniu/qiniu/retry/retryPolicy.js +55 -0
- package/dist/weixin/node_modules/qiniu/qiniu/rpc.js +237 -0
- package/dist/weixin/node_modules/qiniu/qiniu/rtc/app.js +123 -0
- package/dist/weixin/node_modules/qiniu/qiniu/rtc/credentials.js +57 -0
- package/dist/weixin/node_modules/qiniu/qiniu/rtc/room.js +118 -0
- package/dist/weixin/node_modules/qiniu/qiniu/rtc/util.js +16 -0
- package/dist/weixin/node_modules/qiniu/qiniu/sms/message.js +58 -0
- package/dist/weixin/node_modules/qiniu/qiniu/storage/form.js +442 -0
- package/dist/weixin/node_modules/qiniu/qiniu/storage/internal.js +214 -0
- package/dist/weixin/node_modules/qiniu/qiniu/storage/resume.js +1272 -0
- package/dist/weixin/node_modules/qiniu/qiniu/storage/rs.js +1764 -0
- package/dist/weixin/node_modules/qiniu/qiniu/util.js +382 -0
- package/dist/weixin/node_modules/qiniu/qiniu/zone.js +230 -0
- package/dist/weixin/node_modules/qiniu/tsconfig.json +112 -0
- package/dist/weixin/types.js +25 -0
- package/package.json +56 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const Readable = require('stream').Readable;
|
|
4
|
+
|
|
5
|
+
const getCrc32 = require('crc32');
|
|
6
|
+
const mime = require('mime');
|
|
7
|
+
const FormStream = require('formstream');
|
|
8
|
+
|
|
9
|
+
const conf = require('../conf');
|
|
10
|
+
const util = require('../util');
|
|
11
|
+
const rpc = require('../rpc');
|
|
12
|
+
const { SERVICE_NAME } = require('../httpc/region');
|
|
13
|
+
const { ResponseWrapper } = require('../httpc/responseWrapper');
|
|
14
|
+
const { EndpointsRetryPolicy } = require('../httpc/endpointsRetryPolicy');
|
|
15
|
+
const { RegionsRetryPolicy } = require('../httpc/regionsRetryPolicy');
|
|
16
|
+
const { Retrier } = require('../retry');
|
|
17
|
+
const {
|
|
18
|
+
AccUnavailableRetryPolicy,
|
|
19
|
+
handleReqCallback
|
|
20
|
+
} = require('./internal');
|
|
21
|
+
|
|
22
|
+
exports.FormUploader = FormUploader;
|
|
23
|
+
exports.PutExtra = PutExtra;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @class
|
|
27
|
+
* @param {conf.Config} [config]
|
|
28
|
+
* @constructor
|
|
29
|
+
*/
|
|
30
|
+
function FormUploader (config) {
|
|
31
|
+
this.config = config || new conf.Config();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @private
|
|
36
|
+
* @param {Object} options
|
|
37
|
+
* @param {string} options.accessKey
|
|
38
|
+
* @param {string} options.bucketName
|
|
39
|
+
* @param {boolean} [options.retryable]
|
|
40
|
+
* @returns {Promise<Retrier>}
|
|
41
|
+
*/
|
|
42
|
+
function _getRegionsRetrier (options) {
|
|
43
|
+
const {
|
|
44
|
+
bucketName,
|
|
45
|
+
accessKey,
|
|
46
|
+
retryable = true
|
|
47
|
+
} = options;
|
|
48
|
+
|
|
49
|
+
return this.config.getRegionsProvider({
|
|
50
|
+
bucketName,
|
|
51
|
+
accessKey
|
|
52
|
+
})
|
|
53
|
+
.then(regionsProvider => {
|
|
54
|
+
let retryPolicies;
|
|
55
|
+
if (this.config.accelerateUploading) {
|
|
56
|
+
retryPolicies = [
|
|
57
|
+
new AccUnavailableRetryPolicy(),
|
|
58
|
+
new EndpointsRetryPolicy({
|
|
59
|
+
skipInitContext: true
|
|
60
|
+
}),
|
|
61
|
+
new RegionsRetryPolicy({
|
|
62
|
+
regionsProvider,
|
|
63
|
+
serviceNames: [SERVICE_NAME.UP_ACC, SERVICE_NAME.UP]
|
|
64
|
+
})
|
|
65
|
+
];
|
|
66
|
+
} else {
|
|
67
|
+
retryPolicies = [
|
|
68
|
+
new EndpointsRetryPolicy({
|
|
69
|
+
skipInitContext: true
|
|
70
|
+
}),
|
|
71
|
+
new RegionsRetryPolicy({
|
|
72
|
+
regionsProvider,
|
|
73
|
+
serviceNames: [SERVICE_NAME.UP]
|
|
74
|
+
})
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return new Retrier({
|
|
79
|
+
retryPolicies,
|
|
80
|
+
onBeforeRetry: (context, policy) => {
|
|
81
|
+
if (context.error) {
|
|
82
|
+
return retryable;
|
|
83
|
+
}
|
|
84
|
+
if (policy instanceof AccUnavailableRetryPolicy) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return retryable && context.result && context.result.needRetry();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 上传可选参数
|
|
95
|
+
* @class
|
|
96
|
+
* @constructor
|
|
97
|
+
* @param {string} [fname] 请求体中的文件的名称
|
|
98
|
+
* @param {Object} [params] 额外参数设置,参数名称必须以x:开头
|
|
99
|
+
* @param {string} [mimeType] 指定文件的mimeType
|
|
100
|
+
* @param {string} [crc32] 指定文件的crc32值
|
|
101
|
+
* @param {number | boolean} [checkCrc] 指定是否检测文件的crc32值
|
|
102
|
+
* @param {Object} [metadata] 元数据设置,参数名称必须以 x-qn-meta-${name}: 开头
|
|
103
|
+
*/
|
|
104
|
+
function PutExtra (
|
|
105
|
+
fname,
|
|
106
|
+
params,
|
|
107
|
+
mimeType,
|
|
108
|
+
crc32,
|
|
109
|
+
checkCrc,
|
|
110
|
+
metadata
|
|
111
|
+
) {
|
|
112
|
+
this.fname = fname || '';
|
|
113
|
+
this.params = params || {};
|
|
114
|
+
this.mimeType = mimeType || null;
|
|
115
|
+
this.crc32 = crc32 || null;
|
|
116
|
+
this.checkCrc = checkCrc || true;
|
|
117
|
+
this.metadata = metadata || {};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @callback reqCallback
|
|
122
|
+
*
|
|
123
|
+
* @param { Error } err
|
|
124
|
+
* @param { Object } ret
|
|
125
|
+
* @param { http.IncomingMessage } info
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {string} uploadToken
|
|
130
|
+
* @param {string | null} key
|
|
131
|
+
* @param {stream.Readable} fsStream
|
|
132
|
+
* @param {PutExtra | null} putExtra
|
|
133
|
+
* @param {reqCallback} callbackFunc
|
|
134
|
+
* @returns {Promise<ResponseWrapper>}
|
|
135
|
+
*/
|
|
136
|
+
FormUploader.prototype.putStream = function (
|
|
137
|
+
uploadToken,
|
|
138
|
+
key,
|
|
139
|
+
fsStream,
|
|
140
|
+
putExtra,
|
|
141
|
+
callbackFunc
|
|
142
|
+
) {
|
|
143
|
+
const preferredScheme = this.config.useHttpsDomain ? 'https' : 'http';
|
|
144
|
+
|
|
145
|
+
// PutExtra
|
|
146
|
+
putExtra = getDefaultPutExtra(
|
|
147
|
+
putExtra,
|
|
148
|
+
{
|
|
149
|
+
key
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Why need retrier even if retryable is false?
|
|
154
|
+
// Because the retrier is used to get the endpoints,
|
|
155
|
+
// which will be initialed by region policy.
|
|
156
|
+
const result = _getRegionsRetrier.call(this, {
|
|
157
|
+
bucketName: util.getBucketFromUptoken(uploadToken),
|
|
158
|
+
accessKey: util.getAKFromUptoken(uploadToken),
|
|
159
|
+
retryable: false
|
|
160
|
+
})
|
|
161
|
+
.then(retrier => Promise.all([
|
|
162
|
+
retrier,
|
|
163
|
+
retrier.initContext()
|
|
164
|
+
]))
|
|
165
|
+
.then(([retrier, context]) => retrier.retry({
|
|
166
|
+
func: context => putReq(
|
|
167
|
+
context.endpoint.getValue({ scheme: preferredScheme }),
|
|
168
|
+
uploadToken,
|
|
169
|
+
key,
|
|
170
|
+
fsStream,
|
|
171
|
+
putExtra
|
|
172
|
+
),
|
|
173
|
+
context
|
|
174
|
+
}));
|
|
175
|
+
handleReqCallback(result, callbackFunc);
|
|
176
|
+
return result;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @param {string} upDomain
|
|
181
|
+
* @param {string} uploadToken
|
|
182
|
+
* @param {string} key
|
|
183
|
+
* @param {Readable} fsStream
|
|
184
|
+
* @param {PutExtra} putExtra
|
|
185
|
+
* @returns {Promise<any>}
|
|
186
|
+
*/
|
|
187
|
+
function putReq (
|
|
188
|
+
upDomain,
|
|
189
|
+
uploadToken,
|
|
190
|
+
key,
|
|
191
|
+
fsStream,
|
|
192
|
+
putExtra
|
|
193
|
+
) {
|
|
194
|
+
const postForm = createMultipartForm(
|
|
195
|
+
uploadToken,
|
|
196
|
+
key,
|
|
197
|
+
fsStream,
|
|
198
|
+
putExtra
|
|
199
|
+
);
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
rpc.postMultipart(
|
|
202
|
+
upDomain,
|
|
203
|
+
postForm,
|
|
204
|
+
function (err, data, resp) {
|
|
205
|
+
if (err) {
|
|
206
|
+
err.resp = resp;
|
|
207
|
+
reject(err);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
resolve(new ResponseWrapper({
|
|
211
|
+
data,
|
|
212
|
+
resp
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 上传字节
|
|
221
|
+
* @param {string} uploadToken
|
|
222
|
+
* @param {string | null} key
|
|
223
|
+
* @param {any} body
|
|
224
|
+
* @param {PutExtra | null} putExtra
|
|
225
|
+
* @param {reqCallback} [callbackFunc]
|
|
226
|
+
* @returns {Promise<UploadResult>}
|
|
227
|
+
*/
|
|
228
|
+
FormUploader.prototype.put = function (
|
|
229
|
+
uploadToken,
|
|
230
|
+
key,
|
|
231
|
+
body,
|
|
232
|
+
putExtra,
|
|
233
|
+
callbackFunc
|
|
234
|
+
) {
|
|
235
|
+
const preferredScheme = this.config.useHttpsDomain ? 'https' : 'http';
|
|
236
|
+
|
|
237
|
+
// initial PutExtra
|
|
238
|
+
putExtra = getDefaultPutExtra(
|
|
239
|
+
putExtra,
|
|
240
|
+
{
|
|
241
|
+
key
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// initial retrier and try upload
|
|
246
|
+
const result = _getRegionsRetrier.call(this, {
|
|
247
|
+
bucketName: util.getBucketFromUptoken(uploadToken),
|
|
248
|
+
accessKey: util.getAKFromUptoken(uploadToken)
|
|
249
|
+
})
|
|
250
|
+
.then(retrier => Promise.all([
|
|
251
|
+
retrier,
|
|
252
|
+
retrier.initContext()
|
|
253
|
+
]))
|
|
254
|
+
.then(([retrier, context]) => retrier.retry({
|
|
255
|
+
func: context => {
|
|
256
|
+
const fsStream = new Readable();
|
|
257
|
+
fsStream.push(body);
|
|
258
|
+
fsStream.push(null);
|
|
259
|
+
|
|
260
|
+
return putReq(
|
|
261
|
+
context.endpoint.getValue({ scheme: preferredScheme }),
|
|
262
|
+
uploadToken,
|
|
263
|
+
key,
|
|
264
|
+
fsStream,
|
|
265
|
+
putExtra
|
|
266
|
+
);
|
|
267
|
+
},
|
|
268
|
+
context
|
|
269
|
+
}));
|
|
270
|
+
handleReqCallback(result, callbackFunc);
|
|
271
|
+
return result;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* @param {string} uploadToken
|
|
276
|
+
* @param {any} body
|
|
277
|
+
* @param {PutExtra | null} putExtra
|
|
278
|
+
* @param {reqCallback} callbackFunc
|
|
279
|
+
* @returns {Promise<UploadResult>}
|
|
280
|
+
*/
|
|
281
|
+
FormUploader.prototype.putWithoutKey = function (
|
|
282
|
+
uploadToken,
|
|
283
|
+
body,
|
|
284
|
+
putExtra,
|
|
285
|
+
callbackFunc
|
|
286
|
+
) {
|
|
287
|
+
return this.put(uploadToken, null, body, putExtra, callbackFunc);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @param {string} uploadToken
|
|
292
|
+
* @param {string | null} key
|
|
293
|
+
* @param {stream.Readable} fsStream
|
|
294
|
+
* @param {PutExtra | null} putExtra
|
|
295
|
+
* @returns {FormStream}
|
|
296
|
+
*/
|
|
297
|
+
function createMultipartForm (uploadToken, key, fsStream, putExtra) {
|
|
298
|
+
const postForm = new FormStream();
|
|
299
|
+
postForm.field('token', uploadToken);
|
|
300
|
+
if (key != null) {
|
|
301
|
+
postForm.field('key', key);
|
|
302
|
+
}
|
|
303
|
+
// fix the bug of formstream
|
|
304
|
+
// https://html.spec.whatwg.org/#multipart-form-data
|
|
305
|
+
const escapeFname = putExtra.fname.replace(/"/g, '%22')
|
|
306
|
+
.replace(/\r/g, '%0D')
|
|
307
|
+
.replace(/\n/g, '%0A');
|
|
308
|
+
postForm.stream(
|
|
309
|
+
'file',
|
|
310
|
+
fsStream,
|
|
311
|
+
escapeFname,
|
|
312
|
+
putExtra.mimeType
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// putExtra params
|
|
316
|
+
for (const k in putExtra.params) {
|
|
317
|
+
if (k.startsWith('x:')) {
|
|
318
|
+
postForm.field(k, putExtra.params[k].toString());
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// putExtra metadata
|
|
323
|
+
for (const metadataKey in putExtra.metadata) {
|
|
324
|
+
if (metadataKey.startsWith('x-qn-meta-')) {
|
|
325
|
+
postForm.field(metadataKey, putExtra.metadata[metadataKey].toString());
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
let fileBody = [];
|
|
330
|
+
fsStream.on('data', function (data) {
|
|
331
|
+
fileBody.push(data);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
fsStream.on('end', function () {
|
|
335
|
+
if (putExtra.checkCrc) {
|
|
336
|
+
if (putExtra.crc32 == null) {
|
|
337
|
+
fileBody = Buffer.concat(fileBody);
|
|
338
|
+
const bodyCrc32 = parseInt('0x' + getCrc32(fileBody));
|
|
339
|
+
postForm.field('crc32', bodyCrc32.toString());
|
|
340
|
+
} else {
|
|
341
|
+
postForm.field('crc32', putExtra.crc32);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
return postForm;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** 上传本地文件
|
|
350
|
+
* @param {string} uploadToken 上传凭证
|
|
351
|
+
* @param {string | null} key 目标文件名
|
|
352
|
+
* @param {string} localFile 本地文件路径
|
|
353
|
+
* @param {PutExtra | null} putExtra 额外选项
|
|
354
|
+
* @param {reqCallback} [callbackFunc] 回调函数
|
|
355
|
+
* @returns {Promise<UploadResult>}
|
|
356
|
+
*/
|
|
357
|
+
FormUploader.prototype.putFile = function (
|
|
358
|
+
uploadToken,
|
|
359
|
+
key,
|
|
360
|
+
localFile,
|
|
361
|
+
putExtra,
|
|
362
|
+
callbackFunc
|
|
363
|
+
) {
|
|
364
|
+
const preferredScheme = this.config.useHttpsDomain ? 'https' : 'http';
|
|
365
|
+
|
|
366
|
+
// initial PutExtra
|
|
367
|
+
putExtra = putExtra || new PutExtra();
|
|
368
|
+
if (!putExtra.mimeType) {
|
|
369
|
+
putExtra.mimeType = mime.getType(localFile);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!putExtra.fname) {
|
|
373
|
+
putExtra.fname = path.basename(localFile);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
putExtra = getDefaultPutExtra(
|
|
377
|
+
putExtra,
|
|
378
|
+
{
|
|
379
|
+
key
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// initial retrier and try upload
|
|
384
|
+
const result = _getRegionsRetrier.call(this, {
|
|
385
|
+
bucketName: util.getBucketFromUptoken(uploadToken),
|
|
386
|
+
accessKey: util.getAKFromUptoken(uploadToken)
|
|
387
|
+
})
|
|
388
|
+
.then(retrier => Promise.all([
|
|
389
|
+
retrier,
|
|
390
|
+
retrier.initContext()
|
|
391
|
+
]))
|
|
392
|
+
.then(([retrier, context]) => retrier.retry({
|
|
393
|
+
func: context => {
|
|
394
|
+
const fsStream = fs.createReadStream(localFile);
|
|
395
|
+
return putReq(
|
|
396
|
+
context.endpoint.getValue({ scheme: preferredScheme }),
|
|
397
|
+
uploadToken,
|
|
398
|
+
key,
|
|
399
|
+
fsStream,
|
|
400
|
+
putExtra
|
|
401
|
+
);
|
|
402
|
+
},
|
|
403
|
+
context
|
|
404
|
+
}));
|
|
405
|
+
handleReqCallback(result, callbackFunc);
|
|
406
|
+
return result;
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
/** 上传本地文件
|
|
410
|
+
* @param {string} uploadToken 上传凭证
|
|
411
|
+
* @param {string} localFile 本地文件路径
|
|
412
|
+
* @param {PutExtra | null} putExtra 额外选项
|
|
413
|
+
* @param callbackFunc 回调函数
|
|
414
|
+
* @returns {Promise<UploadResult>}
|
|
415
|
+
*/
|
|
416
|
+
FormUploader.prototype.putFileWithoutKey = function (
|
|
417
|
+
uploadToken,
|
|
418
|
+
localFile,
|
|
419
|
+
putExtra,
|
|
420
|
+
callbackFunc
|
|
421
|
+
) {
|
|
422
|
+
return this.putFile(uploadToken, null, localFile, putExtra, callbackFunc);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* @param {PutExtra} putExtra
|
|
427
|
+
* @param {Object} options
|
|
428
|
+
* @param {string} options.key
|
|
429
|
+
* @returns {PutExtra}
|
|
430
|
+
*/
|
|
431
|
+
function getDefaultPutExtra (putExtra, options) {
|
|
432
|
+
putExtra = putExtra || new PutExtra();
|
|
433
|
+
if (!putExtra.mimeType) {
|
|
434
|
+
putExtra.mimeType = 'application/octet-stream';
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!putExtra.fname) {
|
|
438
|
+
putExtra.fname = options.key || 'fname';
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return putExtra;
|
|
442
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// internal
|
|
2
|
+
// DO NOT use this file, unless you know what you're doing.
|
|
3
|
+
// Because its API may make broken change for internal usage.
|
|
4
|
+
|
|
5
|
+
const { RetryPolicy } = require('../retry');
|
|
6
|
+
|
|
7
|
+
// --- split to files --- //
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {RetryPolicyContext} TokenExpiredRetryPolicyContext
|
|
10
|
+
* @property {string} resumeRecordFilePath
|
|
11
|
+
* @property {'v1' | 'v2' | string} uploadApiVersion
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @class
|
|
16
|
+
* @extends RetryPolicy
|
|
17
|
+
* @param {Object} options
|
|
18
|
+
* @param {string} options.uploadApiVersion
|
|
19
|
+
* @param {function} options.recordDeleteHandler
|
|
20
|
+
* @param {function} options.recordExistsHandler
|
|
21
|
+
* @param {number} [options.maxRetryTimes]
|
|
22
|
+
* @constructor
|
|
23
|
+
*/
|
|
24
|
+
function TokenExpiredRetryPolicy (options) {
|
|
25
|
+
this.id = Symbol(this.constructor.name);
|
|
26
|
+
this.uploadApiVersion = options.uploadApiVersion;
|
|
27
|
+
this.recordDeleteHandler = options.recordDeleteHandler;
|
|
28
|
+
this.recordExistsHandler = options.recordExistsHandler;
|
|
29
|
+
this.maxRetryTimes = options.maxRetryTimes || 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
TokenExpiredRetryPolicy.prototype = Object.create(RetryPolicy.prototype);
|
|
33
|
+
TokenExpiredRetryPolicy.prototype.constructor = TokenExpiredRetryPolicy;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {Object} context
|
|
37
|
+
* @returns {Promise<void>}
|
|
38
|
+
*/
|
|
39
|
+
TokenExpiredRetryPolicy.prototype.initContext = function (context) {
|
|
40
|
+
context[this.id] = {
|
|
41
|
+
retriedTimes: 0,
|
|
42
|
+
uploadApiVersion: this.uploadApiVersion
|
|
43
|
+
};
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {Object} context
|
|
49
|
+
* @returns {boolean}
|
|
50
|
+
*/
|
|
51
|
+
TokenExpiredRetryPolicy.prototype.shouldRetry = function (context) {
|
|
52
|
+
const {
|
|
53
|
+
retriedTimes,
|
|
54
|
+
uploadApiVersion
|
|
55
|
+
} = context[this.id];
|
|
56
|
+
|
|
57
|
+
if (
|
|
58
|
+
retriedTimes >= this.maxRetryTimes ||
|
|
59
|
+
!this.recordExistsHandler()
|
|
60
|
+
) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!context.result) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (uploadApiVersion === 'v1' &&
|
|
69
|
+
context.result.resp.statusCode === 701
|
|
70
|
+
) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (uploadApiVersion === 'v2' &&
|
|
75
|
+
context.result.resp.statusCode === 612
|
|
76
|
+
) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return false;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {Object} context
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
TokenExpiredRetryPolicy.prototype.prepareRetry = function (context) {
|
|
88
|
+
context[this.id].retriedTimes += 1;
|
|
89
|
+
return new Promise(resolve => {
|
|
90
|
+
if (!this.recordExistsHandler()) {
|
|
91
|
+
resolve();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.recordDeleteHandler();
|
|
95
|
+
resolve();
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
exports.TokenExpiredRetryPolicy = TokenExpiredRetryPolicy;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @class
|
|
103
|
+
* @extends RetryPolicy
|
|
104
|
+
* @constructor
|
|
105
|
+
*/
|
|
106
|
+
function AccUnavailableRetryPolicy () {
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
AccUnavailableRetryPolicy.prototype = Object.create(RetryPolicy.prototype);
|
|
110
|
+
AccUnavailableRetryPolicy.prototype.constructor = AccUnavailableRetryPolicy;
|
|
111
|
+
|
|
112
|
+
AccUnavailableRetryPolicy.prototype.initContext = function (context) {
|
|
113
|
+
return Promise.resolve();
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
AccUnavailableRetryPolicy.prototype.isAccNotAvailable = function (context) {
|
|
117
|
+
try {
|
|
118
|
+
return context.result.resp.statusCode === 400 &&
|
|
119
|
+
context.result.resp.data.error.includes('transfer acceleration is not configured on this bucket');
|
|
120
|
+
} catch (_err) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
AccUnavailableRetryPolicy.prototype.shouldRetry = function (context) {
|
|
126
|
+
if (!context.result) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (!context.alternativeServiceNames.length) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const [nextServiceName] = context.alternativeServiceNames;
|
|
133
|
+
if (
|
|
134
|
+
!context.region.services[nextServiceName] ||
|
|
135
|
+
!context.region.services[nextServiceName].length
|
|
136
|
+
) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return this.isAccNotAvailable(context);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
AccUnavailableRetryPolicy.prototype.prepareRetry = function (context) {
|
|
143
|
+
if (!context.alternativeServiceNames.length) {
|
|
144
|
+
return Promise.reject(new Error(
|
|
145
|
+
'No alternative service available.'
|
|
146
|
+
));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
context.serviceName = context.alternativeServiceNames.shift();
|
|
150
|
+
[context.endpoint, ...context.alternativeEndpoints] = context.region.services[context.serviceName];
|
|
151
|
+
if (!context.endpoint) {
|
|
152
|
+
return Promise.reject(new Error(
|
|
153
|
+
'No alternative endpoint available.'
|
|
154
|
+
));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return Promise.resolve();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
exports.AccUnavailableRetryPolicy = AccUnavailableRetryPolicy;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {Error} err
|
|
164
|
+
* @param {string} msg
|
|
165
|
+
*/
|
|
166
|
+
function getNoNeedRetryError (err, msg) {
|
|
167
|
+
err.message = msg + '\n' + err.message;
|
|
168
|
+
err.noNeedRetry = true;
|
|
169
|
+
return err;
|
|
170
|
+
}
|
|
171
|
+
exports.getNoNeedRetryError = getNoNeedRetryError;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param fn
|
|
175
|
+
* @returns {(function(...[*]): (*|undefined))|*}
|
|
176
|
+
*/
|
|
177
|
+
function wrapTryCallback (fn) {
|
|
178
|
+
if (typeof fn !== 'function') {
|
|
179
|
+
return () => {};
|
|
180
|
+
}
|
|
181
|
+
return (...args) => {
|
|
182
|
+
try {
|
|
183
|
+
return fn(...args);
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.warn(
|
|
186
|
+
'WARNING:\n' +
|
|
187
|
+
'qiniu SDK will migrate API to Promise style gradually.\n' +
|
|
188
|
+
'The callback style will not be removed for now,\n' +
|
|
189
|
+
'but you should catch your error in your callback function itself'
|
|
190
|
+
);
|
|
191
|
+
console.error(err);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Compatible with callback style
|
|
198
|
+
* Could be removed when make break changes.
|
|
199
|
+
*/
|
|
200
|
+
function handleReqCallback (responseWrapperPromise, callbackFunc) {
|
|
201
|
+
if (typeof callbackFunc !== 'function') {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const wrappedCallback = wrapTryCallback(callbackFunc);
|
|
205
|
+
responseWrapperPromise
|
|
206
|
+
.then(({ data, resp }) => {
|
|
207
|
+
wrappedCallback(null, data, resp);
|
|
208
|
+
})
|
|
209
|
+
.catch(err => {
|
|
210
|
+
wrappedCallback(err, null, err.resp);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
exports.handleReqCallback = handleReqCallback;
|