Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update ipfsd-ctl to 4.x #1411

Merged
merged 6 commits into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,281 changes: 912 additions & 1,369 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,16 @@
"electron-updater": "^4.2.5",
"fix-path": "^3.0.0",
"fs-extra": "^9.0.0",
"go-ipfs-dep": "0.4.23",
"i18next": "^19.4.3",
"go-ipfs-dep": "^0.4.23-3",
"i18next-electron-language-detector": "0.0.10",
"i18next-icu": "^1.3.1",
"i18next-node-fs-backend": "^2.1.3",
"ipfsd-ctl": "^0.46.1",
"ipfs-http-client": "^44.0.0",
"ipfsd-ctl": "^4.0.1",
"is-ipfs": "^1.0.0",
"it-all": "^1.0.1",
"it-concat": "^1.0.0",
"multiaddr": "^7.4.3",
"multiaddr-to-uri": "^5.1.0",
"portfinder": "^1.0.25",
Expand Down
28 changes: 16 additions & 12 deletions src/add-to-ipfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const { clipboard } = require('electron')
const i18n = require('i18next')
const logger = require('./common/logger')
const { notify, notifyError } = require('./common/notify')
const { globSource } = require('ipfs-http-client')

async function copyFile (ipfs, hash, name) {
async function copyFile (ipfs, cid, name) {
let i = 0
const ext = extname(name)
const base = basename(name, ext)
Expand All @@ -22,7 +23,7 @@ async function copyFile (ipfs, hash, name) {
i++
}

return ipfs.files.cp(`/ipfs/${hash}`, `/${name}`)
return ipfs.files.cp(`/ipfs/${cid.toString()}`, `/${name}`)
}

async function makeShareableObject (ipfs, results) {
Expand All @@ -33,15 +34,15 @@ async function makeShareableObject (ipfs, results) {

let baseCID = await ipfs.object.new('unixfs-dir')

for (const { hash, path, size } of results) {
for (const { cid, path, size } of results) {
baseCID = (await ipfs.object.patch.addLink(baseCID, {
name: path,
size,
cid: hash
})).toString()
cid
}))
}

return { hash: baseCID, path: '' }
return { cid: baseCID, path: '' }
}

function sendNotification (failures, successes, launch, path) {
Expand Down Expand Up @@ -86,10 +87,13 @@ module.exports = async function ({ getIpfsd, launchWebUI }, files) {

await Promise.all(files.map(async file => {
try {
const results = await ipfsd.api.addFromFs(file, { recursive: true })
const { path, hash, size } = results[results.length - 1]
await copyFile(ipfsd.api, hash, path)
successes.push({ path, hash, size })
let result = null
for await (const res of ipfsd.api.add(globSource(file, { recursive: true }))) {
result = res
}

await copyFile(ipfsd.api, result.cid, result.path)
successes.push(result)
} catch (e) {
failures.push(e)
}
Expand All @@ -101,9 +105,9 @@ module.exports = async function ({ getIpfsd, launchWebUI }, files) {
log.end()
}

const { hash, path } = await makeShareableObject(ipfsd.api, successes)
const { cid, path } = await makeShareableObject(ipfsd.api, successes)
sendNotification(failures, successes, launchWebUI, path)

const url = `https://ipfs.io/ipfs/${hash}`
const url = `https://ipfs.io/ipfs/${cid.toString()}`
clipboard.writeText(url)
}
2 changes: 1 addition & 1 deletion src/common/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ module.exports = Object.freeze({
},
fail: (err) => {
Countly.log_error(err)
logger.error(`${msg} ${err.toString()}`)
logger.error(`${msg} ${err.stack}`)
}
}
},
Expand Down
102 changes: 61 additions & 41 deletions src/daemon/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ const { showDialog } = require('../dialogs')
const store = require('../common/store')
const logger = require('../common/logger')

function configExists (ipfsd) {
return fs.pathExistsSync(join(ipfsd.path, 'config'))
}

function apiFileExists (ipfsd) {
return fs.pathExistsSync(join(ipfsd.path, 'api'))
}

function configPath (ipfsd) {
return join(ipfsd.repoPath, 'config')
return join(ipfsd.path, 'config')
}

function readConfigFile (ipfsd) {
Expand Down Expand Up @@ -151,7 +159,7 @@ async function checkPortsArray (ipfsd, addrs) {
})

if (opt === 0) {
shell.openItem(join(ipfsd.repoPath, 'config'))
shell.openItem(join(ipfsd.path, 'config'))
}

throw new Error('ports already being used')
Expand Down Expand Up @@ -184,8 +192,13 @@ async function checkPorts (ipfsd) {
const apiPort = parseInt(configApiMa.nodeAddress().port, 10)
const gatewayPort = parseInt(configGatewayMa.nodeAddress().port, 10)

const freeGatewayPort = await portfinder.getPortPromise({ port: gatewayPort, stopPort: gatewayPort + 100 })
const freeApiPort = await portfinder.getPortPromise({ port: apiPort, stopPort: apiPort + 100 })
const findFreePort = async (port, from) => {
port = Math.max(port, from, 1024)
Copy link

@guanzo guanzo Feb 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, this Math.max call prevents me from setting a gateway port lower than 8080, and an api port lower than 5001. When I edit the config file and restart ipfs-desktop, it says the port is busy and suggests a new one.

For example if I try to set gateway port to 6437, then

const gatewayPort = 6437 // read from config file
const freeGatewayPort = await findFreePort(gatewayPort, 8080) // returns 8080

// evaluates to true, even though 6437 is free.
const busyGatewayPort = gatewayPort !== freeGatewayPort 

// I get a popup saying "The port 6437 is not available. Do you want to use 8080 instead?"

return portfinder.getPortPromise({ port, stopPort: port + 100 })
}

const freeGatewayPort = await findFreePort(gatewayPort, 8080)
const freeApiPort = await findFreePort(apiPort, 5001)

const busyApiPort = apiPort !== freeApiPort
const busyGatewayPort = gatewayPort !== freeGatewayPort
Expand All @@ -194,46 +207,51 @@ async function checkPorts (ipfsd) {
return
}

let message = null
let options = null

if (busyApiPort && busyGatewayPort) {
logger.info('[daemon] api and gateway ports busy')
message = 'busyPortsDialog'
options = {
port1: apiPort,
alt1: freeApiPort,
port2: gatewayPort,
alt2: freeGatewayPort
}
} else if (busyApiPort) {
logger.info('[daemon] api port busy')
message = 'busyPortDialog'
options = {
port: apiPort,
alt: freeApiPort
}
} else {
logger.info('[daemon] gateway port busy')
message = 'busyPortDialog'
options = {
port: gatewayPort,
alt: freeGatewayPort
// two "0" in config mean "pick free ports without any prompt"
const promptUser = (apiPort !== 0 || gatewayPort !== 0)

if (promptUser) {
let message = null
let options = null

if (busyApiPort && busyGatewayPort) {
logger.info('[daemon] api and gateway ports busy')
message = 'busyPortsDialog'
options = {
port1: apiPort,
alt1: freeApiPort,
port2: gatewayPort,
alt2: freeGatewayPort
}
} else if (busyApiPort) {
logger.info('[daemon] api port busy')
message = 'busyPortDialog'
options = {
port: apiPort,
alt: freeApiPort
}
} else {
logger.info('[daemon] gateway port busy')
message = 'busyPortDialog'
options = {
port: gatewayPort,
alt: freeGatewayPort
}
}
}

const opt = showDialog({
title: i18n.t(`${message}.title`),
message: i18n.t(`${message}.message`, options),
type: 'error',
buttons: [
i18n.t(`${message}.action`, options),
i18n.t('close')
]
})
const opt = showDialog({
title: i18n.t(`${message}.title`),
message: i18n.t(`${message}.message`, options),
type: 'error',
buttons: [
i18n.t(`${message}.action`, options),
i18n.t('close')
]
})

if (opt !== 0) {
throw new Error('ports already being used')
if (opt !== 0) {
throw new Error('ports already being used')
}
}

if (busyApiPort) {
Expand All @@ -250,6 +268,8 @@ async function checkPorts (ipfsd) {

module.exports = Object.freeze({
configPath,
configExists,
apiFileExists,
applyDefaults,
checkCorsConfig,
checkPorts
Expand Down
60 changes: 33 additions & 27 deletions src/daemon/daemon.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
const IPFSFactory = require('ipfsd-ctl')
const Ctl = require('ipfsd-ctl')
const i18n = require('i18next')
const fs = require('fs-extra')
const { app } = require('electron')
const { execFileSync } = require('child_process')
const findExecutable = require('ipfsd-ctl/src/utils/find-ipfs-executable')
const { showDialog } = require('../dialogs')
const logger = require('../common/logger')
const { applyDefaults, checkCorsConfig, checkPorts, configPath } = require('./config')
const { applyDefaults, checkCorsConfig, checkPorts, configExists, apiFileExists } = require('./config')

function cannotConnectDialog (addr) {
showDialog({
Expand All @@ -22,19 +19,19 @@ function cannotConnectDialog (addr) {
async function cleanup (ipfsd) {
const log = logger.start('[daemon] cleanup')

if (!await fs.pathExists(configPath(ipfsd))) {
if (!configExists(ipfsd)) {
cannotConnectDialog(ipfsd.apiAddr)
throw new Error('cannot tonnect to api')
throw new Error('cannot connect to api')
}

log.info('run: ipfs repo fsck')
const exec = findExecutable('go', app.getAppPath())
const exec = require('go-ipfs-dep').path()

try {
execFileSync(exec, ['repo', 'fsck'], {
env: {
...process.env,
IPFS_PATH: ipfsd.repoPath
IPFS_PATH: ipfsd.path
}
})
log.end()
Expand All @@ -43,45 +40,54 @@ async function cleanup (ipfsd) {
}
}

async function spawn ({ type, path, keysize }) {
const factory = IPFSFactory.create({ type: type })

const ipfsd = await factory.spawn({
async function spawn ({ flags, path, keysize }) {
const ipfsd = await Ctl.createController({
ipfsHttpModule: require('ipfs-http-client'),
ipfsBin: require('go-ipfs-dep').path(),
ipfsOptions: {
repo: path
},
remote: false,
disposable: false,
defaultAddrs: true,
repoPath: path,
init: false,
start: false
test: false,
args: flags
})

if (ipfsd.initialized) {
if (configExists(ipfsd)) {
checkCorsConfig(ipfsd)
return ipfsd
return { ipfsd, isRemote: false }
}

// If config does not exist, but $IPFS_PATH/api exists, then
// it is a remote repository.
if (apiFileExists(ipfsd)) {
return { ipfsd, isRemote: true }
}

await ipfsd.init({
directory: path,
keysize: keysize
bits: keysize
})

applyDefaults(ipfsd)
return ipfsd
return { ipfsd, isRemote: false }
}

module.exports = async function (opts) {
const ipfsd = await spawn(opts)
await checkPorts(ipfsd)
await ipfsd.start(opts.flags)
const { ipfsd, isRemote } = await spawn(opts)
if (!isRemote) await checkPorts(ipfsd)

try {
await ipfsd.api.id()
await ipfsd.start()
const { id } = await ipfsd.api.id()
logger.info(`[daemon] PeerID is ${id}`)
logger.info(`[daemon] Repo is at ${ipfsd.path}`)
} catch (err) {
if (!err.message.includes('ECONNREFUSED')) {
throw err
}

await cleanup(ipfsd)
await ipfsd.start(opts.flags)
await ipfsd.start()
}

return ipfsd
Expand Down
10 changes: 4 additions & 6 deletions src/daemon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module.exports = async function (ctx) {
// This way we use the default path when it is
// not set.
if (!config.path || typeof config.path !== 'string') {
config.path = ipfsd.repoPath
config.path = ipfsd.path
store.set('ipfsConfig', config)
writeIpfsPath(config.path)
}
Expand All @@ -78,21 +78,19 @@ module.exports = async function (ctx) {
const log = logger.start('[ipfsd] stop daemon', { withAnalytics: 'DAEMON_STOP' })
updateStatus(STATUS.STOPPING_STARTED)

if (!fs.pathExists(join(ipfsd.repoPath, 'config'))) {
if (!fs.pathExistsSync(join(ipfsd.path, 'config'))) {
Copy link
Member

@lidel lidel Apr 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hacdias pathExists returns a promise, FYSA I fixed this (247b3a8) to use pathExistsSync instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oopsie. I knew that but completely missed. Probably forgot adding an await. Thanks!

// Is remote api... ignore
ipfsd = null
updateStatus(STATUS.STOPPING_FINISHED)
return
}

try {
// give ipfs 3s to stop. An unclean shutdown is preferable to making the
// user wait, and taking longer prevents the update mechanism from working.
await ipfsd.stop(180)
await ipfsd.stop()
log.end()
updateStatus(STATUS.STOPPING_FINISHED)
} catch (err) {
logger.error(`[ipfsd] ${err.toString}`)
logger.error(`[ipfsd] ${err.toString()}`)
updateStatus(STATUS.STOPPING_FAILED)
} finally {
ipfsd = null
Expand Down
Loading