- ${renderCompanionLogo(i18n, isIpfsOnline)}
- ${isIpfsOnline ? renderWelcome(i18n, peerCount, openWebUi) : renderInstallSteps(i18n, isIpfsOnline)}
+ ${renderCompanionLogo(i18n, apiAvailable)}
+ ${apiAvailable ? renderWelcome(i18n, peerCount, openWebUi) : renderInstallSteps(i18n, apiAvailable)}
@@ -43,14 +43,14 @@ function createWelcomePage (i18n) {
Render functions for the left side
======================================================== */
-const renderCompanionLogo = (i18n, isIpfsOnline) => {
+const renderCompanionLogo = (i18n, apiAvailable) => {
const logoPath = '../../../icons'
const logoSize = 128
- const stateUnknown = isIpfsOnline === null
+ const stateUnknown = apiAvailable === null
return html`
- ${logo({ path: logoPath, size: logoSize, isIpfsOnline: isIpfsOnline })}
+ ${logo({ path: logoPath, size: logoSize, apiAvailable: apiAvailable })}
${i18n.getMessage('page_landingWelcome_logo_title')}
`
@@ -83,10 +83,10 @@ const renderWelcome = (i18n, peerCount, openWebUi) => {
`
}
-const renderInstallSteps = (i18n, isIpfsOnline) => {
+const renderInstallSteps = (i18n, apiAvailable) => {
const copyClass = 'mv0 white f5 lh-copy'
const anchorClass = 'aqua hover-white'
- const stateUnknown = isIpfsOnline === null
+ const stateUnknown = apiAvailable == null
const svgWidth = 130
const nodeOffSvg = () => html`
diff --git a/add-on/src/landing-pages/welcome/store.js b/add-on/src/landing-pages/welcome/store.js
index 19833abc2..6d5614e29 100644
--- a/add-on/src/landing-pages/welcome/store.js
+++ b/add-on/src/landing-pages/welcome/store.js
@@ -4,7 +4,7 @@ const browser = require('webextension-polyfill')
function createWelcomePageStore (i18n, runtime) {
return function welcomePageStore (state, emitter) {
- state.isIpfsOnline = null
+ state.apiAvailable = null
state.peerCount = null
state.webuiRootUrl = null
let port
@@ -13,12 +13,10 @@ function createWelcomePageStore (i18n, runtime) {
port = runtime.connect({ name: 'browser-action-port' })
port.onMessage.addListener(async (message) => {
if (message.statusUpdate) {
- const webuiRootUrl = message.statusUpdate.webuiRootUrl
- const peerCount = message.statusUpdate.peerCount
- const isIpfsOnline = peerCount > -1
- if (isIpfsOnline !== state.isIpfsOnline || peerCount !== state.peerCount || webuiRootUrl !== state.webuiRootUrl) {
+ const { webuiRootUrl, peerCount, apiAvailable } = message.statusUpdate
+ if (apiAvailable !== state.apiAvailable || peerCount !== state.peerCount || webuiRootUrl !== state.webuiRootUrl) {
state.webuiRootUrl = webuiRootUrl
- state.isIpfsOnline = isIpfsOnline
+ state.apiAvailable = apiAvailable
state.peerCount = peerCount
emitter.emit('render')
}
diff --git a/add-on/src/lib/context-menus.js b/add-on/src/lib/context-menus.js
index 01943c3d2..d35e156ae 100644
--- a/add-on/src/lib/context-menus.js
+++ b/add-on/src/lib/context-menus.js
@@ -163,15 +163,15 @@ function createContextMenus (getState, runtime, ipfsPathValidator, { onAddFromCo
ipfsContext = ipfsPathValidator.isIpfsPageActionsContext(currentTab.url)
}
}
- const ifApi = getState().peerCount > -1
+ const { apiAvailable } = getState()
for (const item of apiMenuItems) {
- await browser.contextMenus.update(item, { enabled: ifApi })
+ await browser.contextMenus.update(item, { enabled: apiAvailable })
}
for (const item of ipfsContextItems) {
await browser.contextMenus.update(item, { enabled: ipfsContext })
}
for (const item of apiAndIpfsContextItems) {
- await browser.contextMenus.update(item, { enabled: (ifApi && ipfsContext) })
+ await browser.contextMenus.update(item, { enabled: (apiAvailable && ipfsContext) })
}
} catch (err) {
log.error('Error updating context menus', err)
diff --git a/add-on/src/lib/dnslink.js b/add-on/src/lib/dnslink.js
index b27736f44..f91ef519d 100644
--- a/add-on/src/lib/dnslink.js
+++ b/add-on/src/lib/dnslink.js
@@ -8,7 +8,6 @@ log.error = debug('ipfs-companion:dnslink:error')
const IsIpfs = require('is-ipfs')
const LRU = require('lru-cache')
const { default: PQueue } = require('p-queue')
-const { offlinePeerCount } = require('./state')
const { ipfsContentPath, sameGateway, pathAtHttpGateway } = require('./ipfs-path')
module.exports = function createDnslinkResolver (getState) {
@@ -123,7 +122,7 @@ module.exports = function createDnslinkResolver (getState) {
const state = getState()
let apiProvider
// TODO: fix DNS resolver for ipfsNodeType='embedded:chromesockets', for now use ipfs.io
- if (!state.ipfsNodeType.startsWith('embedded') && state.peerCount !== offlinePeerCount) {
+ if (state.localGwAvailable && state.apiAvailable) {
// Use gw port so it can be a GET:
// Chromium does not execute onBeforeSendHeaders for synchronous calls
// made from the same extension context as onBeforeSendHeaders
diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js
index 2ef04a551..e5698a44e 100644
--- a/add-on/src/lib/ipfs-companion.js
+++ b/add-on/src/lib/ipfs-companion.js
@@ -11,7 +11,7 @@ const pMemoize = require('p-memoize')
const LRU = require('lru-cache')
const all = require('it-all')
const { optionDefaults, storeMissingOptions, migrateOptions, guiURLString, safeURL } = require('./options')
-const { initState, offlinePeerCount } = require('./state')
+const { initState, offlinePeerCount, apiDownPeerCount } = require('./state')
const { createIpfsPathValidator, sameGateway } = require('./ipfs-path')
const createDnslinkResolver = require('./dnslink')
const { createRequestModifier } = require('./ipfs-request')
@@ -257,6 +257,7 @@ module.exports = async function init () {
importDir: state.importDir,
openViaWebUI: state.openViaWebUI,
apiURLString: dropSlash(state.apiURLString),
+ apiAvailable: state.apiAvailable,
redirect: state.redirect,
enabledOn: state.enabledOn,
disabledOn: state.disabledOn,
@@ -462,13 +463,18 @@ module.exports = async function init () {
}
async function getSwarmPeerCount () {
- if (!ipfs) return offlinePeerCount
+ if (!ipfs) return apiDownPeerCount
try {
const peerInfos = await ipfs.swarm.peers({ timeout: 2500 })
return peerInfos.length
} catch (error) {
+ if (error.message.includes('action must be run in online mode')) {
+ // node is running in offline mode (ipfs daemon --offline)
+ // https://github.com/ipfs-shipyard/ipfs-companion/issues/790
+ return offlinePeerCount // ipfs daemon --offline
+ }
console.error(`Error while ipfs.swarm.peers: ${error}`)
- return offlinePeerCount
+ return apiDownPeerCount
}
}
@@ -495,11 +501,11 @@ module.exports = async function init () {
let badgeText, badgeColor, badgeIcon
badgeText = state.peerCount.toString()
- if (state.peerCount > 0) {
+ if (state.peerCount > offlinePeerCount) {
// All is good (online with peers)
badgeColor = '#418B8E'
badgeIcon = '/icons/ipfs-logo-on.svg'
- } else if (state.peerCount === 0) {
+ } else if (state.peerCount === offlinePeerCount) {
// API is online but no peers
badgeColor = 'red'
badgeIcon = '/icons/ipfs-logo-on.svg'
@@ -578,13 +584,11 @@ module.exports = async function init () {
function updateAutomaticModeRedirectState (oldPeerCount, newPeerCount) {
// enable/disable gw redirect based on API going online or offline
- // newPeerCount === -1 currently implies node is offline.
- // TODO: use `node.isOnline()` if available (js-ipfs)
if (state.automaticMode && state.localGwAvailable) {
- if (oldPeerCount === offlinePeerCount && newPeerCount > offlinePeerCount && !state.redirect) {
+ if (oldPeerCount === apiDownPeerCount && newPeerCount > apiDownPeerCount && !state.redirect) {
browser.storage.local.set({ useCustomGateway: true })
.then(() => notify('notify_apiOnlineTitle', 'notify_apiOnlineAutomaticModeMsg'))
- } else if (newPeerCount === offlinePeerCount && state.redirect) {
+ } else if (newPeerCount === apiDownPeerCount && state.redirect) {
browser.storage.local.set({ useCustomGateway: false })
.then(() => notify('notify_apiOfflineTitle', 'notify_apiOfflineAutomaticModeMsg'))
}
diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js
index 0a6174449..769354574 100644
--- a/add-on/src/lib/state.js
+++ b/add-on/src/lib/state.js
@@ -4,7 +4,8 @@
const isFQDN = require('is-fqdn')
const { safeURL } = require('./options')
const { braveJsIpfsWebuiCid } = require('./precache')
-const offlinePeerCount = -1
+const offlinePeerCount = 0 // always the case when running: ipfs daemon --offline
+const apiDownPeerCount = -1 // unable to read, most likely API is down
function initState (options, overrides) {
// we store options and some pregenerated values to avoid async storage
@@ -48,6 +49,12 @@ function initState (options, overrides) {
// TODO: make quick fetch to confirm it works?
get: function () { return this.ipfsNodeType !== 'embedded' }
})
+ Object.defineProperty(state, 'apiAvailable', {
+ // TODO: when we move away from constantly polling in the backgroun,
+ // this can be replaced with ipfs.id check to confirm it works + memoize for ipfsApiPollMs
+ // that way there is no need for polling, api check would execute only when user actualy needs it
+ get: function () { return this.peerCount > apiDownPeerCount }
+ })
Object.defineProperty(state, 'webuiRootUrl', {
get: function () {
// Did user opt-in for rolling release published on DNSLink?
@@ -67,3 +74,4 @@ function initState (options, overrides) {
exports.initState = initState
exports.offlinePeerCount = offlinePeerCount
+exports.apiDownPeerCount = apiDownPeerCount
diff --git a/add-on/src/popup/browser-action/context-actions.js b/add-on/src/popup/browser-action/context-actions.js
index f6955f703..8957e9466 100644
--- a/add-on/src/popup/browser-action/context-actions.js
+++ b/add-on/src/popup/browser-action/context-actions.js
@@ -32,16 +32,15 @@ function contextActions ({
isPinning,
isUnPinning,
isPinned,
- isIpfsOnline,
- isApiAvailable,
+ apiAvailable,
onToggleSiteIntegrations,
onViewOnGateway,
onCopy,
onPin,
onUnPin
}) {
- const activeCidResolver = active && isIpfsOnline && isApiAvailable && currentTabCid
- const activePinControls = active && isApiAvailable
+ const activeCidResolver = active && apiAvailable && currentTabCid
+ const activePinControls = active && apiAvailable
const activeViewOnGateway = (currentTab) => {
if (!currentTab) return false
const { url } = currentTab
diff --git a/add-on/src/popup/browser-action/gateway-status.js b/add-on/src/popup/browser-action/gateway-status.js
index 2711294bb..b268ac9b5 100644
--- a/add-on/src/popup/browser-action/gateway-status.js
+++ b/add-on/src/popup/browser-action/gateway-status.js
@@ -8,7 +8,7 @@ function statusEntry ({ label, labelLegend, value, check, itemClass = '', valueC
const offline = browser.i18n.getMessage('panel_statusOffline')
label = label ? browser.i18n.getMessage(label) : null
labelLegend = labelLegend ? browser.i18n.getMessage(labelLegend) : label
- value = value || value === 0 ? value : offline
+ value = value || offline
return html`
${label}
diff --git a/add-on/src/popup/browser-action/header.js b/add-on/src/popup/browser-action/header.js
index e5fcbfe04..ab7e04927 100644
--- a/add-on/src/popup/browser-action/header.js
+++ b/add-on/src/popup/browser-action/header.js
@@ -9,7 +9,7 @@ const ipfsVersion = require('./ipfs-version')
const gatewayStatus = require('./gateway-status')
module.exports = function header (props) {
- const { ipfsNodeType, active, onToggleActive, onOpenPrefs, isIpfsOnline, onOpenWelcomePage } = props
+ const { ipfsNodeType, active, onToggleActive, onOpenPrefs, apiAvailable, onOpenWelcomePage } = props
return html`
@@ -22,7 +22,7 @@ module.exports = function header (props) {
size: 54,
path: '../../../icons',
ipfsNodeType,
- isIpfsOnline: (active && isIpfsOnline)
+ apiAvailable
})}
diff --git a/add-on/src/popup/browser-action/store.js b/add-on/src/popup/browser-action/store.js
index 6fa955ed1..acc437c1e 100644
--- a/add-on/src/popup/browser-action/store.js
+++ b/add-on/src/popup/browser-action/store.js
@@ -22,14 +22,13 @@ module.exports = (state, emitter) => {
isPinned: false,
// IPFS details
ipfsNodeType: 'external',
- isIpfsOnline: false,
+ apiAvailable: false,
ipfsApiUrl: null,
publicGatewayUrl: null,
publicSubdomainGatewayUrl: null,
gatewayAddress: null,
swarmPeers: null,
gatewayVersion: null,
- isApiAvailable: false,
// isRedirectContext
currentTab: null,
currentFqdn: null,
@@ -229,7 +228,7 @@ module.exports = (state, emitter) => {
state.ipfsApiUrl = null
state.gatewayVersion = null
state.swarmPeers = null
- state.isIpfsOnline = false
+ state.apiAvailable = false
}
try {
await browser.storage.local.set({ active: state.active })
@@ -257,7 +256,7 @@ module.exports = (state, emitter) => {
// Note: access to background page will be denied in Private Browsing mode
const ipfs = await getIpfsApi()
// There is no point in displaying actions that require API interaction if API is down
- const apiIsUp = ipfs && status && status.peerCount >= 0
+ const apiIsUp = ipfs && status && status.apiAvailable
if (apiIsUp) await updatePinnedState(ipfs, status)
}
}
@@ -273,15 +272,14 @@ module.exports = (state, emitter) => {
state.gatewayAddress = status.pubGwURLString
}
// Import requires access to the background page (https://github.com/ipfs-shipyard/ipfs-companion/issues/477)
- state.isApiAvailable = state.active && !!(await getBackgroundPage()) && !browser.extension.inIncognitoContext // https://github.com/ipfs-shipyard/ipfs-companion/issues/243
- state.swarmPeers = !state.active || status.peerCount === -1 ? null : status.peerCount
- state.isIpfsOnline = state.active && status.peerCount > -1
+ state.apiAvailable = state.active && status.apiAvailable && !!(await getBackgroundPage()) && !browser.extension.inIncognitoContext // https://github.com/ipfs-shipyard/ipfs-companion/issues/243
+ state.swarmPeers = state.apiAvailable ? status.peerCount : null
state.gatewayVersion = state.active && status.gatewayVersion ? status.gatewayVersion : null
state.ipfsApiUrl = state.active ? status.apiURLString : null
} else {
state.ipfsNodeType = 'external'
state.swarmPeers = null
- state.isIpfsOnline = false
+ state.apiAvailable = false
state.gatewayVersion = null
state.isIpfsContext = false
state.isRedirectContext = false
diff --git a/add-on/src/popup/browser-action/tools.js b/add-on/src/popup/browser-action/tools.js
index 4e43571dd..60c495d1a 100644
--- a/add-on/src/popup/browser-action/tools.js
+++ b/add-on/src/popup/browser-action/tools.js
@@ -8,13 +8,13 @@ const navItem = require('./nav-item')
module.exports = function tools ({
active,
ipfsNodeType,
- isIpfsOnline,
- isApiAvailable,
+ apiAvailable,
onQuickImport,
onOpenWebUi
}) {
- const activeQuickImport = active && isApiAvailable
- const activeWebUI = active && isApiAvailable && ipfsNodeType !== 'embedded'
+ const localGwAvailable = ipfsNodeType !== 'embedded'
+ const activeQuickImport = active && apiAvailable
+ const activeWebUI = active && apiAvailable && localGwAvailable
return html`
diff --git a/add-on/src/popup/logo.js b/add-on/src/popup/logo.js
index e2ee0da41..9853e99b0 100644
--- a/add-on/src/popup/logo.js
+++ b/add-on/src/popup/logo.js
@@ -3,14 +3,14 @@
const html = require('choo/html')
-function logo ({ path, size = 52, ipfsNodeType = 'external', isIpfsOnline = true, heartbeat = true }) {
+function logo ({ path, size = 52, ipfsNodeType = 'external', apiAvailable = true, heartbeat = true }) {
const logoTypePrefix = ipfsNodeType.startsWith('embedded') ? 'js-' : ''
- const logoFileName = `${logoTypePrefix}ipfs-logo-${isIpfsOnline ? 'on' : 'off'}.svg`
+ const logoFileName = `${logoTypePrefix}ipfs-logo-${apiAvailable ? 'on' : 'off'}.svg`
return html`
`
}
diff --git a/add-on/src/popup/page-action/header.js b/add-on/src/popup/page-action/header.js
index a660a3c92..7dd9c5923 100644
--- a/add-on/src/popup/page-action/header.js
+++ b/add-on/src/popup/page-action/header.js
@@ -13,7 +13,7 @@ module.exports = function header ({ isIpfsContext, pageActionTitle }) {
size: 20,
path: '../../../icons',
ipfsNodeType: 'external',
- isIpfsOnline: true,
+ apiAvailable: true,
heartbeat: false
})}
${pageActionTitle || '…'}
diff --git a/add-on/src/popup/quick-import.js b/add-on/src/popup/quick-import.js
index 9feac1a39..38cbc8acf 100644
--- a/add-on/src/popup/quick-import.js
+++ b/add-on/src/popup/quick-import.js
@@ -8,6 +8,7 @@ const choo = require('choo')
const html = require('choo/html')
const logo = require('./logo')
const externalApiClient = require('../lib/ipfs-client/external')
+const { offlinePeerCount } = require('../lib/state')
const all = require('it-all')
const drop = require('drag-and-drop-files')
const filesize = require('filesize')
@@ -22,7 +23,7 @@ app.mount('#root')
function quickImportStore (state, emitter) {
state.message = ''
- state.peerCount = ''
+ state.peerCount = offlinePeerCount
state.ipfsNodeType = 'external'
state.expandOptions = false
state.openViaWebUI = true