IPFS 版本:v0.4.23
WebUI 版本: v2.7.2
WebUI 使用独立仓库管理,最新版直接发布到 IPFS
网络上,在IPFS
实现代码中引用相应CID
,如在 go-ipfs
中的webui.go所示。
daemon.go
// serveHTTPApi collects options, creates listener, prints status message and starts serving requests
func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error) {
...
// 定义处理 /ipfs/ 请求
// corehttp.WebUIPaths 包含webui的历史版本
gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...)
if unrestricted {
gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns")
}
var opts = []corehttp.ServeOption{
...
// 访问 :5001/webui 重定向到最新的webui版本
corehttp.WebUIOption,
gatewayOpt,
...
}
...
WebUI
基于React
实现,使用 js-ipfs-http-client 与后端节点交互。
WebUI 使用 Redux Bundler 管理 Redux
状态数据。
index.js
...
import ipfsBundle from 'ipfs-redux-bundle'
...
export default composeBundles(
...
// ipfs api bundle
ipfsBundle({
tryWindow: false,
ipfsConnectionTest: async (ipfs) => {
// ipfs connection is working if can we fetch the bw stats.
// See: https://github.com/ipfs-shipyard/ipfs-webui/issues/835#issuecomment-466966884
try {
await ipfs.stats.bw()
} catch (err) {
if (!/bandwidth reporter disabled in config/.test(err)) {
throw err
}
}
return true
}
}),
...
ipfs-redux-bundle 主要初始化逻辑如下:
doInitIpfs
在App.js中调用
const root = require('window-or-global')
const httpClient = require('ipfs-http-client')
...
const tryApi = require('./js-ipfs-api')
...
const defaultOptions = {
tryWindow: true,
tryCompanion: true,
tryApi: true,
tryJsIpfs: false,
defaultApiAddress: '/ip4/127.0.0.1/tcp/5001',
ipfsConnectionTest: (ipfs) => {
// ipfs connection is working if can we fetch the empty directtory.
return ipfs.get('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn')
}
}
module.exports = (opts) => {
opts = Object.assign({}, defaultOptions, opts)
const defaultState = {
defaultApiAddress: opts.defaultApiAddress,
apiAddress: getUserProvidedIpfsApi(),
provider: null, // 'window.ipfs' || 'ipfs-companion' || 'js-ipfs-api' || 'js-ipfs'
failed: false,
ready: false,
invalidAddress: false
}
return {
name: 'ipfs',
...
getExtraArgs () {
return { getIpfs: () => ipfs }
},
...
doInitIpfs: () => async (store) => {
await getIpfs(opts, store)
},
...
}
}
async function getIpfs (opts, { store, getState, dispatch }) {
dispatch({ type: 'IPFS_INIT_STARTED' })
const { ipfsConnectionTest } = opts
if (opts.tryCompanion) {
...
}
if (opts.tryWindow) {
...
}
if (opts.tryApi) {
const { apiAddress, defaultApiAddress } = getState().ipfs
const { location } = root
const res = await tryApi({ apiAddress, defaultApiAddress, location, httpClient, ipfsConnectionTest })
if (res) {
return dispatch({ type: 'IPFS_INIT_FINISHED', payload: res })
}
}
if (opts.tryJsIpfs) {
...
}
dispatch({ type: 'IPFS_INIT_FAILED' })
}
tryApi
定义如下:
const toMultiaddr = require('uri-to-multiaddr')
const { isURL } = require('../utils')
const provider = 'js-ipfs-api'
// 1. Try user specified API address
// 2. Try current origin
// 3. Try default origin
async function tryApi ({ httpClient, apiAddress, defaultApiAddress, location, ipfsConnectionTest }) {
console.info('️ Customise your js-ipfs-api options by storing a `ipfsApi` object in localStorage. e.g. localStorage.setItem(\'ipfsApi\', \'/ip4/127.0.0.1/tcp/5001\')')
// Explicit custom apiAddress provided. Only try that.
if (apiAddress) {
console.log('Trying ipfs-api with custom api address', apiAddress)
return maybeApi({ apiAddress, ipfsConnectionTest, httpClient })
}
// Current origin is not localhost:5001 so try with current origin info
if (location.port !== '5001' || !location.hostname.match(/^127.0.0.1$|^localhost$/)) {
let originAddress = null
try {
originAddress = toMultiaddr(location.origin).toString()
} catch (err) {
console.log(`Failed to convert ${location.origin} to a multiaddr`)
}
if (originAddress) {
console.log('Trying ipfs-api at current origin', originAddress)
const res = await maybeApi({
apiAddress: originAddress,
apiOpts: {
protocol: location.protocol.slice(0, -1)
},
ipfsConnectionTest,
httpClient
})
if (res) return res
}
}
// ...otherwise try /ip4/127.0.0.1/tcp/5001
console.log('Trying ipfs-api', defaultApiAddress)
return maybeApi({ apiAddress: defaultApiAddress, ipfsConnectionTest, httpClient })
}
// Helper to construct and test an api client. Returns an js-ipfs-api instance or null
async function maybeApi ({ apiAddress, apiOpts, ipfsConnectionTest, httpClient }) {
const address = isURL(apiAddress) ? parseURL(apiAddress) : apiAddress
try {
const ipfs = httpClient(address, apiOpts)
await ipfsConnectionTest(ipfs)
return { ipfs, provider, apiAddress }
} catch (error) {
console.log('Failed to connect to ipfs-api', apiAddress)
}
}