-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.js
86 lines (69 loc) · 2.35 KB
/
utils.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
import fetch from 'node-fetch'
import AbortController from 'abort-controller'
import { XMLParser, XMLBuilder, XMLValidator } from 'fast-xml-parser'
const RM_PI_REGEX = /<\?(?!xml ).*?\?>[\r\n]*/g
const defaultProps = {
method: 'GET',
headers: {}
}
const defaultRetryOptions = {
attemptsLimit: 5,
interval: 1000
}
async function request(url, opts, timeout = 30000) {
const controller = new AbortController()
const { signal } = controller
const options = { ...defaultProps, signal, ...opts }
const requestTimeout = setTimeout(() => controller.abort(), timeout)
try {
return await fetch(url, options)
} finally {
clearTimeout(requestTimeout)
}
}
async function requestUntilSuccess(url, options, timeout = 30000, retryOptions = {}) {
const retryOpts = { ...defaultRetryOptions, ...retryOptions }
return execUntilSuccess(request, null, [url, options, timeout], retryOpts)()
}
async function execUntilSuccess(fn, thisCtx, args, { attemptsLimit, interval }) {
let attempts = 0
const exec = async () => {
try {
return await fn.apply(thisCtx, args)
} catch (err) {
if (++attempts > attemptsLimit) throw err
await new Promise((resolve) => setTimeout(resolve, interval))
return exec()
}
}
return exec()
}
const xml2jsonOptions = {
attributeNamePrefix: '@',
ignoreAttributes: false
}
const json2xmlOptions = {
...xml2jsonOptions,
suppressEmptyNode: true,
tagValueProcessor: (tagName, tagValue) => escapeValue(tagValue),
attributeValueProcessor: (name, value) => escapeAttrValue(value)
}
const xml2obj = (data, options = {}) => new XMLParser({ ...xml2jsonOptions, ...options }).parse(data)
const obj2xml = (data, options = {}) => new XMLBuilder({ ...json2xmlOptions, ...options }).build(data)
const validate = XMLValidator.validate
const escapeValue = (value) =>
typeof value === 'string'
? value.replace(
/&(?!(?:apos|quot|[gl]t|amp);|#)|>|</g,
(char) => ({ '&': '&', '>': '>', '<': '<' }[char])
)
: value
const escapeAttrValue = (value) =>
typeof value === 'string'
? value.replace(
/&(?!(?:apos|quot|[gl]t|amp);|#)|>|<|"|'/g,
(char) => ({ '&': '&', '>': '>', '<': '<', '"': '"', "'": ''' }[char])
)
: value
const removeProcessingInstructions = (xmlBuf) => Buffer.from(xmlBuf.toString().replace(RM_PI_REGEX, ''))
export { request, requestUntilSuccess, execUntilSuccess, xml2obj, obj2xml }