Skip to content

feat: new ctl #1302

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

Closed
wants to merge 2 commits into from
Closed
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
26,138 changes: 25,672 additions & 466 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"i18next-electron-language-detector": "0.0.10",
"i18next-icu": "^1.1.2",
"i18next-node-fs-backend": "^2.1.3",
"ipfsd-ctl": "^0.46.1",
"ipfsd-ctl": "^1.0.2",
"is-ipfs": "^0.6.1",
"multiaddr": "^7.2.1",
"multiaddr-to-uri": "^5.0.0",
Expand Down
95 changes: 52 additions & 43 deletions src/daemon/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import { showDialog } from '../dialogs'
import store from '../common/store'
import logger from '../common/logger'

export function configExists (ipfsPath) {
return fs.pathExistsSync(join(ipfsPath, 'config'))
}

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

function readConfigFile (ipfsd) {
Expand Down Expand Up @@ -151,7 +155,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 +188,9 @@ export async function checkPorts (ipfsd) {
const apiPort = parseInt(configApiMa.nodeAddress().port, 10)
const gatewayPort = parseInt(configGatewayMa.nodeAddress().port, 10)

const freeGatewayPort = await getPort({ port: getPort.makeRange(gatewayPort, gatewayPort + 100) })
const freeApiPort = await getPort({ port: getPort.makeRange(apiPort, apiPort + 100) })
const findFreePort = async (port, from) => getPort({ port: getPort.makeRange(Math.max(port, from, 1024), 65535) })
const freeGatewayPort = await findFreePort(gatewayPort, 8080)
const freeApiPort = await findFreePort(apiPort, 5001)

const busyApiPort = apiPort !== freeApiPort
const busyGatewayPort = gatewayPort !== freeGatewayPort
Expand All @@ -194,54 +199,58 @@ export 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) {
config.Addresses.API = config.Addresses.API.replace(apiPort.toString(), freeApiPort.toString())
config.Addresses.API = config.Addresses.API.replace(`/tcp/${apiPort}`, `/tcp/${freeApiPort}`)
}

if (busyGatewayPort) {
config.Addresses.Gateway = config.Addresses.Gateway.replace(gatewayPort.toString(), freeGatewayPort.toString())
config.Addresses.Gateway = config.Addresses.Gateway.replace(`/tcp/${gatewayPort}`, `/tcp/${freeGatewayPort}`)
}

writeConfigFile(ipfsd, config)
Expand Down
45 changes: 27 additions & 18 deletions src/daemon/daemon.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import IPFSFactory from 'ipfsd-ctl'
import Ctl from 'ipfsd-ctl'
import i18n from 'i18next'
import fs from 'fs-extra'
import { app } from 'electron'
import { execFileSync } from 'child_process'
import findExecutable from 'ipfsd-ctl/src/utils/find-ipfs-executable'
import { findBin } from 'ipfsd-ctl/src/utils'
import { showDialog } from '../dialogs'
import logger from '../common/logger'
import { applyDefaults, checkCorsConfig, checkPorts, configPath } from './config'
import { applyDefaults, checkCorsConfig, checkPorts, configExists } from './config'

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

if (!await fs.pathExists(configPath(ipfsd))) {
if (!configExists(ipfsd.path)) {
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 = findBin('go')

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

async function spawn ({ type, path, keysize }) {
const factory = IPFSFactory.create({ type: type })
async function spawn ({ type, path, flags, keysize }) {
// NOTE: presence of env variable IPFS_PATH overrides config
path = process.env.IPFS_PATH || path

const ipfsd = await factory.spawn({
const factory = Ctl.createFactory({
remote: false,
disposable: false,
defaultAddrs: true,
repoPath: path,
test: false,
args: flags,
type: type
})

const ipfsd = await factory.spawn({
ipfsOptions: {
repo: path
},
Comment on lines +56 to +59
Copy link
Member

Choose a reason for hiding this comment

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

I believe basic init did not work because repo path got moved to ipfsOptions. This was the fix :)

Copy link
Member Author

@hacdias hacdias Apr 17, 2020

Choose a reason for hiding this comment

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

About the api file: I thought IPFS itself (or the controller) handled it! The only thing we did was this: #722.

init: false,
start: false
})

if (ipfsd.initialized) {
// old: if (ipfsd.initialized) { TODO: ipfsd.initialized is not set properly when Ctl's factory.spawn is called with init: false
if (configExists(ipfsd.path)) {
checkCorsConfig(ipfsd)
return ipfsd
}
Expand All @@ -71,17 +79,18 @@ async function spawn ({ type, path, keysize }) {
export default async function (opts) {
const ipfsd = await spawn(opts)
await checkPorts(ipfsd)
await ipfsd.start(opts.flags)
await ipfsd.start()

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

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

return ipfsd
Expand Down
15 changes: 5 additions & 10 deletions src/daemon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,9 @@ export default async function (ctx) {

try {
ipfsd = await createDaemon(config)

// Update the path if it was blank previously.
// This way we use the default path when it is
// not set.
if (config.path === '') {
config.path = ipfsd.repoPath
// Update the path if daemon changed it (eg. due to passing a custom IPFS_PATH)
if (config.path !== ipfsd.path) {
config.path = ipfsd.path
store.set('ipfsConfig', config)
writeIpfsPath(config.path)
}
Expand All @@ -86,17 +83,15 @@ export default 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.pathExists(join(ipfsd.path, 'config'))) {
// 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) {
Expand Down
Loading