Browse Source

feat: init contracts provider

develop
Apostolos Fanakis 4 years ago
parent
commit
755ff0e717
  1. 2
      packages/concordia-app/src/constants/contracts/ContractNames.js
  2. 12
      packages/concordia-app/src/options/drizzleOptions.js
  3. 47
      packages/concordia-app/src/utils/drizzleUtils.js
  4. 60
      packages/concordia-contracts-provider/.eslintrc.js
  5. 22
      packages/concordia-contracts-provider/.gitignore
  6. 26
      packages/concordia-contracts-provider/package.json
  7. 3
      packages/concordia-contracts-provider/src/constants.js
  8. 19
      packages/concordia-contracts-provider/src/controllers/download.js
  9. 19
      packages/concordia-contracts-provider/src/controllers/upload.js
  10. 19
      packages/concordia-contracts-provider/src/index.js
  11. 32
      packages/concordia-contracts-provider/src/middleware/upload.js
  12. 14
      packages/concordia-contracts-provider/src/routes/web.js

2
packages/concordia-app/src/constants/contracts/ContractNames.js

@ -1,3 +1,5 @@
export const FORUM_CONTRACT = 'Forum'; export const FORUM_CONTRACT = 'Forum';
export const POST_VOTING_CONTRACT = 'PostVoting'; export const POST_VOTING_CONTRACT = 'PostVoting';
export const VOTING_CONTRACT = 'Voting'; export const VOTING_CONTRACT = 'Voting';
export const NUMBER_OF_CONTRACTS = 4;
export const NUMBER_OF_CONTRACTS = 4;

12
packages/concordia-app/src/options/drizzleOptions.js

@ -2,13 +2,23 @@
import { contracts } from 'concordia-contracts'; import { contracts } from 'concordia-contracts';
import web3Options from './web3Options'; import web3Options from './web3Options';
import appEvents from '../constants/contracts/events'; import appEvents from '../constants/contracts/events';
import { downloadContractArtifactsSync } from '../utils/drizzleUtils';
const drizzleOptions = { const drizzleOptions = {
web3: web3Options, web3: web3Options,
contracts,
events: { ...appEvents }, events: { ...appEvents },
reloadWindowOnNetworkChange: true, reloadWindowOnNetworkChange: true,
reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases
}; };
const CONTRACTS_SUPPLIER_URL = process.env.REACT_APP_CONTRACTS_SUPPLIER;
if (!CONTRACTS_SUPPLIER_URL) {
drizzleOptions.contracts = contracts;
} else {
const remoteContracts = downloadContractArtifactsSync();
console.log(remoteContracts);
drizzleOptions.contracts = remoteContracts;
}
export default drizzleOptions; export default drizzleOptions;

47
packages/concordia-app/src/utils/drizzleUtils.js

@ -0,0 +1,47 @@
// const downloadContractArtifacts = async () => {
import { NUMBER_OF_CONTRACTS } from '../constants/contracts/ContractNames';
export const downloadContractArtifacts = async () => {
const headers = new Headers();
headers.append('Access-Control-Allow-Origin', 'http://localhost:7000');
headers.append('Access-Control-Allow-Credentials', 'true');
const requestOptions = {
method: 'GET',
redirect: 'follow',
headers,
};
const remoteContracts = await fetch('http://127.0.0.1:8400/contracts/asdf', requestOptions)
.then((response) => response.text())
.then((contractsRawData) => JSON.parse(contractsRawData));
if (remoteContracts.length !== NUMBER_OF_CONTRACTS) {
throw new Error(`Version mismatch detected. Artifacts brought ${remoteContracts.length} contracts but app
expected ${NUMBER_OF_CONTRACTS}`);
}
return remoteContracts;
};
export const downloadContractArtifactsSync = () => {
const xhrRequest = new XMLHttpRequest();
// xhrRequest.withCredentials = true;
xhrRequest.open('GET', 'http://127.0.0.1:8400/contracts/asdf', false);
xhrRequest.setRequestHeader('Access-Control-Allow-Origin', 'http://localhost:7000');
xhrRequest.setRequestHeader('Access-Control-Allow-Credentials', 'true');
xhrRequest.send(null);
if (xhrRequest.status === 200) {
const contractsRawData = xhrRequest.responseText;
const remoteContracts = JSON.parse(contractsRawData);
if (remoteContracts.length !== NUMBER_OF_CONTRACTS) {
throw new Error(`Version mismatch detected. Artifacts brought ${remoteContracts.length} contracts but app
expected ${NUMBER_OF_CONTRACTS}`);
}
return remoteContracts;
}
throw new Error(`Remote contract artifacts download request failed!\n${xhrRequest.responseText}`);
};

60
packages/concordia-contracts-provider/.eslintrc.js

@ -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'],
},
},
},
};

22
packages/concordia-contracts-provider/.gitignore

@ -0,0 +1,22 @@
# Node
/node_modules
# IDE
.DS_Store
.idea
# Build Directories
/build
/src/build
# Logs
/log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Misc
.env.local
.env.development.local
.env.test.local
.env.production.local

26
packages/concordia-contracts-provider/package.json

@ -0,0 +1,26 @@
{
"name": "concordia-contracts-provider",
"description": "A server that provides built contracts for Concordia.",
"version": "0.1.0",
"private": true,
"main": "src/index.js",
"scripts": {
"start": "node -r esm src/index.js"
},
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"esm": "~3.2.25",
"express": "^4.17.1",
"lodash": "^4.17.20",
"multer": "^1.4.2",
"multiparty": "^4.2.2"
},
"devDependencies": {
"eslint": "^7.19.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0"
}
}

3
packages/concordia-contracts-provider/src/constants.js

@ -0,0 +1,3 @@
export const API_HOST = '127.0.0.1';
export const API_PORT = '8400';
export const UPLOADED_CONTRACTS_DIR = './contracts-uploads/';

19
packages/concordia-contracts-provider/src/controllers/download.js

@ -0,0 +1,19 @@
import * as fs from 'fs';
import path from 'path';
import { UPLOADED_CONTRACTS_DIR } from '../constants';
const downloadContracts = async (req, res) => {
const { params: { hash } } = req;
const directoryPath = path.join(`${__dirname}/../../${UPLOADED_CONTRACTS_DIR}/${hash}`);
const contracts = [];
fs.readdirSync(directoryPath).forEach((contractFilename) => {
const rawContractData = fs.readFileSync(path.join(`${directoryPath}/${contractFilename}`), 'utf-8');
const contractJson = JSON.parse(rawContractData);
contracts.push(contractJson);
});
res.send(contracts);
};
export default downloadContracts;

19
packages/concordia-contracts-provider/src/controllers/upload.js

@ -0,0 +1,19 @@
import upload from '../middleware/upload';
const uploadContracts = async (req, res) => {
try {
await upload(req, res);
if (req.files.length <= 0) {
return res.send('You must select at least 1 file.');
}
return res.send('Files have been uploaded.');
} catch (error) {
console.log(error);
return res.send(`Error when trying upload many files: ${error}`);
}
};
export default uploadContracts;

19
packages/concordia-contracts-provider/src/index.js

@ -0,0 +1,19 @@
import express from 'express';
import cors from 'cors';
import initRoutes from './routes/web';
import { API_HOST, API_PORT } from './constants';
const app = express();
const corsOptions = {
origin: ['localhost:7000', '127.0.0.1:7000', 'http://localhost:7000'],
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
};
app.use(express.urlencoded({ extended: true }));
app.use(cors(corsOptions));
initRoutes(app);
app.listen(API_PORT, () => {
console.log(`Contracts provider listening at http://${API_HOST}:${API_PORT}`);
});

32
packages/concordia-contracts-provider/src/middleware/upload.js

@ -0,0 +1,32 @@
import * as util from 'util';
import * as path from 'path';
import * as fs from 'fs';
import multer from 'multer';
import { UPLOADED_CONTRACTS_DIR } from '../constants';
const storage = multer.diskStorage({
destination: (req, file, callback) => {
const { params: { hash } } = req;
const contractsPath = path.join(`${__dirname}/../../${UPLOADED_CONTRACTS_DIR}/${hash}`);
fs.mkdirSync(contractsPath, { recursive: true });
callback(null, contractsPath);
// callback(null, UPLOADED_CONTRACTS_DIR);
},
filename: (req, file, callback) => {
const match = ['application/json'];
if (match.indexOf(file.mimetype) === -1) {
const message = `<strong>${file.originalname}</strong> is invalid. Only JSON files are accepted.`;
return callback(message, null);
}
const filename = `${file.originalname}`;
callback(null, filename);
},
});
const uploadFiles = multer({ storage }).array('contracts');
const uploadFilesMiddleware = util.promisify(uploadFiles);
export default uploadFilesMiddleware;

14
packages/concordia-contracts-provider/src/routes/web.js

@ -0,0 +1,14 @@
import express from 'express';
import downloadContracts from '../controllers/download';
import uploadContracts from '../controllers/upload';
const router = express.Router();
const routes = (app) => {
router.get('/contracts/:hash', downloadContracts);
router.post('/contracts/:hash', uploadContracts);
return app.use('/', router);
};
export default routes;
Loading…
Cancel
Save