IPFS WebUI

基本信息

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/<cid> 請求
	// corehttp.WebUIPaths 包含webui的歷史版本
	gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...)
	if unrestricted {
		gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns")
	}

	var opts = []corehttp.ServeOption{
		...
		// 訪問 <host>:5001/webui 重定向到最新的webui版本
		corehttp.WebUIOption,
		gatewayOpt,
		...
	}
	...

IPFS Web UI

WebUI基於React實現,使用 js-ipfs-http-client 與後端節點交互。

WebUI 使用 Redux Bundler 管理 Redux 狀態數據。

IPFS API初始化

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 主要初始化邏輯如下:

doInitIpfsApp.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)
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章