feat: add private bee node address and postage stamp

pull/5370/head
Attila Gazso 3 years ago committed by yann300
parent cdc5c088e0
commit 527c021851
  1. 42
      libs/remix-ui/publish-to-storage/src/lib/publishOnSwarm.tsx
  2. 2
      libs/remix-ui/settings/src/lib/constants.ts
  3. 81
      libs/remix-ui/settings/src/lib/remix-ui-settings.tsx
  4. 6
      libs/remix-ui/settings/src/lib/settingsAction.ts

@ -2,12 +2,12 @@ import { Bee } from '@ethersphere/bee-js'
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import type { UploadResult } from '@ethersphere/bee-js' import type { UploadResult } from '@ethersphere/bee-js'
const beeNodes = [ // public gateway node address
new Bee('http://localhost:1633/'), // TODO should change to https://api.ethswarm.org/
new Bee('https://bee-0.gateway.ethswarm.org/') const publicBeeNode = new Bee('https://bee-9.gateway.ethswarm.org/')
]
const postageBatchId = 'b75edc084f30f76368a6a1a596c39d3d913048d20b34d00a69ddd14cb15f507f' // on the public gateway the postage stamp id is not relevant, so we use all zeroes
const defaultPostageStampId = '0000000000000000000000000000000000000000000000000000000000000000'
export const publishToSwarm = async (contract, api) => { export const publishToSwarm = async (contract, api) => {
// gather list of files to publish // gather list of files to publish
@ -55,11 +55,24 @@ export const publishToSwarm = async (contract, api) => {
console.log(error) console.log(error)
}) })
})) }))
// publish the list of sources in order, fail if any failed
// the list of nodes to publish to
const beeNodes = [
publicBeeNode
]
// add custom private Bee node to the list
const postageStampId = api.config.get('settings/swarm-postage-stamp-id') || defaultPostageStampId
const privateBeeAddress = api.config.get('settings/swarm-private-bee-address')
if (privateBeeAddress) {
const privateBee = new Bee(privateBeeAddress)
beeNodes.push(privateBee)
}
// publish the list of sources in order, fail if any failed
await Promise.all(sources.map(async (item) => { await Promise.all(sources.map(async (item) => {
try { try {
const result = await swarmVerifiedPublish(item.content, item.hash) const result = await swarmVerifiedPublish(beeNodes, postageStampId, item.content, item.hash)
try { try {
item.hash = result.url.match('bzz-raw://(.+)')[1] item.hash = result.url.match('bzz-raw://(.+)')[1]
@ -78,7 +91,7 @@ export const publishToSwarm = async (contract, api) => {
const metadataContent = JSON.stringify(metadata) const metadataContent = JSON.stringify(metadata)
try { try {
const result = await swarmVerifiedPublish(metadataContent, '') const result = await swarmVerifiedPublish(beeNodes, postageStampId, metadataContent, '')
try { try {
contract.metadataHash = result.url.match('bzz-raw://(.+)')[1] contract.metadataHash = result.url.match('bzz-raw://(.+)')[1]
@ -101,9 +114,9 @@ export const publishToSwarm = async (contract, api) => {
return { uploaded, item } return { uploaded, item }
} }
const swarmVerifiedPublish = async (content, expectedHash): Promise<Record<string, any>> => { const swarmVerifiedPublish = async (beeNodes: Bee[], postageStampId: string, content, expectedHash): Promise<Record<string, any>> => {
try { try {
const results = await uploadToBeeNodes(content) const results = await uploadToBeeNodes(beeNodes, postageStampId, content)
const hash = hashFromResults(results) const hash = hashFromResults(results)
if (expectedHash && hash !== expectedHash) { if (expectedHash && hash !== expectedHash) {
@ -125,14 +138,15 @@ const hashFromResults = (results: UploadResult[]) => {
throw new Error('no result') throw new Error('no result')
} }
const uploadToBee = async (bee, content) => { const uploadToBee = async (bee: Bee, postageStampId: string, content) => {
try { try {
return await bee.uploadData(postageBatchId, content) return await bee.uploadData(postageStampId, content)
} catch { } catch {
// ignore errors for now
return null return null
} }
} }
const uploadToBeeNodes = (content) => { const uploadToBeeNodes = (beeNodes: Bee[], postageBatchId: string, content) => {
return Promise.all(beeNodes.map((node) => uploadToBee(node, content))) return Promise.all(beeNodes.map(node => uploadToBee(node, postageBatchId, content)))
} }

@ -10,3 +10,5 @@ export const ethereunVMText = 'Always use Javascript VM at load'
export const wordWrapText = 'Word wrap in editor' export const wordWrapText = 'Word wrap in editor'
export const enablePersonalModeText = ' Enable Personal Mode for web3 provider. Transaction sent over Web3 will use the web3.personal API.\n' export const enablePersonalModeText = ' Enable Personal Mode for web3 provider. Transaction sent over Web3 will use the web3.personal API.\n'
export const matomoAnalytics = 'Enable Matomo Analytics. We do not collect personally identifiable information (PII). The info is used to improve the site’s UX & UI. See more about ' export const matomoAnalytics = 'Enable Matomo Analytics. We do not collect personally identifiable information (PII). The info is used to improve the site’s UX & UI. See more about '
export const swarmSettingsTitle = 'Swarm Settings'
export const swarmSettingsText = 'Swarm Settings'

@ -1,10 +1,10 @@
import React, { useState, useReducer, useEffect, useCallback } from 'react' // eslint-disable-line import React, { useState, useReducer, useEffect, useCallback } from 'react' // eslint-disable-line
import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line
import { enablePersonalModeText, ethereunVMText, generateContractMetadataText, gitAccessTokenLink, gitAccessTokenText, gitAccessTokenText2, gitAccessTokenTitle, matomoAnalytics, textDark, textSecondary, warnText, wordWrapText } from './constants' import { enablePersonalModeText, ethereunVMText, generateContractMetadataText, gitAccessTokenLink, gitAccessTokenText, gitAccessTokenText2, gitAccessTokenTitle, matomoAnalytics, swarmSettingsTitle, textDark, textSecondary, warnText, wordWrapText } from './constants'
import './remix-ui-settings.css' import './remix-ui-settings.css'
import { ethereumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast } from './settingsAction' import { ethereumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast, saveSwarmSettingsToast } from './settingsAction'
import { initialState, toastInitialState, toastReducer, settingReducer } from './settingsReducer' import { initialState, toastInitialState, toastReducer, settingReducer } from './settingsReducer'
import { Toaster } from '@remix-ui/toaster'// eslint-disable-line import { Toaster } from '@remix-ui/toaster'// eslint-disable-line
import { RemixUiThemeModule, ThemeModule} from '@remix-ui/theme-module' import { RemixUiThemeModule, ThemeModule} from '@remix-ui/theme-module'
@ -22,6 +22,9 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
const [, dispatch] = useReducer(settingReducer, initialState) const [, dispatch] = useReducer(settingReducer, initialState)
const [state, dispatchToast] = useReducer(toastReducer, toastInitialState) const [state, dispatchToast] = useReducer(toastReducer, toastInitialState)
const [tokenValue, setTokenValue] = useState('') const [tokenValue, setTokenValue] = useState('')
const [themeName, setThemeName] = useState('')
const [privateBeeAddress, setPrivateBeeAddress] = useState('')
const [postageStampId, setPostageStampId] = useState('')
useEffect(() => { useEffect(() => {
const token = props.config.get('settings/gist-access-token') const token = props.config.get('settings/gist-access-token')
@ -32,7 +35,15 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
if (token) { if (token) {
setTokenValue(token) setTokenValue(token)
} }
}, [state.message]) const configPrivateBeeAddress = props.config.get('settings/swarm-private-bee-address')
if (configPrivateBeeAddress) {
setPrivateBeeAddress(configPrivateBeeAddress)
}
const configPostageStampId = props.config.get('settings/swarm-postage-stamp-id')
if (configPostageStampId) {
setPostageStampId(configPostageStampId)
}
}, [themeName, state.message])
useEffect(() => { useEffect(() => {
if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch) if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch)
@ -150,12 +161,76 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
</div> </div>
) )
const handleSavePrivateBeeAddress = useCallback(
(event) => {
setPrivateBeeAddress(event.target.value)
},
[privateBeeAddress]
)
const handleSavePostageStampId = useCallback(
(event) => {
setPostageStampId(event.target.value)
},
[postageStampId]
)
const saveSwarmSettings = () => {
saveSwarmSettingsToast(props.config, dispatchToast, privateBeeAddress, postageStampId)
}
const swarmSettings = () => (
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">{ swarmSettingsTitle }</h6>
<div className=""><label>PRIVATE BEE ADDRESS:</label>
<div className="text-secondary mb-0 h6">
<input id="swarmprivatebeeaddress" data-id="settingsPrivateBeeAddress" className="form-control" onChange={handleSavePrivateBeeAddress} value={ privateBeeAddress } />
</div>
</div>
<div className=""><label>POSTAGE STAMP ID:</label>
<div className="text-secondary mb-0 h6">
<input id="swarmpostagestamp" data-id="settingsPostageStampId" className="form-control" onChange={handleSavePostageStampId} value={ postageStampId } />
<div className="d-flex justify-content-end pt-2">
</div>
</div>
</div>
<div className="d-flex justify-content-end pt-2">
<input className="btn btn-sm btn-primary ml-2" id="saveswarmsettings" data-id="settingsTabSaveSwarmSettings" onClick={() => saveSwarmSettings()} value="Save" type="button" disabled={privateBeeAddress === ''}></input>
</div>
</div>
</div>
)
const themes = () => {
const themes = props._deps.themeModule.getThemes()
if (themes) {
return themes.map((aTheme, index) => (
<div className="radio custom-control custom-radio mb-1 form-check" key={index}>
<input type="radio" onChange={event => { onswitchTheme(event, aTheme.name) }} className="align-middle custom-control-input" name='theme' id={aTheme.name} data-id={`settingsTabTheme${aTheme.name}`} checked = {props._deps.themeModule.active === aTheme.name }/>
<label className="form-check-label custom-control-label" data-id={`settingsTabThemeLabel${aTheme.name}`} htmlFor={aTheme.name}>{aTheme.name} ({aTheme.quality})</label>
</div>
)
)
}
}
return ( return (
<div> <div>
{state.message ? <Toaster message= {state.message}/> : null} {state.message ? <Toaster message= {state.message}/> : null}
{generalConfig()} {generalConfig()}
{gistToken()} {gistToken()}
{swarmSettings()}
<RemixUiThemeModule themeModule={props._deps.themeModule} /> <RemixUiThemeModule themeModule={props._deps.themeModule} />
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">Themes</h6>
<div className="card-text themes-container">
{themes()}
</div>
</div>
</div>
</div> </div>
) )
} }

@ -50,3 +50,9 @@ export const removeTokenToast = (config, dispatch) => {
config.set('settings/gist-access-token', '') config.set('settings/gist-access-token', '')
dispatch({ type: 'removed', payload: { message: 'Access token removed' } }) dispatch({ type: 'removed', payload: { message: 'Access token removed' } })
} }
export const saveSwarmSettingsToast = (config, dispatch, privateBeeAddress, postageStampId) => {
config.set('settings/swarm-private-bee-address', privateBeeAddress)
config.set('settings/swarm-postage-stamp-id', postageStampId)
dispatch({ type: 'save', payload: { message: 'Swarm settings have been saved' } })
}

Loading…
Cancel
Save