@things-factory/integration-base 6.0.68 → 6.0.69
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/dist-server/engine/connector/http-connector.js +1 -1
- package/dist-server/engine/connector/http-connector.js.map +1 -1
- package/dist-server/engine/task/headless-post.js +123 -0
- package/dist-server/engine/task/headless-post.js.map +1 -0
- package/dist-server/engine/task/http-post.js +3 -6
- package/dist-server/engine/task/http-post.js.map +1 -1
- package/dist-server/engine/task/index.js +1 -0
- package/dist-server/engine/task/index.js.map +1 -1
- package/dist-server/engine/task/utils/headless-pool-for-scenario.js +65 -0
- package/dist-server/engine/task/utils/headless-pool-for-scenario.js.map +1 -0
- package/dist-server/engine/task/utils/headless-pool-for-task.js +65 -0
- package/dist-server/engine/task/utils/headless-pool-for-task.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/server/engine/connector/http-connector.ts +1 -1
- package/server/engine/task/headless-post.ts +141 -0
- package/server/engine/task/http-post.ts +4 -8
- package/server/engine/task/index.ts +1 -0
- package/server/engine/task/utils/headless-pool-for-scenario.ts +71 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/integration-base",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.69",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/cron": "^2.0.1"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "d0198bba193b275f29fffd8c3963f556db4dda92"
|
|
49
49
|
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import https from 'https'
|
|
2
|
+
import { URL } from 'url'
|
|
3
|
+
|
|
4
|
+
import { access } from '@things-factory/utils'
|
|
5
|
+
import { TaskRegistry } from '../task-registry'
|
|
6
|
+
import { ConnectionManager } from '../connection-manager'
|
|
7
|
+
|
|
8
|
+
import { getHeadlessPool } from './utils/headless-pool-for-scenario'
|
|
9
|
+
|
|
10
|
+
async function HeadlessPost(step, { logger, data, domain }) {
|
|
11
|
+
var { connection: connectionName, params: stepOptions } = step
|
|
12
|
+
var { headers: requestHeaders, contentType, path, accessor } = stepOptions || {}
|
|
13
|
+
|
|
14
|
+
var connection = ConnectionManager.getConnectionInstanceByName(domain, connectionName)
|
|
15
|
+
|
|
16
|
+
if (!connection) {
|
|
17
|
+
throw new Error(`connection '${connectionName}' is not established.`)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var { endpoint, params: connectionParams, authHeaders = {} } = connection
|
|
21
|
+
|
|
22
|
+
var headers = {
|
|
23
|
+
...authHeaders,
|
|
24
|
+
...requestHeaders
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var body = access(accessor, data)
|
|
28
|
+
if (contentType && body) {
|
|
29
|
+
headers['content-type'] = contentType
|
|
30
|
+
switch (contentType) {
|
|
31
|
+
case 'text/plain':
|
|
32
|
+
body = JSON.stringify(body)
|
|
33
|
+
break
|
|
34
|
+
case 'application/json':
|
|
35
|
+
body = JSON.stringify(body)
|
|
36
|
+
break
|
|
37
|
+
case 'application/x-www-form-urlencoded':
|
|
38
|
+
const searchParams = new URLSearchParams()
|
|
39
|
+
for (const prop in body) {
|
|
40
|
+
searchParams.set(prop, body[prop])
|
|
41
|
+
}
|
|
42
|
+
body = searchParams
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var options: any = {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers,
|
|
50
|
+
body
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var { rejectUnauthorized } = connectionParams
|
|
54
|
+
|
|
55
|
+
if (!rejectUnauthorized) {
|
|
56
|
+
const httpsAgent = new https.Agent({
|
|
57
|
+
rejectUnauthorized
|
|
58
|
+
})
|
|
59
|
+
options.agent = httpsAgent
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const browser = (await getHeadlessPool().acquire()) as any
|
|
63
|
+
const page = await browser.newPage()
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
page.on('console', msg => {
|
|
67
|
+
console.log(`[browser ${msg.type()}] ${msg.text()}`)
|
|
68
|
+
for (let i = 0; i < msg.args().length; ++i) console.log(`${i}: ${msg.args()[i]}`)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
await page.goto(endpoint, { waitUntil: 'networkidle2' })
|
|
72
|
+
|
|
73
|
+
const response = await page.evaluate(
|
|
74
|
+
async (urlString, options) => {
|
|
75
|
+
const response = await fetch(urlString, options)
|
|
76
|
+
|
|
77
|
+
if (response.ok && response.headers.get('content-type').includes('application/json')) {
|
|
78
|
+
return await response.json()
|
|
79
|
+
} else {
|
|
80
|
+
return await response.text()
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
new URL(path, endpoint),
|
|
84
|
+
options
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
data: response
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error(e)
|
|
92
|
+
} finally {
|
|
93
|
+
page.close()
|
|
94
|
+
getHeadlessPool().release(browser)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
HeadlessPost.parameterSpec = [
|
|
99
|
+
{
|
|
100
|
+
type: 'string',
|
|
101
|
+
name: 'path',
|
|
102
|
+
label: 'path'
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: 'http-headers',
|
|
106
|
+
name: 'headers',
|
|
107
|
+
label: 'headers'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'select',
|
|
111
|
+
name: 'contentType',
|
|
112
|
+
label: 'content-type',
|
|
113
|
+
property: {
|
|
114
|
+
options: [
|
|
115
|
+
{
|
|
116
|
+
display: '',
|
|
117
|
+
value: ''
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
display: 'application/json',
|
|
121
|
+
value: 'application/json'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
display: 'text/plain',
|
|
125
|
+
value: 'text/plain'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
display: 'application/x-www-form-urlencoded',
|
|
129
|
+
value: 'application/x-www-form-urlencoded'
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'scenario-step-input',
|
|
136
|
+
name: 'accessor',
|
|
137
|
+
label: 'accessor'
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
TaskRegistry.registerTaskHandler('headless-post', HeadlessPost)
|
|
@@ -61,15 +61,11 @@ async function HttpPost(step, { logger, data, domain }) {
|
|
|
61
61
|
|
|
62
62
|
var response = await fetch(url, fetchOptions)
|
|
63
63
|
|
|
64
|
-
var responseData = await response.text()
|
|
65
|
-
|
|
66
|
-
const responseContentType = response.headers.get('content-type')
|
|
67
|
-
if (responseContentType && responseContentType.indexOf('application/json') !== -1) {
|
|
68
|
-
responseData = JSON.stringify(responseData)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
64
|
return {
|
|
72
|
-
data:
|
|
65
|
+
data:
|
|
66
|
+
response.ok && response.headers.get('content-type').includes('application/json')
|
|
67
|
+
? await response.json()
|
|
68
|
+
: await response.text()
|
|
73
69
|
}
|
|
74
70
|
}
|
|
75
71
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as genericPool from 'generic-pool'
|
|
2
|
+
|
|
3
|
+
import { config, logger } from '@things-factory/env'
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
var puppeteer = require('puppeteer')
|
|
7
|
+
} catch (err) {
|
|
8
|
+
logger.error(err)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
var headlessPool
|
|
12
|
+
|
|
13
|
+
export function getHeadlessPool() {
|
|
14
|
+
if (!headlessPool) {
|
|
15
|
+
headlessPool = genericPool.createPool(
|
|
16
|
+
{
|
|
17
|
+
create() {
|
|
18
|
+
console.log('headless-pool-for-scensrio about to create')
|
|
19
|
+
return initializeChromium()
|
|
20
|
+
},
|
|
21
|
+
validate(browser) {
|
|
22
|
+
return Promise.race([
|
|
23
|
+
new Promise(res => setTimeout(() => res(false), 1500)),
|
|
24
|
+
browser
|
|
25
|
+
//@ts-ignore
|
|
26
|
+
.version()
|
|
27
|
+
.then(_ => true)
|
|
28
|
+
.catch(_ => false)
|
|
29
|
+
])
|
|
30
|
+
},
|
|
31
|
+
destroy(browser) {
|
|
32
|
+
//@ts-ignore
|
|
33
|
+
return browser.close()
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
min: 2,
|
|
38
|
+
max: 10,
|
|
39
|
+
testOnBorrow: true,
|
|
40
|
+
acquireTimeoutMillis: 15000
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return headlessPool
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const CHROMIUM_PATH = config.get('CHROMIUM_PATH')
|
|
49
|
+
|
|
50
|
+
async function initializeChromium() {
|
|
51
|
+
try {
|
|
52
|
+
if (!puppeteer) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var launchSetting = {
|
|
57
|
+
args: ['--mute-audio', '--no-sandbox'],
|
|
58
|
+
headless: 'new'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (CHROMIUM_PATH) {
|
|
62
|
+
launchSetting['executablePath'] = CHROMIUM_PATH
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const browser = await puppeteer.launch(launchSetting)
|
|
66
|
+
|
|
67
|
+
return browser
|
|
68
|
+
} catch (err) {
|
|
69
|
+
logger.error(err)
|
|
70
|
+
}
|
|
71
|
+
}
|