mirror of https://gitlab.com/ecentrics/concordia
Browse Source
# Conflicts: # packages/concordia-app/src/components/PostList/PostListRow/index.jsx # packages/concordia-app/src/components/PostList/index.jsx # packages/concordia-app/src/components/TopicList/TopicListRow/index.jsx # packages/concordia-app/src/components/TopicList/index.jsx # packages/concordia-app/src/views/Topic/TopicCreate/index.jsx # packages/concordia-app/src/views/Topic/TopicView/index.jsxdevelop
Apostolos Fanakis
4 years ago
72 changed files with 1384 additions and 344 deletions
@ -1,14 +1,2 @@ |
|||
export const WEB3_HOST_DEFAULT = '127.0.0.1'; |
|||
export const WEB3_PORT_DEFAULT = '8545'; |
|||
export const WEB3_PORT_SOCKET_TIMEOUT_DEFAULT = 30000; |
|||
export const WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT = 3; |
|||
|
|||
export const REACT_APP_CONCORDIA_HOST_DEFAULT = '127.0.0.1'; |
|||
export const REACT_APP_CONCORDIA_PORT_DEFAULT = '7000'; |
|||
|
|||
export const REACT_APP_RENDEZVOUS_HOST_DEFAULT = '127.0.0.1'; |
|||
export const REACT_APP_RENDEZVOUS_PORT_DEFAULT = '9090'; |
|||
|
|||
export const REACT_APP_CONTRACTS_SUPPLIER_HOST_DEFAULT = '127.0.0.1'; |
|||
export const REACT_APP_CONTRACTS_SUPPLIER_PORT_DEFAULT = '8400'; |
|||
export const REACT_APP_CONTRACTS_VERSION_HASH_DEFAULT = 'latest'; |
|||
export const CONCORDIA_HOST_DEFAULT = '127.0.0.1'; |
|||
export const CONCORDIA_PORT_DEFAULT = '7000'; |
|||
|
@ -1,11 +0,0 @@ |
|||
export const FORUM_CONTRACT = 'Forum'; |
|||
export const POST_VOTING_CONTRACT = 'PostVoting'; |
|||
export const VOTING_CONTRACT = 'Voting'; |
|||
|
|||
const CONTRACTS = [ |
|||
FORUM_CONTRACT, |
|||
POST_VOTING_CONTRACT, |
|||
VOTING_CONTRACT, |
|||
]; |
|||
|
|||
export default CONTRACTS; |
@ -1,13 +0,0 @@ |
|||
export const USER_SIGNED_UP_EVENT = 'UserSignedUp'; |
|||
export const USERNAME_UPDATED_EVENT = 'UsernameUpdated'; |
|||
export const TOPIC_CREATED_EVENT = 'TopicCreated'; |
|||
export const POST_CREATED_EVENT = 'PostCreated'; |
|||
|
|||
const forumContractEvents = [ |
|||
USER_SIGNED_UP_EVENT, |
|||
USERNAME_UPDATED_EVENT, |
|||
TOPIC_CREATED_EVENT, |
|||
POST_CREATED_EVENT, |
|||
]; |
|||
|
|||
export default forumContractEvents; |
@ -1,8 +0,0 @@ |
|||
import { FORUM_CONTRACT } from '../ContractNames'; |
|||
import forumContractEvents from './ForumContractEvents'; |
|||
|
|||
const appEvents = { |
|||
[FORUM_CONTRACT]: forumContractEvents, |
|||
}; |
|||
|
|||
export default appEvents; |
@ -1,40 +0,0 @@ |
|||
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider'; |
|||
import databases from '../constants/orbit/OrbitDatabases'; |
|||
import { |
|||
REACT_APP_RENDEZVOUS_HOST_DEFAULT, |
|||
REACT_APP_RENDEZVOUS_PORT_DEFAULT, |
|||
} from '../constants/configuration/defaults'; |
|||
|
|||
const REACT_APP_RENDEZVOUS_HOST = process.env.REACT_APP_RENDEZVOUS_HOST || REACT_APP_RENDEZVOUS_HOST_DEFAULT; |
|||
const REACT_APP_RENDEZVOUS_PORT = process.env.REACT_APP_RENDEZVOUS_PORT || REACT_APP_RENDEZVOUS_PORT_DEFAULT; |
|||
|
|||
const breezeOptions = { |
|||
ipfs: { |
|||
repo: 'concordia', |
|||
config: { |
|||
Addresses: { |
|||
Swarm: [ |
|||
// Use local signaling server (see also rendezvous script in package.json)
|
|||
// For more information: https://github.com/libp2p/js-libp2p-webrtc-star
|
|||
`/ip4/${REACT_APP_RENDEZVOUS_HOST}/tcp/${REACT_APP_RENDEZVOUS_PORT}/wss/p2p-webrtc-star`, |
|||
|
|||
// Use the following public servers if needed
|
|||
// '/dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star',
|
|||
// '/dns4/ wrtc-star2.sjc.dwebops.pub/tcp/443/wss/p2p-webrtc-star'
|
|||
], |
|||
}, |
|||
}, |
|||
preload: { |
|||
enabled: false, |
|||
}, |
|||
init: { |
|||
emptyRepo: true, |
|||
}, |
|||
}, |
|||
orbit: { |
|||
identityProvider: EthereumContractIdentityProvider, |
|||
databases, |
|||
}, |
|||
}; |
|||
|
|||
export default breezeOptions; |
@ -1,29 +0,0 @@ |
|||
import Web3 from 'web3'; |
|||
import { |
|||
WEB3_HOST_DEFAULT, |
|||
WEB3_PORT_DEFAULT, |
|||
WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT, |
|||
WEB3_PORT_SOCKET_TIMEOUT_DEFAULT, |
|||
} from '../constants/configuration/defaults'; |
|||
|
|||
const { WEB3_HOST, WEB3_PORT, WEBSOCKET_TIMEOUT } = process.env; |
|||
|
|||
const web3WebsocketOptions = { |
|||
keepAlive: true, |
|||
timeout: WEBSOCKET_TIMEOUT !== undefined ? WEBSOCKET_TIMEOUT : WEB3_PORT_SOCKET_TIMEOUT_DEFAULT, |
|||
reconnect: { |
|||
maxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT, |
|||
}, |
|||
}; |
|||
|
|||
const web3 = (WEB3_HOST !== undefined && WEB3_PORT !== undefined) |
|||
? new Web3(new Web3.providers.WebsocketProvider(`ws://${WEB3_HOST}:${WEB3_PORT}`)) |
|||
: new Web3(Web3.givenProvider || new Web3.providers.WebsocketProvider( |
|||
`ws://${WEB3_HOST_DEFAULT}:${WEB3_PORT_DEFAULT}`, web3WebsocketOptions, |
|||
)); |
|||
|
|||
const web3Options = { |
|||
customProvider: web3, |
|||
}; |
|||
|
|||
export default web3Options; |
@ -1,11 +1,9 @@ |
|||
import path from 'path'; |
|||
|
|||
const PROVIDER_PORT = '8400'; |
|||
const UPLOAD_CONTRACTS_DIRECTORY = path.join(__dirname, '..', 'contracts-uploads'); |
|||
const CORS_ALLOWED_ORIGINS = ['http://127.0.0.1:7000', 'http://localhost:7000']; |
|||
|
|||
export default { |
|||
port: PROVIDER_PORT, |
|||
uploadsDirectory: UPLOAD_CONTRACTS_DIRECTORY, |
|||
corsAllowedOrigins: CORS_ALLOWED_ORIGINS, |
|||
}; |
|||
|
@ -1,21 +0,0 @@ |
|||
const DEVELOP_CHAIN_HOST_DEFAULT = '127.0.0.1'; |
|||
const DEVELOP_CHAIN_PORT_DEFAULT = '8545'; |
|||
|
|||
const TEST_CHAIN_HOST_DEFAULT = '127.0.0.1'; |
|||
const TEST_CHAIN_PORT_DEFAULT = '8546'; |
|||
|
|||
const CONTRACTS_PROVIDER_HOST_DEFAULT = '127.0.0.1'; |
|||
const CONTRACTS_PROVIDER_PORT_DEFAULT = '8400'; |
|||
|
|||
module.exports = { |
|||
develop: { |
|||
chainHost: DEVELOP_CHAIN_HOST_DEFAULT, |
|||
chainPort: DEVELOP_CHAIN_PORT_DEFAULT, |
|||
}, |
|||
test: { |
|||
chainHost: TEST_CHAIN_HOST_DEFAULT, |
|||
chainPort: TEST_CHAIN_PORT_DEFAULT, |
|||
}, |
|||
contractsProviderHost: CONTRACTS_PROVIDER_HOST_DEFAULT, |
|||
contractsProviderPort: CONTRACTS_PROVIDER_PORT_DEFAULT, |
|||
}; |
@ -0,0 +1,60 @@ |
|||
module.exports = { |
|||
env: { |
|||
browser: true, |
|||
es6: true, |
|||
jest: true, |
|||
}, |
|||
extends: [ |
|||
'plugin:react/recommended', |
|||
'airbnb', |
|||
], |
|||
globals: { |
|||
Atomics: 'readonly', |
|||
SharedArrayBuffer: 'readonly', |
|||
}, |
|||
parser: 'babel-eslint', |
|||
parserOptions: { |
|||
ecmaFeatures: { |
|||
jsx: true, |
|||
}, |
|||
ecmaVersion: 2018, |
|||
sourceType: 'module', |
|||
}, |
|||
plugins: [ |
|||
'react', |
|||
'react-hooks', |
|||
], |
|||
rules: { |
|||
'react/jsx-props-no-spreading': 'off', |
|||
'import/extensions': 'off', |
|||
'react/jsx-indent': [ |
|||
'error', |
|||
4, |
|||
{ |
|||
checkAttributes: true, |
|||
indentLogicalExpressions: true, |
|||
}, |
|||
], |
|||
'react/require-default-props': 'off', |
|||
'react/prop-types': 'off', |
|||
'react-hooks/rules-of-hooks': 'error', |
|||
'react-hooks/exhaustive-deps': 'error', |
|||
'max-len': ['warn', { code: 120, tabWidth: 4 }], |
|||
'no-unused-vars': 'warn', |
|||
'no-console': 'off', |
|||
'no-shadow': 'warn', |
|||
'no-multi-str': 'warn', |
|||
'jsx-a11y/label-has-associated-control': [2, { |
|||
labelAttributes: ['label'], |
|||
controlComponents: ['Input'], |
|||
depth: 3, |
|||
}], |
|||
}, |
|||
settings: { |
|||
'import/resolver': { |
|||
node: { |
|||
extensions: ['.js', '.jsx'], |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
@ -0,0 +1,10 @@ |
|||
# Set the default behavior, in case people don't have core.autocrlf set. |
|||
* text=auto eol=lf |
|||
|
|||
# Denote all files that are truly binary and should not be modified. |
|||
*.png binary |
|||
*.jpg binary |
|||
*.ico binary |
|||
|
|||
# Solidity |
|||
*.sol linguist-language=Solidity |
@ -0,0 +1,40 @@ |
|||
# Node |
|||
/node_modules |
|||
packages/*/node_modules |
|||
packages/concordia-contracts/build |
|||
|
|||
# IDE |
|||
.DS_Store |
|||
.idea |
|||
|
|||
# Build Directories |
|||
/build |
|||
/src/build |
|||
/packages/concordia-app/build |
|||
/packages/concordia-contracts/build |
|||
|
|||
# Logs |
|||
/log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Docker volumes |
|||
docker/volumes |
|||
docker/ganache/volumes |
|||
docker/reports |
|||
|
|||
# Env var files |
|||
docker/env/concordia.env |
|||
docker/env/contracts.env |
|||
|
|||
# Misc |
|||
.env.local |
|||
.env.development.local |
|||
.env.test.local |
|||
.env.production.local |
|||
|
|||
# IPFS & OrbitDB Storage |
|||
ipfs |
|||
orbitdb |
|||
|
@ -0,0 +1,39 @@ |
|||
{ |
|||
"name": "concordia-pinner", |
|||
"description": "An OrbitDB pinning service for Concordia.", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"main": "src/index.js", |
|||
"scripts": { |
|||
"start": "node -r esm src/index.js", |
|||
"clean": "rimraf ipfs orbitdb", |
|||
"lint": "eslint --ext js,jsx . --format table" |
|||
}, |
|||
"license": "MIT", |
|||
"dependencies": { |
|||
"@ezerous/eth-identity-provider": "~0.1.2", |
|||
"concordia-contracts": "~0.1.0", |
|||
"concordia-shared": "~0.1.0", |
|||
"esm": "~3.2.25", |
|||
"express": "^4.17.1", |
|||
"ipfs": "~0.52.1", |
|||
"is-reachable": "^5.0.0", |
|||
"level": "~6.0.1", |
|||
"libp2p": "~0.30.0", |
|||
"libp2p-bootstrap": "~0.12.1", |
|||
"libp2p-gossipsub": "~0.8.0", |
|||
"libp2p-kad-dht": "~0.20.1", |
|||
"libp2p-mdns": "~0.15.0", |
|||
"libp2p-mplex": "~0.10.0", |
|||
"libp2p-noise": "~2.0.1", |
|||
"libp2p-tcp": "~0.15.1", |
|||
"libp2p-webrtc-star": "~0.20.2", |
|||
"lodash": "^4.17.20", |
|||
"orbit-db": "~0.26.0", |
|||
"orbit-db-identity-provider": "~0.3.1", |
|||
"rimraf": "~3.0.2", |
|||
"web3": "~1.3.0", |
|||
"web3-eth-contract": "^1.3.1", |
|||
"wrtc": "~0.4.6" |
|||
} |
|||
} |
@ -0,0 +1,63 @@ |
|||
import express from 'express'; |
|||
import _ from 'lodash'; |
|||
import isReachable from 'is-reachable'; |
|||
import { pinnerApiPort } from 'concordia-shared/src/environment/interpolated/pinner'; |
|||
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3'; |
|||
import getRendezvousUrl from 'concordia-shared/src/utils/rendezvous'; |
|||
|
|||
const POLLING_INTERVAL = 1000; |
|||
|
|||
const responseBody = { |
|||
ipfs: { |
|||
id: '', localAddresses: [], peers: [], totalPeers: 0, repoStats: {}, |
|||
}, |
|||
orbit: { identity: {}, databases: [] }, |
|||
web3: { url: getWeb3ProviderUrl(), reachable: false }, |
|||
rendezvous: { url: getRendezvousUrl(), reachable: false }, |
|||
timestamp: 0, |
|||
}; |
|||
|
|||
async function getStats(orbit) { |
|||
try { |
|||
// eslint-disable-next-line no-underscore-dangle
|
|||
const ipfs = orbit._ipfs; |
|||
const { id } = await ipfs.id(); |
|||
const peers = await ipfs.swarm.peers(); |
|||
const localAddresses = await ipfs.swarm.localAddrs(); |
|||
const repoStats = await ipfs.stats.repo(); |
|||
const uniquePeers = _.uniqBy(peers, 'peer'); |
|||
const orbitIdentity = orbit.identity; |
|||
const databases = Object.keys(orbit.stores); |
|||
const isWeb3Reachable = await isReachable(getWeb3ProviderUrl()); |
|||
const isRendezvousReachable = await isReachable(getRendezvousUrl()); |
|||
const timestamp = +new Date(); |
|||
|
|||
responseBody.ipfs.id = id; |
|||
responseBody.ipfs.peers = uniquePeers; |
|||
responseBody.ipfs.totalPeers = uniquePeers.length; |
|||
responseBody.ipfs.localAddresses = localAddresses; |
|||
responseBody.ipfs.repoStats = repoStats; |
|||
responseBody.orbit.identity = orbitIdentity; |
|||
responseBody.orbit.databases = databases; |
|||
responseBody.web3.reachable = isWeb3Reachable; |
|||
responseBody.rendezvous.reachable = isRendezvousReachable; |
|||
responseBody.timestamp = timestamp; |
|||
} catch (err) { |
|||
console.error('Error while getting stats:', err); |
|||
} |
|||
} |
|||
|
|||
const startAPI = (orbit) => { |
|||
const app = express(); |
|||
app.get('/', async (req, res) => { |
|||
res.send(responseBody); |
|||
}); |
|||
|
|||
app.listen(pinnerApiPort, () => { |
|||
console.log(`Pinner API at http://localhost:${pinnerApiPort}!`); |
|||
}); |
|||
|
|||
setInterval(getStats, POLLING_INTERVAL, orbit); |
|||
}; |
|||
|
|||
export default startAPI; |
@ -0,0 +1,6 @@ |
|||
import path from 'path'; |
|||
import getBreezeConfiguration from 'concordia-shared/src/configuration/breezeConfiguration'; |
|||
|
|||
export const swarmAddresses = getBreezeConfiguration().ipfs.config.Addresses.Swarm; |
|||
|
|||
export const ORBIT_DIRECTORY_DEFAULT = path.join(__dirname, '..', 'orbitdb'); |
@ -0,0 +1,80 @@ |
|||
import Web3 from 'web3'; |
|||
import Contract from 'web3-eth-contract'; |
|||
import IPFS from 'ipfs'; |
|||
import { contracts } from 'concordia-contracts'; |
|||
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; |
|||
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3'; |
|||
import { createOrbitInstance, getPeerDatabases, openKVDBs } from './utils/orbitUtils'; |
|||
import ipfsOptions from './options/ipfsOptions'; |
|||
import startAPI from './app'; |
|||
|
|||
process.on('unhandledRejection', (error) => { |
|||
// This happens when attempting to initialize without any available Swarm addresses (e.g. Rendezvous)
|
|||
if (error.code === 'ERR_NO_VALID_ADDRESSES') { |
|||
console.error('unhandledRejection', error.message); |
|||
process.exit(1); |
|||
} |
|||
|
|||
// Don't swallow other errors
|
|||
console.error(error); |
|||
throw error; |
|||
}); |
|||
|
|||
const getDeployedContract = async (web3) => { |
|||
const forumContract = contracts.find((contract) => contract.contractName === FORUM_CONTRACT); |
|||
|
|||
return web3.eth.net.getId() |
|||
.then((networkId) => forumContract.networks[networkId].address) |
|||
.then((contractAddress) => { |
|||
Contract.setProvider(getWeb3ProviderUrl()); |
|||
const contract = new Contract(forumContract.abi, contractAddress); |
|||
|
|||
return { contract, contractAddress }; |
|||
}); |
|||
}; |
|||
|
|||
// Open & replicate databases of existing users
|
|||
const openExistingUsersDatabases = async (contract, orbit) => contract.methods.getUserAddresses().call() |
|||
.then((userAddresses) => getPeerDatabases(orbit, userAddresses)) |
|||
.then((peerDBs) => openKVDBs(orbit, peerDBs)); |
|||
|
|||
const handleWeb3LogEvent = (web3, eventJsonInterface, orbit) => (error, result) => { |
|||
if (!error) { |
|||
const eventObj = web3.eth.abi.decodeLog( |
|||
eventJsonInterface.inputs, |
|||
result.data, |
|||
result.topics.slice(1), |
|||
); |
|||
const userAddress = eventObj[1]; |
|||
console.log('User signed up:', userAddress); |
|||
getPeerDatabases(orbit, [userAddress]) |
|||
.then((peerDBs) => openKVDBs(orbit, peerDBs)); |
|||
} |
|||
}; |
|||
|
|||
const main = async () => { |
|||
console.log('Initializing...'); |
|||
const web3 = new Web3(new Web3.providers.WebsocketProvider(getWeb3ProviderUrl())); |
|||
|
|||
getDeployedContract(web3) |
|||
.then(({ contract, contractAddress }) => IPFS.create(ipfsOptions) |
|||
.then((ipfs) => createOrbitInstance(ipfs, contractAddress)) |
|||
.then((orbit) => openExistingUsersDatabases(contract, orbit) |
|||
.then(() => { |
|||
// Listen for new users and subscribe to their databases
|
|||
const eventJsonInterface = web3.utils._.find( |
|||
// eslint-disable-next-line no-underscore-dangle
|
|||
contract._jsonInterface, |
|||
(obj) => obj.name === 'UserSignedUp' && obj.type === 'event', |
|||
); |
|||
|
|||
web3.eth.subscribe('logs', { |
|||
address: contractAddress, |
|||
topics: [eventJsonInterface.signature], |
|||
}, handleWeb3LogEvent(web3, eventJsonInterface, orbit)); |
|||
|
|||
startAPI(orbit); |
|||
}))); |
|||
}; |
|||
|
|||
main(); |
@ -0,0 +1,22 @@ |
|||
import libp2pBundle from './libp2pBundle'; |
|||
import { swarmAddresses } from '../constants'; |
|||
|
|||
export default { |
|||
repo: 'ipfs', |
|||
config: { |
|||
Profile: 'server', |
|||
Addresses: { |
|||
Swarm: swarmAddresses, |
|||
}, |
|||
}, |
|||
libp2p: libp2pBundle, |
|||
EXPERIMENTAL: { |
|||
pubsub: true, |
|||
}, |
|||
preload: { |
|||
enabled: false, |
|||
}, |
|||
init: { |
|||
emptyRepo: true, |
|||
}, |
|||
}; |
@ -0,0 +1,90 @@ |
|||
import Libp2p from 'libp2p'; |
|||
import wrtc from 'wrtc'; |
|||
import MulticastDNS from 'libp2p-mdns'; |
|||
import WebrtcStar from 'libp2p-webrtc-star'; |
|||
import Bootstrap from 'libp2p-bootstrap'; |
|||
import Gossipsub from 'libp2p-gossipsub'; |
|||
import KadDHT from 'libp2p-kad-dht'; |
|||
import MPLEX from 'libp2p-mplex'; |
|||
import { NOISE } from 'libp2p-noise'; |
|||
import { swarmAddresses } from '../constants'; |
|||
|
|||
// See also: https://github.com/libp2p/js-libp2p/blob/master/doc/CONFIGURATION.md
|
|||
export default (opts) => new Libp2p({ |
|||
peerId: opts.peerId, |
|||
addresses: { |
|||
listen: swarmAddresses, |
|||
}, |
|||
connectionManager: { |
|||
minPeers: 25, |
|||
maxPeers: 100, |
|||
pollInterval: 5000, |
|||
}, |
|||
modules: { |
|||
transport: [ |
|||
WebrtcStar, |
|||
], |
|||
streamMuxer: [ |
|||
MPLEX, |
|||
], |
|||
connEncryption: [ |
|||
NOISE, |
|||
], |
|||
peerDiscovery: [ |
|||
MulticastDNS, |
|||
Bootstrap, |
|||
], |
|||
dht: KadDHT, |
|||
pubsub: Gossipsub, |
|||
}, |
|||
config: { |
|||
transport: { |
|||
[WebrtcStar.prototype[Symbol.toStringTag]]: { |
|||
wrtc, |
|||
}, |
|||
}, |
|||
peerDiscovery: { |
|||
autoDial: true, |
|||
mdns: { |
|||
enabled: true, |
|||
interval: 10000, |
|||
}, |
|||
bootstrap: { |
|||
enabled: true, |
|||
interval: 30e3, |
|||
list: opts.config.Bootstrap, |
|||
}, |
|||
}, |
|||
relay: { |
|||
enabled: true, |
|||
hop: { |
|||
enabled: true, |
|||
active: true, |
|||
}, |
|||
}, |
|||
dht: { |
|||
enabled: true, |
|||
kBucketSize: 20, |
|||
randomWalk: { |
|||
enabled: true, |
|||
interval: 10e3, |
|||
timeout: 2e3, |
|||
}, |
|||
}, |
|||
pubsub: { |
|||
enabled: true, |
|||
emitself: true, |
|||
}, |
|||
}, |
|||
metrics: { |
|||
enabled: true, |
|||
computeThrottleMaxQueueSize: 1000, |
|||
computeThrottleTimeout: 2000, |
|||
movingAverageIntervals: [ |
|||
60 * 1000, // 1 minute
|
|||
5 * 60 * 1000, // 5 minutes
|
|||
15 * 60 * 1000, // 15 minutes
|
|||
], |
|||
maxOldPeersRetention: 50, |
|||
}, |
|||
}); |
@ -0,0 +1,46 @@ |
|||
import OrbitDB from 'orbit-db'; |
|||
import Identities from 'orbit-db-identity-provider'; |
|||
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider'; |
|||
import Web3 from 'web3'; |
|||
import { ORBIT_DIRECTORY_DEFAULT } from '../constants'; |
|||
|
|||
// TODO: share code below with frontend (?)
|
|||
const determineDBAddress = async ({ |
|||
orbit, dbName, type, identityId, |
|||
}) => orbit.determineAddress(dbName, type, { accessController: { write: [identityId] } }) |
|||
.then((orbitAddress) => { |
|||
const ipfsMultihash = orbitAddress.root; |
|||
return `/orbitdb/${ipfsMultihash}/${dbName}`; |
|||
}); |
|||
|
|||
const determineKVAddress = async ({ orbit, dbName, userAddress }) => determineDBAddress({ |
|||
orbit, dbName, type: 'keyvalue', identityId: userAddress + EthereumContractIdentityProvider.contractAddress, |
|||
}); |
|||
|
|||
export const createOrbitInstance = async (ipfs, contractAddress) => { |
|||
Identities.addIdentityProvider(EthereumContractIdentityProvider); |
|||
|
|||
EthereumContractIdentityProvider.setWeb3(new Web3()); // We need a fully-featured new Web3 for signature verification
|
|||
EthereumContractIdentityProvider.setContractAddress(contractAddress); |
|||
|
|||
const ORBIT_DIRECTORY = process.env.ORBIT_DIRECTORY || ORBIT_DIRECTORY_DEFAULT; |
|||
|
|||
return OrbitDB.createInstance(ipfs, { directory: ORBIT_DIRECTORY }); |
|||
}; |
|||
|
|||
export const getPeerDatabases = async (orbit, userAddresses) => Promise.all(userAddresses |
|||
.flatMap((userAddress) => [ |
|||
determineKVAddress({ orbit, dbName: 'user', userAddress }), |
|||
determineKVAddress({ orbit, dbName: 'posts', userAddress }), |
|||
determineKVAddress({ orbit, dbName: 'topics', userAddress }), |
|||
])); |
|||
|
|||
export const openKVDBs = async (orbit, databases) => { |
|||
databases |
|||
.forEach((database) => { |
|||
orbit |
|||
.keyvalue(database) |
|||
.then((store) => store.events.on('replicated', (address) => console.log(`Replicated ${address}`))); |
|||
console.log(`Opened ${database}`); |
|||
}); |
|||
}; |
@ -0,0 +1,60 @@ |
|||
module.exports = { |
|||
'env': { |
|||
'browser': true, |
|||
'es6': true, |
|||
'jest': true |
|||
}, |
|||
'extends': [ |
|||
'plugin:react/recommended', |
|||
'airbnb' |
|||
], |
|||
'globals': { |
|||
'Atomics': 'readonly', |
|||
'SharedArrayBuffer': 'readonly' |
|||
}, |
|||
parser: 'babel-eslint', |
|||
'parserOptions': { |
|||
'ecmaFeatures': { |
|||
'jsx': true |
|||
}, |
|||
'ecmaVersion': 2018, |
|||
'sourceType': 'module' |
|||
}, |
|||
'plugins': [ |
|||
'react', |
|||
'react-hooks', |
|||
], |
|||
'rules': { |
|||
'react/jsx-props-no-spreading': 'off', |
|||
'import/extensions': 'off', |
|||
"react/jsx-indent": [ |
|||
'error', |
|||
4, |
|||
{ |
|||
checkAttributes: true, |
|||
indentLogicalExpressions: true |
|||
} |
|||
], |
|||
'react/require-default-props': 'off', |
|||
'react/prop-types': 'off', |
|||
'react-hooks/rules-of-hooks': 'error', |
|||
'react-hooks/exhaustive-deps': 'error', |
|||
'max-len': ['warn', {'code': 120, 'tabWidth': 4}], |
|||
'no-unused-vars': 'warn', |
|||
'no-console': 'warn', |
|||
'no-shadow': 'warn', |
|||
"no-multi-str": "warn", |
|||
"jsx-a11y/label-has-associated-control": [ 2, { |
|||
"labelAttributes": ["label"], |
|||
"controlComponents": ["Input"], |
|||
"depth": 3, |
|||
}], |
|||
}, |
|||
'settings': { |
|||
'import/resolver': { |
|||
'node': { |
|||
'extensions': ['.js', '.jsx'] |
|||
} |
|||
} |
|||
}, |
|||
}; |
@ -0,0 +1,16 @@ |
|||
{ |
|||
"name": "concordia-shared", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"lint": "eslint --ext js,jsx . --format table" |
|||
}, |
|||
"devDependencies": { |
|||
"eslint": "^6.8.0", |
|||
"eslint-config-airbnb": "^18.1.0", |
|||
"eslint-plugin-import": "^2.20.2", |
|||
"eslint-plugin-jsx-a11y": "^6.2.3", |
|||
"eslint-plugin-react": "^7.19.0", |
|||
"eslint-plugin-react-hooks": "^4.2.0" |
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
const { databases } = require('../constants/orbit/OrbitDatabases'); |
|||
const { rendezvousHost, rendezvousPort } = require('../environment/interpolated/rendezvous'); |
|||
|
|||
const getBreezeConfiguration = (identityProvider) => ({ |
|||
ipfs: { |
|||
repo: 'concordia', |
|||
config: { |
|||
Addresses: { |
|||
Swarm: [ |
|||
// Use local signaling server (see also rendezvous script in package.json)
|
|||
// For more information: https://github.com/libp2p/js-libp2p-webrtc-star
|
|||
`/ip4/${rendezvousHost}/tcp/${rendezvousPort}/wss/p2p-webrtc-star`, |
|||
|
|||
// Use the following public servers if needed
|
|||
// '/dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star',
|
|||
// '/dns4/ wrtc-star2.sjc.dwebops.pub/tcp/443/wss/p2p-webrtc-star'
|
|||
], |
|||
}, |
|||
}, |
|||
preload: { |
|||
enabled: false, |
|||
}, |
|||
init: { |
|||
emptyRepo: true, |
|||
}, |
|||
}, |
|||
orbit: { |
|||
identityProvider, |
|||
databases, |
|||
}, |
|||
}); |
|||
|
|||
module.exports = getBreezeConfiguration; |
@ -0,0 +1,25 @@ |
|||
const getWeb3ProviderUrl = require('../utils/web3'); |
|||
const { web3PortSocketConnectMaxAttempts, web3PortSocketTimeout } = require('../environment/interpolated/web3'); |
|||
const { web3HostEnv, web3PortEnv } = require('../environment/web3Env'); |
|||
|
|||
const getWeb3Configuration = (Web3) => { |
|||
const web3WebsocketOptions = { |
|||
keepAlive: true, |
|||
timeout: web3PortSocketTimeout, |
|||
reconnect: { |
|||
maxAttempts: web3PortSocketConnectMaxAttempts, |
|||
}, |
|||
}; |
|||
|
|||
const web3 = (web3HostEnv !== undefined && web3PortEnv !== undefined) |
|||
? new Web3(new Web3.providers.WebsocketProvider(getWeb3ProviderUrl())) |
|||
: new Web3(Web3.givenProvider || new Web3.providers.WebsocketProvider(getWeb3ProviderUrl(), web3WebsocketOptions)); |
|||
|
|||
return { |
|||
customProvider: web3, |
|||
}; |
|||
}; |
|||
|
|||
module.exports = { |
|||
getWeb3Configuration, |
|||
}; |
@ -0,0 +1,46 @@ |
|||
// Contracts provider
|
|||
const CONTRACTS_PROVIDER_HOST_DEFAULT = '127.0.0.1'; |
|||
const CONTRACTS_PROVIDER_PORT_DEFAULT = '8400'; |
|||
const CONTRACTS_VERSION_HASH_DEFAULT = 'latest'; |
|||
|
|||
// Pinner
|
|||
const PINNER_API_PORT_DEFAULT = 4444; |
|||
|
|||
// Rendezvous
|
|||
const RENDEZVOUS_HOST_DEFAULT = '127.0.0.1'; |
|||
const RENDEZVOUS_PORT_DEFAULT = '9090'; |
|||
|
|||
// Web3 (probably ganache)
|
|||
const WEB3_HOST_DEFAULT = '127.0.0.1'; |
|||
const WEB3_PORT_DEFAULT = '8545'; |
|||
const WEB3_HOST_TEST_DEFAULT = '127.0.0.1'; |
|||
const WEB3_PORT_TEST_DEFAULT = '8546'; |
|||
const WEB3_PORT_SOCKET_TIMEOUT_DEFAULT = 30000; |
|||
const WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT = 3; |
|||
|
|||
module.exports = Object.freeze({ |
|||
contractsProvider: { |
|||
host: CONTRACTS_PROVIDER_HOST_DEFAULT, |
|||
port: CONTRACTS_PROVIDER_PORT_DEFAULT, |
|||
hash: CONTRACTS_VERSION_HASH_DEFAULT, |
|||
}, |
|||
pinner: { |
|||
port: PINNER_API_PORT_DEFAULT, |
|||
}, |
|||
rendezvous: { |
|||
host: RENDEZVOUS_HOST_DEFAULT, |
|||
port: RENDEZVOUS_PORT_DEFAULT, |
|||
}, |
|||
web3: { |
|||
develop: { |
|||
chainHost: WEB3_HOST_DEFAULT, |
|||
chainPort: WEB3_PORT_DEFAULT, |
|||
}, |
|||
test: { |
|||
chainHost: WEB3_HOST_TEST_DEFAULT, |
|||
chainPort: WEB3_PORT_TEST_DEFAULT, |
|||
}, |
|||
socketTimeout: WEB3_PORT_SOCKET_TIMEOUT_DEFAULT, |
|||
socketConnectMaxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT, |
|||
}, |
|||
}); |
@ -0,0 +1,16 @@ |
|||
const FORUM_CONTRACT = 'Forum'; |
|||
const POST_VOTING_CONTRACT = 'PostVoting'; |
|||
const VOTING_CONTRACT = 'Voting'; |
|||
|
|||
const CONTRACTS = [ |
|||
FORUM_CONTRACT, |
|||
POST_VOTING_CONTRACT, |
|||
VOTING_CONTRACT, |
|||
]; |
|||
|
|||
module.exports = Object.freeze({ |
|||
FORUM_CONTRACT, |
|||
POST_VOTING_CONTRACT, |
|||
VOTING_CONTRACT, |
|||
CONTRACTS, |
|||
}); |
@ -0,0 +1,19 @@ |
|||
const USER_SIGNED_UP_EVENT = 'UserSignedUp'; |
|||
const USERNAME_UPDATED_EVENT = 'UsernameUpdated'; |
|||
const TOPIC_CREATED_EVENT = 'TopicCreated'; |
|||
const POST_CREATED_EVENT = 'PostCreated'; |
|||
|
|||
const forumContractEvents = Object.freeze([ |
|||
USER_SIGNED_UP_EVENT, |
|||
USERNAME_UPDATED_EVENT, |
|||
TOPIC_CREATED_EVENT, |
|||
POST_CREATED_EVENT, |
|||
]); |
|||
|
|||
module.exports = { |
|||
USER_SIGNED_UP_EVENT, |
|||
USERNAME_UPDATED_EVENT, |
|||
TOPIC_CREATED_EVENT, |
|||
POST_CREATED_EVENT, |
|||
forumContractEvents, |
|||
}; |
@ -0,0 +1,8 @@ |
|||
const forumContractEvents = require('./ForumContractEvents'); |
|||
const { FORUM_CONTRACT } = require('../ContractNames'); |
|||
|
|||
const appEvents = Object.freeze({ |
|||
[FORUM_CONTRACT]: forumContractEvents, |
|||
}); |
|||
|
|||
module.exports = appEvents; |
@ -0,0 +1,14 @@ |
|||
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
|
|||
// the REACT_APP_ prefix or not
|
|||
const contractsProviderHostEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_HOST |
|||
|| process.env.CONTRACTS_PROVIDER_HOST; |
|||
const contractsProviderPortEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_PORT |
|||
|| process.env.CONTRACTS_PROVIDER_PORT; |
|||
const contractsVersionHashEnv = process.env.REACT_APP_CONTRACTS_VERSION_HASH |
|||
|| process.env.CONTRACTS_VERSION_HASH; |
|||
|
|||
module.exports = { |
|||
contractsProviderHostEnv, |
|||
contractsProviderPortEnv, |
|||
contractsVersionHashEnv, |
|||
}; |
@ -0,0 +1,21 @@ |
|||
const { |
|||
contractsProviderHostEnv, contractsProviderPortEnv, contractsVersionHashEnv, |
|||
} = require('../contractsProviderEnv'); |
|||
|
|||
const { |
|||
contractsProvider: { |
|||
host: CONTRACTS_PROVIDER_HOST_DEFAULT, |
|||
port: CONTRACTS_PROVIDER_PORT_DEFAULT, |
|||
hash: CONTRACTS_VERSION_HASH_DEFAULT, |
|||
}, |
|||
} = require('../../constants/configuration/defaults'); |
|||
|
|||
const contractsProviderHost = contractsProviderHostEnv || CONTRACTS_PROVIDER_HOST_DEFAULT; |
|||
const contractsProviderPort = contractsProviderPortEnv || CONTRACTS_PROVIDER_PORT_DEFAULT; |
|||
const contractsVersionHash = contractsVersionHashEnv || CONTRACTS_VERSION_HASH_DEFAULT; |
|||
|
|||
module.exports = { |
|||
contractsProviderHost, |
|||
contractsProviderPort, |
|||
contractsVersionHash, |
|||
}; |
@ -0,0 +1,12 @@ |
|||
const { |
|||
pinner: { |
|||
port: PINNER_API_PORT_DEFAULT, |
|||
}, |
|||
} = require('../../constants/configuration/defaults'); |
|||
const { pinnerApiPortEnv } = require('../pinnerEnv'); |
|||
|
|||
const pinnerApiPort = pinnerApiPortEnv || PINNER_API_PORT_DEFAULT; |
|||
|
|||
module.exports = { |
|||
pinnerApiPort, |
|||
}; |
@ -0,0 +1,15 @@ |
|||
const { rendezvousHostEnv, rendezvousPortEnv } = require('../rendezvousEnv'); |
|||
const { |
|||
rendezvous: { |
|||
host: RENDEZVOUS_HOST_DEFAULT, |
|||
port: RENDEZVOUS_PORT_DEFAULT, |
|||
}, |
|||
} = require('../../constants/configuration/defaults'); |
|||
|
|||
const rendezvousHost = rendezvousHostEnv || RENDEZVOUS_HOST_DEFAULT; |
|||
const rendezvousPort = rendezvousPortEnv || RENDEZVOUS_PORT_DEFAULT; |
|||
|
|||
module.exports = { |
|||
rendezvousHost, |
|||
rendezvousPort, |
|||
}; |
@ -0,0 +1,9 @@ |
|||
const contractsProvider = require('./contractsProvider'); |
|||
const rendezvous = require('./rendezvous'); |
|||
const web3 = require('./web3'); |
|||
|
|||
module.exports = { |
|||
contractsProvider, |
|||
rendezvous, |
|||
web3, |
|||
}; |
@ -0,0 +1,37 @@ |
|||
const { |
|||
web3: { |
|||
develop: { |
|||
chainHost: WEB3_HOST_DEFAULT, |
|||
chainPort: WEB3_PORT_DEFAULT, |
|||
}, |
|||
test: { |
|||
chainHost: WEB3_HOST_TEST_DEFAULT, |
|||
chainPort: WEB3_PORT_TEST_DEFAULT, |
|||
}, |
|||
socketConnectMaxAttempts: WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT, |
|||
socketTimeout: WEB3_PORT_SOCKET_TIMEOUT_DEFAULT, |
|||
}, |
|||
} = require('../../constants/configuration/defaults'); |
|||
const { |
|||
web3HostEnv, web3HostTestEnv, web3PortEnv, web3PortSocketConnectMaxAttemptsEnv, web3PortSocketTimeoutEnv, |
|||
web3PortTestEnv, |
|||
} = require('../web3Env'); |
|||
|
|||
const web3Host = web3HostEnv || WEB3_HOST_DEFAULT; |
|||
const web3Port = web3PortEnv || WEB3_PORT_DEFAULT; |
|||
|
|||
const web3HostTest = web3HostTestEnv || WEB3_HOST_TEST_DEFAULT; |
|||
const web3PortTest = web3PortTestEnv || WEB3_PORT_TEST_DEFAULT; |
|||
|
|||
const web3PortSocketTimeout = web3PortSocketTimeoutEnv || WEB3_PORT_SOCKET_TIMEOUT_DEFAULT; |
|||
const web3PortSocketConnectMaxAttempts = web3PortSocketConnectMaxAttemptsEnv |
|||
|| WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS_DEFAULT; |
|||
|
|||
module.exports = { |
|||
web3Host, |
|||
web3Port, |
|||
web3HostTest, |
|||
web3PortTest, |
|||
web3PortSocketTimeout, |
|||
web3PortSocketConnectMaxAttempts, |
|||
}; |
@ -0,0 +1,7 @@ |
|||
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
|
|||
// the REACT_APP_ prefix or not
|
|||
const pinnerApiPortEnv = process.env.REACT_APP_PINNER_API_PORT || process.env.PINNER_API_PORT; |
|||
|
|||
module.exports = { |
|||
pinnerApiPortEnv, |
|||
}; |
@ -0,0 +1,9 @@ |
|||
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
|
|||
// the REACT_APP_ prefix or not
|
|||
const rendezvousHostEnv = process.env.REACT_APP_RENDEZVOUS_HOST || process.env.RENDEZVOUS_HOST; |
|||
const rendezvousPortEnv = process.env.REACT_APP_RENDEZVOUS_PORT || process.env.RENDEZVOUS_PORT; |
|||
|
|||
module.exports = { |
|||
rendezvousHostEnv, |
|||
rendezvousPortEnv, |
|||
}; |
@ -0,0 +1,9 @@ |
|||
const contractsProvider = require('./contractsProviderEnv'); |
|||
const rendezvous = require('./rendezvousEnv'); |
|||
const web3 = require('./web3Env'); |
|||
|
|||
module.exports = { |
|||
contractsProvider, |
|||
rendezvous, |
|||
web3, |
|||
}; |
@ -0,0 +1,24 @@ |
|||
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
|
|||
// the REACT_APP_ prefix or not
|
|||
const web3HostEnv = process.env.REACT_APP_WEB3_HOST |
|||
|| process.env.WEB3_HOST; |
|||
const web3PortEnv = process.env.REACT_APP_WEB3_PORT |
|||
|| process.env.WEB3_PORT; |
|||
|
|||
// Web3 test environment shouldn't be available to the react app
|
|||
const web3HostTestEnv = process.env.WEB3_HOST_TEST; |
|||
const web3PortTestEnv = process.env.WEB3_PORT_TEST; |
|||
|
|||
const web3PortSocketTimeoutEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_TIMEOUT |
|||
|| process.env.WEB3_PORT_SOCKET_TIMEOUT; |
|||
const web3PortSocketConnectMaxAttemptsEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS |
|||
|| process.env.WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS; |
|||
|
|||
module.exports = { |
|||
web3HostEnv, |
|||
web3PortEnv, |
|||
web3HostTestEnv, |
|||
web3PortTestEnv, |
|||
web3PortSocketTimeoutEnv, |
|||
web3PortSocketConnectMaxAttemptsEnv, |
|||
}; |
@ -0,0 +1,5 @@ |
|||
const { rendezvousHost, rendezvousPort } = require('../environment/interpolated/rendezvous'); |
|||
|
|||
const getRendezvousUrl = () => `http://${rendezvousHost}:${rendezvousPort}`; |
|||
|
|||
module.exports = getRendezvousUrl; |
@ -0,0 +1,6 @@ |
|||
const { web3Port } = require('../environment/interpolated/web3'); |
|||
const { web3Host } = require('../environment/interpolated/web3'); |
|||
|
|||
const getWeb3ProviderUrl = () => `ws://${web3Host}:${web3Port}`; |
|||
|
|||
module.exports = getWeb3ProviderUrl; |
File diff suppressed because it is too large
Loading…
Reference in new issue