Skip to content

Commit b03f7ea

Browse files
committed
fix(brave): no port collisions
Before starting embedded js-ipfs we now check if API and Gateway ports are free. If not, we find available ones and update the config. This way user does not need to deal with "port taken" errors and embedded node provides seamless experience without surprises.
1 parent e0e26ed commit b03f7ea

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

add-on/src/lib/ipfs-client/embedded-chromesockets.js

+28-8
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,16 @@ const Ipfs = require('ipfs')
1616
const HttpApi = require('ipfs/src/http')
1717
const multiaddr = require('multiaddr')
1818
const maToUri = require('multiaddr-to-uri')
19+
const getPort = require('get-port')
1920

2021
const { optionDefaults } = require('../options')
2122

2223
// js-ipfs with embedded hapi HTTP server
2324
let node = null
2425
let nodeHttpApi = null
2526

26-
exports.init = function init (opts) {
27-
log('init embedded:chromesockets')
28-
27+
async function buildConfig (opts) {
2928
const defaultOpts = JSON.parse(optionDefaults.ipfsNodeConfig)
30-
3129
defaultOpts.libp2p = {
3230
config: {
3331
dht: {
@@ -36,9 +34,31 @@ exports.init = function init (opts) {
3634
}
3735
}
3836
}
39-
4037
const userOpts = JSON.parse(opts.ipfsNodeConfig)
41-
const ipfsOpts = mergeOptions.call({ concatArrays: true }, defaultOpts, userOpts, { start: false })
38+
const ipfsNodeConfig = mergeOptions.call({ concatArrays: true }, defaultOpts, userOpts, { start: false })
39+
40+
// Detect when API or Gateway port is not available (taken by something else)
41+
// We find the next free port and update configuration to use it instead
42+
const multiaddr2port = (ma) => parseInt(new URL(multiaddr2httpUrl(ma)).port, 10)
43+
const gatewayPort = multiaddr2port(ipfsNodeConfig.config.Addresses.Gateway)
44+
const apiPort = multiaddr2port(ipfsNodeConfig.config.Addresses.API)
45+
log(`checking if ports are available: api: ${apiPort}, gateway: ${gatewayPort}`)
46+
const freeGatewayPort = await getPort({ port: getPort.makeRange(gatewayPort, gatewayPort + 100) })
47+
const freeApiPort = await getPort({ port: getPort.makeRange(apiPort, apiPort + 100) })
48+
if (gatewayPort !== freeGatewayPort || apiPort !== freeApiPort) {
49+
log(`updating config to available ports: api: ${freeApiPort}, gateway: ${freeGatewayPort}`)
50+
const addrs = ipfsNodeConfig.config.Addresses
51+
addrs.Gateway = addrs.Gateway.replace(gatewayPort.toString(), freeGatewayPort.toString())
52+
addrs.API = addrs.API.replace(apiPort.toString(), freeApiPort.toString())
53+
}
54+
55+
return ipfsNodeConfig
56+
}
57+
58+
exports.init = async function init (opts) {
59+
log('init embedded:chromesockets')
60+
61+
const ipfsOpts = await buildConfig(opts)
4262
log('creating js-ipfs with opts: ', ipfsOpts)
4363
node = new Ipfs(ipfsOpts)
4464

@@ -90,9 +110,9 @@ async function updateConfigWithHttpEndpoints (ipfs, opts) {
90110
ipfsApiUrl: httpApi,
91111
ipfsNodeConfig: JSON.stringify(ipfsNodeConfig, null, 2)
92112
}
93-
// update current runtime config (in place, effective without restart)
113+
// update current runtime config (in place)
94114
Object.assign(opts, configChanges)
95-
// update user config in storage (effective on next run)
115+
// update user config in storage (triggers async client restart if ports changed)
96116
log(`synchronizing ipfsNodeConfig with customGatewayUrl (${configChanges.customGatewayUrl}) and ipfsApiUrl (${configChanges.ipfsApiUrl})`)
97117
await browser.storage.local.set(configChanges)
98118
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
"drag-and-drop-files": "0.0.1",
124124
"file-type": "11.1.0",
125125
"filesize": "4.1.2",
126+
"get-port": "5.0.0",
126127
"http-dns": "3.0.1",
127128
"http-node": "1.2.0",
128129
"ipfs": "https://github.com/lidel/js-ipfs/tarball/4081cbd69a252ec8adcec1e965724246669c9e9f/js-ipfs.tar.gz",

yarn.lock

+12
Original file line numberDiff line numberDiff line change
@@ -5613,6 +5613,13 @@ get-iterator@^1.0.0:
56135613
resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.1.tgz#8a284d9b4df9213269c56646dbedb5a90996595f"
56145614
integrity sha512-syV4W5X/I+HlT/RsqTwJ23P95JtaoD10EthArBIgWqxO8jtBqf2k2eNzye2cxvVLeOmz08Ya4wyv7vzCDtx6MQ==
56155615

5616+
5617+
version "5.0.0"
5618+
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.0.0.tgz#aa22b6b86fd926dd7884de3e23332c9f70c031a6"
5619+
integrity sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==
5620+
dependencies:
5621+
type-fest "^0.3.0"
5622+
56165623
get-port@^4.0.0:
56175624
version "4.0.0"
56185625
resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.0.0.tgz#373c85960138ee20027c070e3cb08019fea29816"
@@ -13895,6 +13902,11 @@ [email protected], type-detect@^4.0.0, type-detect@^4.0.5:
1389513902
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
1389613903
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
1389713904

13905+
type-fest@^0.3.0:
13906+
version "0.3.1"
13907+
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
13908+
integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
13909+
1389813910
type-fest@^0.4.1:
1389913911
version "0.4.1"
1390013912
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8"

0 commit comments

Comments
 (0)