pinokiod 3.8.44 → 3.8.45
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/kernel/bin/caddy.js +1 -1
- package/kernel/bin/index.js +0 -18
- package/kernel/{caddy.js → caddy2.js} +0 -6
- package/kernel/index.js +15 -29
- package/kernel/loader.js +1 -1
- package/kernel/peer.js +21 -31
- package/kernel/peer2.js +83 -0
- package/kernel/prototype.js +0 -1
- package/kernel/router/common.js +29 -0
- package/kernel/router/connector.js +56 -0
- package/kernel/router/index.js +137 -0
- package/kernel/router/localhost_home_router.js +61 -0
- package/kernel/router/localhost_port_router.js +15 -0
- package/kernel/router/localhost_variable_router.js +39 -0
- package/kernel/router/peer_home_router.js +15 -0
- package/kernel/router/peer_port_router.js +43 -0
- package/kernel/router/peer_variable_router.js +48 -0
- package/kernel/router/processor.js +18 -0
- package/kernel/router/root.js +32 -0
- package/kernel/sysinfo.js +0 -1
- package/kernel/util.js +1 -3
- package/package.json +1 -1
- package/pipe/index.js +0 -2
- package/server/index.js +34 -70
- package/server/views/install.ejs +0 -1
- package/server/views/proxy.ejs +4 -4
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const Util = require('../util')
|
|
4
|
+
const LocalhostHomeRouter = require('./localhost_home_router')
|
|
5
|
+
const LocalhostVariableRouter = require('./localhost_variable_router')
|
|
6
|
+
const LocalhostPortRouter = require('./localhost_port_router')
|
|
7
|
+
const PeerHomeRouter = require('./peer_home_router')
|
|
8
|
+
const PeerVariableRouter = require('./peer_variable_router')
|
|
9
|
+
const PeerPortRouter = require('./peer_port_router')
|
|
10
|
+
class Router {
|
|
11
|
+
constructor(kernel) {
|
|
12
|
+
this.kernel = kernel
|
|
13
|
+
this.localhost_home_router = new LocalhostHomeRouter(this)
|
|
14
|
+
this.localhost_variable_router = new LocalhostVariableRouter(this)
|
|
15
|
+
this.localhost_port_router = new LocalhostPortRouter(this)
|
|
16
|
+
this.peer_home_router = new PeerHomeRouter(this)
|
|
17
|
+
this.peer_variable_router = new PeerVariableRouter(this)
|
|
18
|
+
this.peer_port_router = new PeerPortRouter(this)
|
|
19
|
+
this.default_prefix = "pinokio"
|
|
20
|
+
this.default_suffix = "localhost"
|
|
21
|
+
this.default_match = this.default_prefix + "." + this.default_suffix
|
|
22
|
+
this.default_port = "42000"
|
|
23
|
+
this.default_host = "127.0.0.1"
|
|
24
|
+
this.config
|
|
25
|
+
}
|
|
26
|
+
async add({ host, match, dial }) {
|
|
27
|
+
if (!this._mapping[host]) {
|
|
28
|
+
this._mapping[host] = {}
|
|
29
|
+
}
|
|
30
|
+
if (!this._mapping[host][dial]) {
|
|
31
|
+
this._mapping[host][dial] = new Set()
|
|
32
|
+
}
|
|
33
|
+
this._mapping[host][dial].add(match)
|
|
34
|
+
}
|
|
35
|
+
info() {
|
|
36
|
+
let mapping = {}
|
|
37
|
+
for(let host in this._mapping) {
|
|
38
|
+
let internal_maps = this._mapping[host]
|
|
39
|
+
if (!mapping[host]) {
|
|
40
|
+
mapping[host] = {}
|
|
41
|
+
}
|
|
42
|
+
for(let url in internal_maps) {
|
|
43
|
+
mapping[host][url] = Array.from(internal_maps[url])
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return mapping
|
|
47
|
+
}
|
|
48
|
+
async fill() {
|
|
49
|
+
const jsonString = JSON.stringify(this.config)
|
|
50
|
+
// find all PORT_PLACEHOLDER patterns
|
|
51
|
+
const matches = jsonString.match(/:PORT_PLACEHOLDER_[0-9.:]+/g)
|
|
52
|
+
console.log("matches", matches)
|
|
53
|
+
|
|
54
|
+
// iterate through them and see if the port already exists
|
|
55
|
+
let count = 0
|
|
56
|
+
if (matches) {
|
|
57
|
+
for(let match of matches) {
|
|
58
|
+
console.log("testing", match)
|
|
59
|
+
const port_match = match.match(/[0-9.]+:([0-9]+)/);
|
|
60
|
+
let port = port_match ? port_match[1] : null
|
|
61
|
+
console.log({ port, port_match })
|
|
62
|
+
if (port && !this.port_mapping[port]) {
|
|
63
|
+
count++
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log("count", count)
|
|
69
|
+
|
|
70
|
+
if (count > 0) {
|
|
71
|
+
let ports = await this.kernel.ports(count)
|
|
72
|
+
console.log({ count, ports })
|
|
73
|
+
console.log("PORT_CACHE", this.port_cache)
|
|
74
|
+
let response = Util.fill_object(this.config, /PORT_PLACEHOLDER_.+/, ports, this.port_cache)
|
|
75
|
+
this.config = response.result
|
|
76
|
+
let replaced_map = response.replaced_map
|
|
77
|
+
for(let key in replaced_map) {
|
|
78
|
+
// local_share_ip :- 192.168....
|
|
79
|
+
let local_share_key = key.replace("PORT_PLACEHOLDER_", "")
|
|
80
|
+
let chunks = local_share_key.split(":")
|
|
81
|
+
let local_share_ip = chunks[0]
|
|
82
|
+
let original_port = chunks[1]
|
|
83
|
+
let local_share_port = replaced_map[key]
|
|
84
|
+
console.log({ local_share_ip, local_share_port })
|
|
85
|
+
if (!this.local_network_mapping[local_share_ip]) {
|
|
86
|
+
this.local_network_mapping[local_share_ip] = {}
|
|
87
|
+
}
|
|
88
|
+
this.local_network_mapping[local_share_ip][original_port] = local_share_port
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
//let original_port = key.replace("PORT_PLACEHOLDER_", "")
|
|
92
|
+
this.port_mapping[original_port] = replaced_map[key]
|
|
93
|
+
}
|
|
94
|
+
this.port_cache = replaced_map
|
|
95
|
+
}
|
|
96
|
+
console.log("port_cache", this.port_cache)
|
|
97
|
+
console.log("port_mapping", this.port_mapping)
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async refresh() {
|
|
102
|
+
this._mapping = {}
|
|
103
|
+
this.port_mapping = {} // 127.0.0.1 => 192.168,..
|
|
104
|
+
this.local_network_mapping = {}
|
|
105
|
+
|
|
106
|
+
// 1. Localhost handling
|
|
107
|
+
this.localhost_home_router.handle()
|
|
108
|
+
this.localhost_variable_router.handle(this.kernel.memory.local)
|
|
109
|
+
let procs = await this.kernel.processes.refresh()
|
|
110
|
+
for(let proc of procs) {
|
|
111
|
+
this.localhost_port_router.handle(proc)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 2. Peers handling
|
|
115
|
+
let peers = await this.kernel.peer.refresh()
|
|
116
|
+
for(let host in peers) {
|
|
117
|
+
let peer = peers[host]
|
|
118
|
+
this.peer_home_router.handle(peer)
|
|
119
|
+
this.peer_variable_router.handle(peer)
|
|
120
|
+
this.peer_port_router.handle(peer)
|
|
121
|
+
}
|
|
122
|
+
// replace :PORT_PLACEHOLDER with available ports
|
|
123
|
+
|
|
124
|
+
await this.fill()
|
|
125
|
+
|
|
126
|
+
console.log("CONFIG", JSON.stringify(this.config, null, 2))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
let response = await axios.post('http://127.0.0.1:2019/load', this.config, {
|
|
130
|
+
headers: { 'Content-Type': 'application/json' }
|
|
131
|
+
}).catch((e) => {
|
|
132
|
+
console.log("EEEEEEEEEEEEE", e)
|
|
133
|
+
})
|
|
134
|
+
console.log("Caddy Response", { response })
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
module.exports = Router
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
class LocalhostHomeRouter {
|
|
2
|
+
constructor(router) {
|
|
3
|
+
this.router = router
|
|
4
|
+
}
|
|
5
|
+
handle () {
|
|
6
|
+
this.router.config = {
|
|
7
|
+
"apps": {
|
|
8
|
+
"http": {
|
|
9
|
+
"servers": {
|
|
10
|
+
"main": {
|
|
11
|
+
"listen": [":443"],
|
|
12
|
+
"routes": [
|
|
13
|
+
{
|
|
14
|
+
"match": [{ "method": ["OPTIONS"] }],
|
|
15
|
+
"handle": [
|
|
16
|
+
{
|
|
17
|
+
"handler": "headers",
|
|
18
|
+
"response": {
|
|
19
|
+
"set": {
|
|
20
|
+
"Access-Control-Allow-Origin": ["*"],
|
|
21
|
+
"Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
|
|
22
|
+
"Access-Control-Allow-Headers": ["*"],
|
|
23
|
+
"Vary": ["Origin"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"handler": "static_response",
|
|
29
|
+
"status_code": 204
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"match": [{ "host": [ this.router.default_match ] }],
|
|
35
|
+
"handle": [
|
|
36
|
+
{
|
|
37
|
+
"handler": "reverse_proxy",
|
|
38
|
+
"upstreams": [{ "dial": this.router.default_host + ":" + this.router.default_port }]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"handler": "headers",
|
|
42
|
+
"response": {
|
|
43
|
+
"set": {
|
|
44
|
+
"Access-Control-Allow-Origin": ["*"],
|
|
45
|
+
"Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
|
|
46
|
+
"Access-Control-Allow-Headers": ["*"],
|
|
47
|
+
"Vary": ["Origin"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
module.exports = LocalhostHomeRouter
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const Common = require('./common')
|
|
2
|
+
class LocalhostHomeRouter {
|
|
3
|
+
constructor(router) {
|
|
4
|
+
this.router = router
|
|
5
|
+
this.common = new Common(router)
|
|
6
|
+
}
|
|
7
|
+
handle (proc) {
|
|
8
|
+
this.common.handle({
|
|
9
|
+
match: `${proc.port}.localhost`,
|
|
10
|
+
dial: proc.ip,
|
|
11
|
+
host: this.router.kernel.peer.host,
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
module.exports = LocalhostHomeRouter
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const Common = require('./common')
|
|
3
|
+
const Processor = require('./processor')
|
|
4
|
+
class LocalhostVariableRouter extends Processor {
|
|
5
|
+
constructor(router) {
|
|
6
|
+
super()
|
|
7
|
+
this.router = router
|
|
8
|
+
this.common = new Common(router)
|
|
9
|
+
}
|
|
10
|
+
handle (local) {
|
|
11
|
+
console.log("localhost_variable_router", { local })
|
|
12
|
+
for(let script_path in local) {
|
|
13
|
+
let local_variables_for_script = local[script_path]
|
|
14
|
+
for(let key in local_variables_for_script) {
|
|
15
|
+
let val = local_variables_for_script[key]
|
|
16
|
+
if (val.startsWith("http")) {
|
|
17
|
+
let dial = val.replace(/https?:\/\//, '')
|
|
18
|
+
let name = this.api_name(script_path)
|
|
19
|
+
console.log({ dial, name, has_port: this.has_port(dial), parsed_dial: this.parse_ip(dial) })
|
|
20
|
+
if (this.has_port(dial)) {
|
|
21
|
+
if (key === "url") {
|
|
22
|
+
this.common.handle({
|
|
23
|
+
match: `${name}.localhost`.toLowerCase(),
|
|
24
|
+
dial,
|
|
25
|
+
host: this.router.kernel.peer.host,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
this.common.handle({
|
|
29
|
+
match: `${key}.${name}.localhost`.toLowerCase(),
|
|
30
|
+
dial,
|
|
31
|
+
host: this.router.kernel.peer.host,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
module.exports = LocalhostVariableRouter
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const Common = require('./common')
|
|
2
|
+
class PeerHomeRouter {
|
|
3
|
+
constructor(router) {
|
|
4
|
+
this.router = router
|
|
5
|
+
this.common = new Common(router)
|
|
6
|
+
}
|
|
7
|
+
handle(peer) {
|
|
8
|
+
this.common.handle({
|
|
9
|
+
match: `${this.router.default_prefix}.${peer.name}.${this.router.default_suffix}`,
|
|
10
|
+
dial: `${peer.host}:${this.router.default_port}`,
|
|
11
|
+
host: peer.host
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
module.exports = PeerHomeRouter
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const Processor = require('./processor')
|
|
3
|
+
const Connector = require('./connector')
|
|
4
|
+
class PeerPortRouter extends Processor {
|
|
5
|
+
constructor(router) {
|
|
6
|
+
super()
|
|
7
|
+
this.router = router
|
|
8
|
+
this.connector = new Connector(router)
|
|
9
|
+
}
|
|
10
|
+
handle(peer) {
|
|
11
|
+
let https_domains_mapping = this.router.info()[peer.host]
|
|
12
|
+
for(let dial in https_domains_mapping) {
|
|
13
|
+
let parsed_dial = this.parse_ip(dial)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
let https_domains = https_domains_mapping[dial]
|
|
17
|
+
|
|
18
|
+
// 1. if https_domains is made up of one item <port>.localhost,
|
|
19
|
+
// add <port>.<account>.localhost
|
|
20
|
+
// 2. if https_domains is made up of two items <port>.localhost and <port>.<account>.localhost, don't do anything
|
|
21
|
+
for(let https_domain of https_domains) {
|
|
22
|
+
// insert the $account value right before the last part (1234.localhost => 1234.x.localhost)
|
|
23
|
+
let match
|
|
24
|
+
if (https_domain.endsWith(`${peer.name}.localhost`)) {
|
|
25
|
+
match = https_domain
|
|
26
|
+
} else {
|
|
27
|
+
let chunks = https_domain.split(".")
|
|
28
|
+
chunks.splice(chunks.length - 1, 0, peer.name)
|
|
29
|
+
match = chunks.join(".")
|
|
30
|
+
}
|
|
31
|
+
this.connector.handle({
|
|
32
|
+
match,
|
|
33
|
+
connector: {
|
|
34
|
+
host: peer.host,
|
|
35
|
+
port: parsed_dial.port
|
|
36
|
+
},
|
|
37
|
+
dial,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
module.exports = PeerPortRouter
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const Connector = require('./connector')
|
|
3
|
+
const Processor = require('./processor')
|
|
4
|
+
class PeerVariableRouter extends Processor {
|
|
5
|
+
constructor(router) {
|
|
6
|
+
super()
|
|
7
|
+
this.router = router
|
|
8
|
+
this.connector = new Connector(router)
|
|
9
|
+
}
|
|
10
|
+
handle(peer) {
|
|
11
|
+
for(let script_path in peer.local) {
|
|
12
|
+
let local_variables = peer.local[script_path]
|
|
13
|
+
for(let key in local_variables) {
|
|
14
|
+
let val = local_variables[key]
|
|
15
|
+
console.log({ key, val })
|
|
16
|
+
if (val.startsWith("http")) {
|
|
17
|
+
let dial = val.replace(/https?:\/\//, '')
|
|
18
|
+
let name = this.api_name(script_path)
|
|
19
|
+
console.log({ dial, name, has_port: this.has_port(dial), parsed_dial: this.parse_ip(dial) })
|
|
20
|
+
if (this.has_port(dial)) {
|
|
21
|
+
let parsed_dial = this.parse_ip(dial)
|
|
22
|
+
if (key === "url") {
|
|
23
|
+
this.connector.handle({
|
|
24
|
+
match: `${name}.${peer.name}.localhost`.toLowerCase(),
|
|
25
|
+
connector: {
|
|
26
|
+
host: peer.host,
|
|
27
|
+
port: parsed_dial.port
|
|
28
|
+
},
|
|
29
|
+
dial,
|
|
30
|
+
host: peer.host,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
connector({
|
|
34
|
+
match:`${key}.${name}.${peer.name}.localhost`.toLowerCase(),
|
|
35
|
+
connector: {
|
|
36
|
+
host: peer.host,
|
|
37
|
+
port: parsed_dial.port
|
|
38
|
+
},
|
|
39
|
+
dial,
|
|
40
|
+
host: peer.host,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
module.exports = PeerVariableRouter
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
class Processor {
|
|
3
|
+
has_port(str) {
|
|
4
|
+
let chunks = str.split(":")
|
|
5
|
+
return chunks.length === 2
|
|
6
|
+
}
|
|
7
|
+
api_name(str) {
|
|
8
|
+
let api_path = this.router.kernel.path("api")
|
|
9
|
+
let rel_path = path.relative(api_path, str)
|
|
10
|
+
console.log({ api_path, rel_path, })
|
|
11
|
+
return rel_path.split(path.sep)[0]
|
|
12
|
+
}
|
|
13
|
+
parse_ip(str) {
|
|
14
|
+
let chunks = str.split(":")
|
|
15
|
+
return { host: chunks[0], port: chunks[1] }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
module.exports = Processor
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module.exports = (payload, { match, dial }) => {
|
|
2
|
+
// create a root level reverse proxy for
|
|
3
|
+
// - peer with ip,
|
|
4
|
+
// - at port
|
|
5
|
+
// The ip is only used for ensuring uniqueness
|
|
6
|
+
// But the only thing that will be exposed is the port
|
|
7
|
+
let name = match.ip + ":" + match.port
|
|
8
|
+
payload.apps.http.servers[name] = {
|
|
9
|
+
// 0.0.0.0:<new_port>
|
|
10
|
+
"listen": ["0.0.0.0:PORT_PLACEHOLDER_" + name],
|
|
11
|
+
"routes": [{
|
|
12
|
+
"handle": [
|
|
13
|
+
{
|
|
14
|
+
"handler": "reverse_proxy",
|
|
15
|
+
// create a route from <new_port> to dial
|
|
16
|
+
"upstreams": [{ "dial": dial }]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"handler": "headers",
|
|
20
|
+
"response": {
|
|
21
|
+
"set": {
|
|
22
|
+
"Access-Control-Allow-Origin": ["*"],
|
|
23
|
+
"Access-Control-Allow-Methods": ["GET, POST, OPTIONS, PUT, DELETE"],
|
|
24
|
+
"Access-Control-Allow-Headers": ["*"],
|
|
25
|
+
"Vary": ["Origin"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}]
|
|
31
|
+
}
|
|
32
|
+
}
|
package/kernel/sysinfo.js
CHANGED
package/kernel/util.js
CHANGED
|
@@ -271,7 +271,6 @@ const find_venv = async (root) => {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const update_env = async (filepath, changes) => {
|
|
274
|
-
console.log("UPDATE_ENV", { filepath, changes })
|
|
275
274
|
const env = await fs.promises.readFile(filepath, "utf8")
|
|
276
275
|
let append = false;
|
|
277
276
|
const newval = Object.keys(changes).reduce((result, varname) => {
|
|
@@ -308,7 +307,7 @@ const update_env = async (filepath, changes) => {
|
|
|
308
307
|
await fs.promises.writeFile(filepath, newval)
|
|
309
308
|
};
|
|
310
309
|
function fill_object(obj, pattern, list, cache) {
|
|
311
|
-
console.log("FILL_OBJECT")
|
|
310
|
+
console.log("FILL_OBJECT", { obj, pattern, list, cache })
|
|
312
311
|
const map = {};
|
|
313
312
|
const replaced_map = cache || {}
|
|
314
313
|
let index = 0;
|
|
@@ -317,7 +316,6 @@ function fill_object(obj, pattern, list, cache) {
|
|
|
317
316
|
if (typeof value === 'string') {
|
|
318
317
|
return value.replace(pattern, (match) => {
|
|
319
318
|
if (!(match in map)) {
|
|
320
|
-
console.log( "fill_object", { replaced_map, match })
|
|
321
319
|
if (replaced_map[match]) {
|
|
322
320
|
map[match] = replaced_map[match]
|
|
323
321
|
} else {
|
package/package.json
CHANGED
package/pipe/index.js
CHANGED
|
@@ -22,7 +22,6 @@ class Pipe {
|
|
|
22
22
|
}
|
|
23
23
|
// a pipe server for creating publicly shareable endpoints
|
|
24
24
|
async start(url, scriptPath, passcode, config) {
|
|
25
|
-
console.log("pipe.start", { url, scriptPath, passcode, config })
|
|
26
25
|
|
|
27
26
|
let port = await this.kernel.port()
|
|
28
27
|
let app = express();
|
|
@@ -100,7 +99,6 @@ class Pipe {
|
|
|
100
99
|
|
|
101
100
|
|
|
102
101
|
await new Promise((resolve, reject) => {
|
|
103
|
-
console.log("starting pipe server at port", port)
|
|
104
102
|
let server = app.listen(port, () => {
|
|
105
103
|
console.log(`Pipe server listening on port ${port}`)
|
|
106
104
|
resolve()
|