mirror of https://github.com/embarklabs/embark.git
commit
e175cd6b56
|
@ -8,12 +8,16 @@ engines:
|
|||
enabled: false
|
||||
global-require:
|
||||
enabled: false
|
||||
guard-for-in:
|
||||
enabled: false
|
||||
ratings:
|
||||
paths:
|
||||
- "lib/**/*"
|
||||
exclude_paths:
|
||||
- "tests/"
|
||||
- "test/"
|
||||
- "old_test/"
|
||||
- "boilerplate/"
|
||||
- "demo/"
|
||||
- "js/"
|
||||
- "test_app/"
|
||||
- "docs/"
|
||||
|
|
|
@ -5,3 +5,10 @@ demo/dist/
|
|||
demo/.embark/development/
|
||||
demo/config/production/password
|
||||
boilerplate/dist/
|
||||
docs/_build
|
||||
docs/utils/__pycache_
|
||||
test_app/dist/
|
||||
test_app/.embark/development/
|
||||
test_app/config/production/password
|
||||
test_app/node_modules/
|
||||
test_app/chains.json
|
||||
|
|
111
README.md
111
README.md
|
@ -1,4 +1,3 @@
|
|||
|
||||
[![Join the chat at https://gitter.im/iurimatias/embark-framework](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iurimatias/embark-framework?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Build
|
||||
Status](https://travis-ci.org/iurimatias/embark-framework.svg?branch=develop)](https://travis-ci.org/iurimatias/embark-framework)
|
||||
|
@ -7,16 +6,33 @@ Status](https://travis-ci.org/iurimatias/embark-framework.svg?branch=develop)](h
|
|||
What is Embark
|
||||
======
|
||||
|
||||
Embark is a framework that allows you to easily develop and deploy DApps.
|
||||
Embark is a framework that allows you to easily develop and deploy Decentralized Applications (DApps).
|
||||
|
||||
A Decentralized Application is serverless html5 application that uses one or more decentralized technologies.
|
||||
|
||||
Embark currently integrates with EVM blockchains (Ethereum), Decentralized Storages (IPFS), and Decentralizaed communication platforms (Whisper and Orbit). Swarm is supported for deployment.
|
||||
|
||||
With Embark you can:
|
||||
|
||||
**Blockchain (Ethereum)**
|
||||
* Automatically deploy contracts and make them available in your JS code. Embark watches for changes, and if you update a contract, Embark will automatically redeploy the contracts (if needed) and the dapp.
|
||||
* Use any build pipeline or tool you wish, including grunt and meteor. (for 1.x, plugins coming soon for 2.x series)
|
||||
* Contracts are available in JS with Promises.
|
||||
* Do Test Driven Development with Contracts using Javascript.
|
||||
* Easily deploy to & use decentralized systems such as IPFS.
|
||||
* Keep track of deployed contracts, deploy only when truly needed.
|
||||
* Manage different chains (e.g testnet, private net, livenet)
|
||||
* Quickly create advanced DApps using multiple contracts that can interact with decentralized infrastructure for storage and comunication.
|
||||
* Easily manage complex systems of interdependent contracts.
|
||||
|
||||
**Decentralized Storage (IPFS)**
|
||||
* Easily Store & Retrieve Data on the DApp through EmbarkJS. Includin uploading and retrieving files.
|
||||
* Deploy the full application to IPFS or Swarm.
|
||||
|
||||
|
||||
**Decentralized Communication (Whisper, Orbit)**
|
||||
* Easily send/receive messages through channels in P2P through Whisper or Orbit.
|
||||
|
||||
**Web Technologies**
|
||||
* Integrate with any web technology including React, Foundation, etc..
|
||||
* Use any build pipeline or tool you wish, including grunt, gulp and webpack.
|
||||
|
||||
Table of Contents
|
||||
======
|
||||
|
@ -28,18 +44,18 @@ Table of Contents
|
|||
* [Using and Configuring Contracts](#dapp-structure)
|
||||
* [EmbarkJS](#embarkjs)
|
||||
* [EmbarkJS - Storage (IPFS)](#embarkjs---storage)
|
||||
* [EmbarkJS - Communication (Whisper)](#embarkjs---communication)
|
||||
* [EmbarkJS - Communication (Whisper/Orbit)](#embarkjs---communication)
|
||||
* [Testing Contracts](#tests)
|
||||
* [Working with different chains](#working-with-different-chains)
|
||||
* [Custom Application Structure](#structuring-application)
|
||||
* [Deploying to IPFS](#deploying-to-ipfs)
|
||||
* [LiveReload Plugin](#livereload-plugin)
|
||||
* [Extending Functionality with Plugins](#plugins)
|
||||
* [Donations](#donations)
|
||||
|
||||
Installation
|
||||
======
|
||||
Requirements: geth (1.4.4 or higher), node (5.0.0) and npm
|
||||
Optional: serpent (develop) if using contracts with Serpent, testrpc or ethersim if using the simulator or the test functionality.
|
||||
Requirements: geth (1.5.8 or higher), node (6.9.1 or higher is recommended) and npm
|
||||
Optional: testrpc (3.0 or higher) if using the simulator or the test functionality.
|
||||
Further: depending on the dapp stack you choose: [IPFS](https://ipfs.io/)
|
||||
|
||||
```Bash
|
||||
|
@ -58,6 +74,9 @@ Embark's npm package has changed from ```embark-framework``` to ```embark```, th
|
|||
|
||||
Usage - Demo
|
||||
======
|
||||
|
||||
![Embark Demo screenshot](http://i.imgur.com/a9ddSjn.png)
|
||||
|
||||
You can easily create a sample working DApp with the following:
|
||||
|
||||
```Bash
|
||||
|
@ -136,7 +155,7 @@ Solidity/Serpent files in the contracts directory will automatically be deployed
|
|||
Libraries and languages available
|
||||
======
|
||||
|
||||
Embark can build and deploy contracts coded in Solidity or Serpent. It will make them available on the client side using EmbarkJS and Web3.js.
|
||||
Embark can build and deploy contracts coded in Solidity. It will make them available on the client side using EmbarkJS and Web3.js.
|
||||
|
||||
Further documentation for these can be found below:
|
||||
|
||||
|
@ -149,6 +168,7 @@ Embark will automatically take care of deployment for you and set all needed JS
|
|||
|
||||
```Javascript
|
||||
# app/contracts/simple_storage.sol
|
||||
pragma solidity ^0.4.7;
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
|
@ -169,8 +189,8 @@ Will automatically be available in Javascript as:
|
|||
```Javascript
|
||||
# app/js/index.js
|
||||
SimpleStorage.set(100);
|
||||
SimpleStorage.get();
|
||||
SimpleStorage.storedData();
|
||||
SimpleStorage.get().then(function(value) { console.log(value.toNumber()) });
|
||||
SimpleStorage.storedData().then(function(value) { console.log(value.toNumber()) });
|
||||
```
|
||||
|
||||
You can specify for each contract and environment its gas costs and arguments:
|
||||
|
@ -291,6 +311,12 @@ methods in EmbarkJS contracts will be converted to promises.
|
|||
myContract.get().then(function(value) { console.log("value is " + value.toNumber) });
|
||||
```
|
||||
|
||||
events:
|
||||
|
||||
```Javascript
|
||||
myContract.eventName({from: web3.eth.accounts}, 'latest').then(function(event) { console.log(event) });
|
||||
```
|
||||
|
||||
**deployment**
|
||||
|
||||
Client side deployment will be automatically available in Embark for existing contracts:
|
||||
|
@ -346,17 +372,33 @@ The current available storage is IPFS. it can be initialized as
|
|||
EmbarkJS.Storage.getUrl(hash);
|
||||
```
|
||||
|
||||
note: if not using localhost, the cors needs to be set as ```ipfs --json API.HTTPHeaders.Access-Control-Allow-Origin '["your-host-name-port"]```
|
||||
|
||||
EmbarkJS - Communication
|
||||
======
|
||||
|
||||
**initialization**
|
||||
|
||||
The current available communication is Whisper.
|
||||
For Whisper:
|
||||
|
||||
```Javascript
|
||||
EmbarkJS.Messages.setProvider('whisper')
|
||||
```
|
||||
|
||||
For Orbit:
|
||||
|
||||
You'll need to use IPFS from master and run it as: ```ipfs daemon --enable-pubsub-experiment```
|
||||
|
||||
then set the provider:
|
||||
|
||||
```Javascript
|
||||
EmbarkJS.Messages.setProvider('orbit', {server: 'localhost', port: 5001})
|
||||
```
|
||||
|
||||
**listening to messages**
|
||||
|
||||
```Javascript
|
||||
EmbarkJS.Messages.listenTo({topic: ["achannel", "anotherchannel"]}).then(function(message) { console.log("received: " + message); })
|
||||
EmbarkJS.Messages.listenTo({topic: ["topic1", "topic2"]}).then(function(message) { console.log("received: " + message); })
|
||||
```
|
||||
|
||||
**sending messages**
|
||||
|
@ -364,15 +406,17 @@ The current available communication is Whisper.
|
|||
you can send plain text
|
||||
|
||||
```Javascript
|
||||
EmbarkJS.Messages.sendMessage({topic: "achannel", data: 'hello world'})
|
||||
EmbarkJS.Messages.sendMessage({topic: "sometopic", data: 'hello world'})
|
||||
```
|
||||
|
||||
or an object
|
||||
|
||||
```Javascript
|
||||
EmbarkJS.Messages.sendMessage({topic: "achannel", data: {msg: 'hello world'}})
|
||||
EmbarkJS.Messages.sendMessage({topic: "sometopic", data: {msg: 'hello world'}})
|
||||
```
|
||||
|
||||
note: array of topics are considered an AND. In Whisper you can use another array for OR combinations of several topics e.g ```["topic1", ["topic2", "topic3"]]``` => ```topic1 AND (topic2 OR topic 3)```
|
||||
|
||||
Tests
|
||||
======
|
||||
|
||||
|
@ -424,9 +468,9 @@ Working with different chains
|
|||
You can specify which environment to deploy to:
|
||||
|
||||
|
||||
```$ embark blockchain production```
|
||||
```$ embark blockchain livenet```
|
||||
|
||||
```$ embark run production```
|
||||
```$ embark run livenet```
|
||||
|
||||
The environment is a specific blockchain configuration that can be managed at config/blockchain.json
|
||||
|
||||
|
@ -439,7 +483,7 @@ The environment is a specific blockchain configuration that can be managed at co
|
|||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/production/password"
|
||||
"password": "config/livenet/password"
|
||||
}
|
||||
},
|
||||
...
|
||||
|
@ -448,7 +492,7 @@ The environment is a specific blockchain configuration that can be managed at co
|
|||
Structuring Application
|
||||
======
|
||||
|
||||
Embark is quite flexible and you can configure you're own directory structure using ```embark.json```
|
||||
Embark is quite flexible and you can configure your own directory structure using ```embark.json```
|
||||
|
||||
```Json
|
||||
# embark.json
|
||||
|
@ -456,24 +500,39 @@ Embark is quite flexible and you can configure you're own directory structure us
|
|||
"contracts": ["app/contracts/**"],
|
||||
"app": {
|
||||
"css/app.css": ["app/css/**"],
|
||||
"images/": ["app/images/**"],
|
||||
"js/app.js": ["embark.js", "app/js/**"],
|
||||
"index.html": "app/index.html"
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/"
|
||||
"config": "config/",
|
||||
"plugins": {}
|
||||
}
|
||||
```
|
||||
|
||||
Deploying to IPFS
|
||||
Deploying to IPFS and Swarm
|
||||
======
|
||||
|
||||
To deploy a dapp to IPFS, all you need to do is run a local IPFS node and then run ```embark ipfs```.
|
||||
If you want to deploy to the livenet then after configuring you account on ```config/blockchain.json``` on the ```production``` environment then you can deploy to that chain by specifying the environment ```embark ipfs production```.
|
||||
To deploy a dapp to IPFS, all you need to do is run a local IPFS node and then run ```embark upload ipfs```.
|
||||
If you want to deploy to the livenet then after configuring you account on ```config/blockchain.json``` on the ```livenet``` environment then you can deploy to that chain by specifying the environment ```embark ipfs livenet```.
|
||||
|
||||
LiveReload Plugin
|
||||
To deploy a dapp to SWARM, all you need to do is run a local SWARM node and then run ```embark upload swarm```.
|
||||
|
||||
Plugins
|
||||
======
|
||||
|
||||
Embark works quite well with the LiveReload Plugin
|
||||
It's possible to extend Embarks functionality with plugins. For example the following is possible:
|
||||
|
||||
* plugin to add support for es6, jsx, coffescript, etc (``embark.registerPipeline``)
|
||||
* plugin to add standard contracts or a contract framework (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||
* plugin to make some contracts available in all environments for use by other contracts or the dapp itself e.g a Token, a DAO, ENS, etc.. (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||
* plugin to add a libraries such as react or boostrap (``embark.addFileToPipeline``)
|
||||
* plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``)
|
||||
* plugin to create a different contract wrapper (``embark.registerContractsGeneration``)
|
||||
* plugin to add new console commands (``embark.registerConsoleCommand``)
|
||||
* plugin to add support for another contract language such as viper, LLL, etc (``embark.registerCompiler``)
|
||||
|
||||
For more information on how to develop your own plugin please see the [plugin documentation](http://embark.readthedocs.io/en/latest/plugins.html)
|
||||
|
||||
Donations
|
||||
======
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
node_modules/
|
||||
dist/
|
||||
config/production/password
|
||||
config/livenet/password
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"development": {
|
||||
"enabled": true,
|
||||
"networkType": "custom",
|
||||
"genesisBlock": "config/development/genesis.json",
|
||||
"datadir": ".embark/development/datadir",
|
||||
"mineWhenNeeded": true,
|
||||
"nodiscover": true,
|
||||
"maxpeers": 0,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
|
@ -13,25 +15,34 @@
|
|||
}
|
||||
},
|
||||
"testnet": {
|
||||
"enabled": true,
|
||||
"networkType": "testnet",
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545
|
||||
},
|
||||
"livenet": {
|
||||
"networkType": "livenet",
|
||||
"light": true,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/production/password"
|
||||
"password": "config/testnet/password"
|
||||
}
|
||||
},
|
||||
"livenet": {
|
||||
"enabled": true,
|
||||
"networkType": "livenet",
|
||||
"light": true,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/livenet/password"
|
||||
}
|
||||
},
|
||||
"privatenet": {
|
||||
"enabled": true,
|
||||
"networkType": "custom",
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"datadir": "yourdatadir",
|
||||
"networkId": "123",
|
||||
"nodes": []
|
||||
"bootnodes": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"provider": "whisper",
|
||||
"available_providers": ["whisper", "orbit"]
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
prod_password
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"ipfs_bin": "ipfs",
|
||||
"provider": "ipfs",
|
||||
"available_providers": ["ipfs"],
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
},
|
||||
"development": {
|
||||
"enabled": true,
|
||||
"provider": "ipfs",
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
test_password
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"enabled": true,
|
||||
"host": "localhost",
|
||||
"port": 8000
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
"index.html": "app/index.html"
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/"
|
||||
"config": "config/",
|
||||
"plugins": {}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
{
|
||||
"name": "app_name",
|
||||
"name": "%APP_NAME%",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "Gruntfile.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "embark test"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"homepage": "",
|
||||
"devDependencies": {
|
||||
"embark": "^2.1.4",
|
||||
"embark": "^2.4.0",
|
||||
"mocha": "^2.2.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
node_modules/
|
||||
dist/
|
||||
config/production/password
|
||||
config/livenet/password
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.2;
|
||||
pragma solidity ^0.4.7;
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
|
|
|
@ -3,3 +3,47 @@ div {
|
|||
margin: 15px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
background-color: black;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: red;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: mediumseagreen;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
|
|
@ -5,27 +5,101 @@
|
|||
<script src="js/app.js"></script>
|
||||
</head>
|
||||
<body class="container">
|
||||
<h3>Embark - SimpleStorage Demo</h3>
|
||||
<h3>Embark - Usage Example</h3>
|
||||
|
||||
<h3> 1. Set the value in the blockchain</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="text" class="text form-control" value="10">
|
||||
<button class="set btn btn-primary">Set Value</button>
|
||||
<p>Once you set the value, the transaction will need to be mined and then the value will be updated on the blockchain.</p>
|
||||
</div>
|
||||
<ul class="nav nav-tabs" role="tablist" id="myTabs">
|
||||
<li role="presentation" class="active"><a href="#blockchain" aria-controls="blockchain" role="tab" data-toggle="tab">Blockchain</a></li>
|
||||
<li role="presentation"><a href="#storage" aria-controls="storage" role="tab" data-toggle="tab">Decentralized Storage (IPFS)<span class="pull-right" id="status-storage"></a></li>
|
||||
<li role="presentation"><a href="#communication" aria-controls="communication" role="tab" data-toggle="tab">P2P communication (Whisper/Orbit)<span class="pull-right" id="status-communication"></span></a></li>
|
||||
</ul>
|
||||
|
||||
<h3> 2. Get the current value</h3>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
current value is <span class="value"></span>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="blockchain">
|
||||
<h3> 1. Set the value in the blockchain</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="text" class="text form-control" value="10">
|
||||
<button class="set btn btn-primary">Set Value</button>
|
||||
<p>Once you set the value, the transaction will need to be mined and then the value will be updated on the blockchain.</p>
|
||||
</div>
|
||||
|
||||
<h3> 2. Get the current value</h3>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
current value is <span class="value"></span>
|
||||
</div>
|
||||
<button class="get btn btn-primary">Get Value</button>
|
||||
<p>Click the button to get the current value. The initial value is 100.</p>
|
||||
</div>
|
||||
|
||||
<h3> 3. Contract Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div class="logs">
|
||||
</div>
|
||||
</div>
|
||||
<button class="get btn btn-primary">Get Value</button>
|
||||
<p>Click the button to get the current value. The initial value is 100.</p>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="storage">
|
||||
<div class="error alert alert-danger" role="alert">The node you are using does not support IPFS. Please ensure <a href="https://github.com/ipfs/js-ipfs-api#cors" target="_blank">CORS</a> is setup for the IPFS node.</div>
|
||||
<div id="storage-controls">
|
||||
|
||||
<h3> 3. Contract Calls </h3>
|
||||
<div class="logs">
|
||||
<p>Javascript call being made: </p>
|
||||
<h3>Save text to IPFS</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="text" class="ipfsText text form-control" value="hello world!">
|
||||
<button class="setIpfsText btn btn-primary">Save</button>
|
||||
<p>generated Hash: <span class="textHash"></span></p>
|
||||
</div>
|
||||
|
||||
<h3>Load text from IPFS given an hash</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="text" class="textHash text form-control" size="60">
|
||||
<button class="loadIpfsHash set btn btn-primary">Load</button>
|
||||
<p>result: <span class="ipfsText"></span></p>
|
||||
</div>
|
||||
|
||||
<h3>upload file to ipfs</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="file" class="form-control">
|
||||
<button class="uploadFile set btn btn-primary">upload</button>
|
||||
<p>generated hash: <span class="fileIpfsHash"></span></p>
|
||||
</div>
|
||||
|
||||
<h3>Get file or image from ipfs</h3>
|
||||
<div class="form-group form-inline">
|
||||
<input type="text" class="fileIpfsHash form-control" size="60">
|
||||
<button class="loadIpfsFile set btn btn-primary">Load</button>
|
||||
<p>file available at: <span class="ipfsFileUrl"></span></p>
|
||||
<p><img class="ipfsImage" src=""></p>
|
||||
</div>
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div class="logs">
|
||||
<br> EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="communication">
|
||||
<div class="error alert alert-danger" role="alert">The node you are using does not support Whisper</div>
|
||||
<div id="communication-controls">
|
||||
<h3>Listen To channel</h3>
|
||||
<div class="form-group form-inline listen">
|
||||
<input type="text" class="channel text form-control" placeholder="channel">
|
||||
<button class="listenToChannel set btn btn-primary">Start Listening</button>
|
||||
<div id="subscribeList"></div>
|
||||
<p>messages received:<p>
|
||||
<div id="messagesList"></div>
|
||||
</div>
|
||||
|
||||
<h3>Send Message</h3>
|
||||
<div class="form-group form-inline send">
|
||||
<input type="text" class="channel text form-control" placeholder="channel">
|
||||
<input type="text" class="message text form-control" placeholder="message">
|
||||
<button class="sendMessage set btn btn-primary">Send Message</button>
|
||||
</div>
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div class="logs">
|
||||
<br> EmbarkJS.Messages.setProvider('whisper')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,22 +1,119 @@
|
|||
/*globals $, SimpleStorage, document*/
|
||||
|
||||
var addToLog = function(txt) {
|
||||
$(".logs").append("<br>" + txt);
|
||||
var addToLog = function(id, txt) {
|
||||
$(id + " .logs").append("<br>" + txt);
|
||||
};
|
||||
|
||||
// ===========================
|
||||
// Blockchain example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
|
||||
$("button.set").click(function() {
|
||||
var value = parseInt($("input.text").val(), 10);
|
||||
$("#blockchain button.set").click(function() {
|
||||
var value = parseInt($("#blockchain input.text").val(), 10);
|
||||
SimpleStorage.set(value);
|
||||
addToLog("SimpleStorage.set(" + value + ")");
|
||||
addToLog("#blockchain", "SimpleStorage.set(" + value + ")");
|
||||
});
|
||||
|
||||
$("button.get").click(function() {
|
||||
$("#blockchain button.get").click(function() {
|
||||
SimpleStorage.get().then(function(value) {
|
||||
$(".value").html(value.toNumber());
|
||||
$("#blockchain .value").html(value.toNumber());
|
||||
});
|
||||
addToLog("SimpleStorage.get()");
|
||||
addToLog("#blockchain", "SimpleStorage.get()");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ===========================
|
||||
// Storage (IPFS) example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
// automatic set if config/storage.json has "enabled": true and "provider": "ipfs"
|
||||
//EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'});
|
||||
|
||||
$("#storage .error").hide();
|
||||
EmbarkJS.Storage.ipfsConnection.ping()
|
||||
.then(function(){
|
||||
$("#status-storage").addClass('status-online');
|
||||
$("#storage-controls").show();
|
||||
})
|
||||
.catch(function(err) {
|
||||
if(err){
|
||||
console.log("IPFS Connection Error => " + err.message);
|
||||
$("#storage .error").show();
|
||||
$("#status-storage").addClass('status-offline');
|
||||
$("#storage-controls").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#storage button.setIpfsText").click(function() {
|
||||
var value = $("#storage input.ipfsText").val();
|
||||
EmbarkJS.Storage.saveText(value).then(function(hash) {
|
||||
$("span.textHash").html(hash);
|
||||
$("input.textHash").val(hash);
|
||||
});
|
||||
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
|
||||
});
|
||||
|
||||
$("#storage button.loadIpfsHash").click(function() {
|
||||
var value = $("#storage input.textHash").val();
|
||||
EmbarkJS.Storage.get(value).then(function(content) {
|
||||
$("span.ipfsText").html(content);
|
||||
});
|
||||
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
|
||||
});
|
||||
|
||||
$("#storage button.uploadFile").click(function() {
|
||||
var input = $("#storage input[type=file]");
|
||||
EmbarkJS.Storage.uploadFile(input).then(function(hash) {
|
||||
$("span.fileIpfsHash").html(hash);
|
||||
$("input.fileIpfsHash").val(hash);
|
||||
});
|
||||
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
|
||||
});
|
||||
|
||||
$("#storage button.loadIpfsFile").click(function() {
|
||||
var hash = $("#storage input.fileIpfsHash").val();
|
||||
var url = EmbarkJS.Storage.getUrl(hash);
|
||||
var link = '<a href="' + url + '" target="_blank">' + url + '</a>';
|
||||
$("span.ipfsFileUrl").html(link);
|
||||
$(".ipfsImage").attr('src', url);
|
||||
addToLog("#storage", "EmbarkJS.Storage.getUrl('" + hash + "')");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ===========================
|
||||
// Communication (Whisper) example
|
||||
// ===========================
|
||||
$(document).ready(function() {
|
||||
|
||||
$("#communication .error").hide();
|
||||
web3.version.getWhisper(function(err, res) {
|
||||
if (err) {
|
||||
$("#communication .error").show();
|
||||
$("#communication-controls").hide();
|
||||
+ $("#status-communication").addClass('status-offline');
|
||||
} else {
|
||||
EmbarkJS.Messages.setProvider('whisper');
|
||||
$("#status-communication").addClass('status-online');
|
||||
}
|
||||
});
|
||||
|
||||
$("#communication button.listenToChannel").click(function() {
|
||||
var channel = $("#communication .listen input.channel").val();
|
||||
$("#communication #subscribeList").append("<br> subscribed to " + channel + " now try sending a message");
|
||||
EmbarkJS.Messages.listenTo({topic: [channel]}).then(function(message) {
|
||||
$("#communication #messagesList").append("<br> channel: " + channel + " message: " + message);
|
||||
});
|
||||
addToLog("#communication", "EmbarkJS.Messages.listenTo({topic: ['" + channel + "']}).then(function(message) {})");
|
||||
});
|
||||
|
||||
$("#communication button.sendMessage").click(function() {
|
||||
var channel = $("#communication .send input.channel").val();
|
||||
var message = $("#communication .send input.message").val();
|
||||
EmbarkJS.Messages.sendMessage({topic: channel, data: message});
|
||||
addToLog("#communication", "EmbarkJS.Messages.sendMessage({topic: '" + channel + "', data: '" + message + "'})");
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
{
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"development": {
|
||||
"enabled": true,
|
||||
"networkType": "custom",
|
||||
"genesisBlock": "config/development/genesis.json",
|
||||
"datadir": ".embark/development/datadir",
|
||||
"mineWhenNeeded": true,
|
||||
"nodiscover": true,
|
||||
"maxpeers": 0,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
|
@ -13,25 +15,35 @@
|
|||
}
|
||||
},
|
||||
"testnet": {
|
||||
"enabled": true,
|
||||
"networkType": "testnet",
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545
|
||||
},
|
||||
"livenet": {
|
||||
"networkType": "livenet",
|
||||
"light": true,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/production/password"
|
||||
"password": "config/testnet/password"
|
||||
}
|
||||
},
|
||||
"livenet": {
|
||||
"enabled": true,
|
||||
"networkType": "livenet",
|
||||
"light": true,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/livenet/password"
|
||||
}
|
||||
},
|
||||
"privatenet": {
|
||||
"enabled": true,
|
||||
"networkType": "custom",
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"datadir": "yourdatadir",
|
||||
"networkId": "123",
|
||||
"nodes": []
|
||||
"bootnodes": ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"provider": "whisper",
|
||||
"available_providers": ["whisper", "orbit"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"ipfs_bin": "ipfs",
|
||||
"provider": "ipfs",
|
||||
"available_providers": ["ipfs"],
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
},
|
||||
"development": {
|
||||
"enabled": true,
|
||||
"provider": "ipfs",
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
test_password
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"enabled": true,
|
||||
"host": "localhost",
|
||||
"port": 8000
|
||||
}
|
|
@ -2,9 +2,12 @@
|
|||
"contracts": ["app/contracts/**"],
|
||||
"app": {
|
||||
"css/app.css": ["app/css/**"],
|
||||
"js/app.js": ["embark.js", "app/js/**"],
|
||||
"images/": ["app/images/**"],
|
||||
"js/app.js": ["embark.js", "app/js/_vendor/jquery.min.js", "app/js/_vendor/bootstrap.min.js", "app/js/**"],
|
||||
"index.html": "app/index.html"
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/"
|
||||
"config": "config/",
|
||||
"plugins": {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"license": "ISC",
|
||||
"homepage": "",
|
||||
"devDependencies": {
|
||||
"embark": "^2.1.4",
|
||||
"embark": "^2.4.0",
|
||||
"mocha": "^2.2.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = embark
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,160 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ENS documentation build configuration file, created by
|
||||
# sphinx-quickstart on Thu Dec 15 16:45:41 2016.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
from recommonmark.parser import CommonMarkParser
|
||||
|
||||
source_parsers = {
|
||||
'.md': CommonMarkParser,
|
||||
}
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.mathjax']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Embark'
|
||||
copyright = u'2017, Iuri Matias'
|
||||
author = u'Iuri Matias'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'2.4'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'2.4.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Embarkdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'Embark.tex', u'Embark Documentation',
|
||||
u'Iuri Matias \\textless{}\\textgreater{}', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'embark', u'Embark Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'Embark', u'Embark Documentation',
|
||||
author, 'Embark', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
Configuring Communication (Whisper, Orbit)
|
||||
==========================
|
||||
|
||||
Embark will check your prefered communication configuration in the file ``config/communication.json``. This file will contain the prefered configuration for each environment. With ``default`` being the configuration fields that applies to every environment. Each of those can be individually overriden in a per environment basis.
|
||||
|
||||
e.g :
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"provider": "whisper",
|
||||
"available_providers": ["whisper", "orbit"]
|
||||
}
|
||||
}
|
||||
|
||||
options available:
|
||||
* ``enabled`` (boolean: true/false) to enable or completly disable communication support
|
||||
* ``provider`` (string: "wisper" or "orbit") desired provider to automatically connect to on the dapp. e.g in the example above, seting this to ``"whisper"`` will automaticaly add ``EmbarkJS.setProvider('whisper')`` to the generated code
|
||||
* ``available_providers`` (array: ["whisper", "orbit"]) list of communication platforms to be supported on the dapp. This will affect what's available with the EmbarkJS library on the dapp so if you don't need Orbit for e.g, removing it from this will considerably reduce the file size of the generated JS code.
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
Configuring Storage (IPFS)
|
||||
==========================
|
||||
|
||||
Embark will check your prefered storage configuration in the file ``config/storage.json``. This file will contain the prefered configuration for each environment. With ``default`` being the configuration fields that applies to every environment. Each of those can be individually overriden in a per environment basis.
|
||||
|
||||
e.g :
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"ipfs_bin": "ipfs",
|
||||
"provider": "ipfs",
|
||||
"available_providers": ["ipfs"],
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
},
|
||||
"development": {
|
||||
"enabled": true,
|
||||
"provider": "ipfs",
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
}
|
||||
}
|
||||
|
||||
options available:
|
||||
* ``enabled`` (boolean: true/false) to enable or completly disable storage support
|
||||
* ``ipfs_bin`` (string) name or desired path to the ipfs binary
|
||||
* ``provider`` (string: "ipfs") desired provider to automatically connect to on the dapp. e.g in the example above, seting this to ``"ipfs"`` will automaticaly add ``EmbarkJS.setProvider('ipfs', {server: 'localhost', 5001})`` to the generated code
|
||||
* ``available_providers`` (array: ["ipfs"]) list of storages to be supported on the dapp. This will affect what's available with the EmbarkJS library on the dapp.
|
||||
* ``host`` and ``port`` of the ipfs node to connect to.
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
Creating a new DApp
|
||||
===================
|
||||
|
||||
If you want to create a blank new app.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark new AppName
|
||||
$ cd AppName
|
||||
|
||||
To run Embark then in one console run:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark blockchain
|
||||
|
||||
And in another console run:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark run
|
||||
|
||||
DApp Structure
|
||||
==============
|
||||
|
||||
.. code:: bash
|
||||
|
||||
app/
|
||||
|___ contracts/ #solidity smart contracts
|
||||
|___ html/
|
||||
|___ css/
|
||||
|___ js/
|
||||
config/
|
||||
|___ blockchain.json #rpc and blockchain configuration
|
||||
|___ contracts.json #ethereum contracts configuration
|
||||
|___ storage.json #ipfs configuration
|
||||
|___ communication.json #whisper/orbit configuration
|
||||
|___ webserver.json #dev webserver configuration
|
||||
test/
|
||||
|___ #contracts tests
|
||||
|
||||
Solidity files in the contracts directory will automatically be deployed with ``embark run``. Changes in any files will automatically be reflected in app, changes to contracts will result in a redeployment and update of their JS Bindings
|
|
@ -0,0 +1,24 @@
|
|||
Dashboard
|
||||
=========
|
||||
|
||||
Embark 2 comes with a terminal dashboard.
|
||||
|
||||
.. figure:: http://i.imgur.com/s4OQZpu.jpg
|
||||
:alt: Dashboard
|
||||
|
||||
Dashboard
|
||||
|
||||
The dashboard will tell you the state of your contracts, the enviroment
|
||||
you are using, and what embark is doing at the moment.
|
||||
|
||||
**available services**
|
||||
|
||||
Available Services will display the services available to your dapp in
|
||||
green, if one of these is down then it will be displayed in red.
|
||||
|
||||
**logs and console**
|
||||
|
||||
There is a console at the bottom which can be used to interact with
|
||||
contracts or with embark itself. type ``help`` to see a list of
|
||||
available commands, more commands will be added with each version of
|
||||
Embark.
|
|
@ -0,0 +1,8 @@
|
|||
Deploying to IPFS
|
||||
=================
|
||||
|
||||
To deploy a dapp to IPFS, all you need to do is run a local IPFS node
|
||||
and then run ``embark upload ipfs``. If you want to deploy to the livenet then
|
||||
after configuring you account on ``config/blockchain.json`` on the
|
||||
``livenet`` environment then you can deploy to that chain by
|
||||
specifying the environment ``embark ipfs livenet``.
|
|
@ -0,0 +1,4 @@
|
|||
Deploying to SWARM
|
||||
==================
|
||||
|
||||
To deploy a dapp to SWARM, all you need to do is run a local SWARM node and then run ``embark upload swarm``.
|
|
@ -0,0 +1,4 @@
|
|||
Donations
|
||||
======
|
||||
|
||||
If you like Embark please consider donating to 0x8811FdF0F988f0CD1B7E9DE252ABfA5b18c1cDb1
|
|
@ -0,0 +1,5 @@
|
|||
Donations
|
||||
=========
|
||||
|
||||
If you like Embark please consider donating to
|
||||
0x8811FdF0F988f0CD1B7E9DE252ABfA5b18c1cDb1
|
|
@ -0,0 +1,46 @@
|
|||
EmbarkJS - Communication (Whisper, Orbit)
|
||||
=========================================
|
||||
|
||||
**initialization**
|
||||
|
||||
For Whisper:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Messages.setProvider('whisper')
|
||||
|
||||
For Orbit:
|
||||
|
||||
You'll need to use IPFS from master and run it as:
|
||||
``ipfs daemon --enable-pubsub-experiment``
|
||||
|
||||
then set the provider:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Messages.setProvider('orbit', {server: 'localhost', port: 5001})
|
||||
|
||||
**listening to messages**
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Messages.listenTo({topic: ["topic1", "topic2"]}).then(function(message) { console.log("received: " + message); })
|
||||
|
||||
**sending messages**
|
||||
|
||||
you can send plain text
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Messages.sendMessage({topic: "sometopic", data: 'hello world'})
|
||||
|
||||
or an object
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Messages.sendMessage({topic: "sometopic", data: {msg: 'hello world'}})
|
||||
|
||||
note: array of topics are considered an AND. In Whisper you can use
|
||||
another array for OR combinations of several topics e.g
|
||||
``["topic1", ["topic2", "topic3"]]`` =>
|
||||
``topic1 AND (topic2 OR topic 3)``
|
|
@ -0,0 +1,39 @@
|
|||
EmbarkJS - Storage (IPFS)
|
||||
=========================
|
||||
|
||||
**initialization**
|
||||
|
||||
The current available storage is IPFS. it can be initialized as
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'})
|
||||
|
||||
**Saving Text**
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Storage.saveText("hello world").then(function(hash) {});
|
||||
|
||||
**Retrieving Data/Text**
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Storage.get(hash).then(function(content) {});
|
||||
|
||||
**Uploading a file**
|
||||
|
||||
.. code:: html
|
||||
|
||||
<input type="file">
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
var input = $("input[type=file"]);
|
||||
EmbarkJS.Storage.uploadFile(input).then(function(hash) {});
|
||||
|
||||
**Generate URL to file**
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
EmbarkJS.Storage.getUrl(hash);
|
|
@ -0,0 +1,30 @@
|
|||
EmbarkJS
|
||||
========
|
||||
|
||||
EmbarkJS is a javascript library meant to abstract and facilitate the
|
||||
development of DApps.
|
||||
|
||||
**promises**
|
||||
|
||||
methods in EmbarkJS contracts will be converted to promises.
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
var myContract = new EmbarkJS.Contract({abi: abiObject, address: "0x123"});
|
||||
myContract.get().then(function(value) { console.log("value is " + value.toNumber) });
|
||||
|
||||
**deployment**
|
||||
|
||||
Client side deployment will be automatically available in Embark for
|
||||
existing contracts:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
SimpleStorage.deploy().then(function(anotherSimpleStorage) {});
|
||||
|
||||
or it can be manually definied as
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
var myContract = new EmbarkJS.Contract({abi: abiObject, code: code});
|
||||
myContract.deploy().then(function(anotherMyContractObject) {});
|
|
@ -0,0 +1,40 @@
|
|||
.. embark documentation master file, created by
|
||||
sphinx-quickstart on Tue Jan 10 06:39:27 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to embark's documentation!
|
||||
==================================
|
||||
|
||||
This is a work in progress, feel free to contribute!
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation.rst
|
||||
usage.rst
|
||||
dashboard.rst
|
||||
creating-a-new-dapp.rst
|
||||
libraries-and-languages-available.rst
|
||||
using-contracts.rst
|
||||
configuring-storage.rst
|
||||
configuring-communication.rst
|
||||
embarkjs.rst
|
||||
embarkjs-storage.rst
|
||||
embarkjs-communication.rst
|
||||
tests.rst
|
||||
working-with-different-chains.rst
|
||||
structuring-application.rst
|
||||
deploying-to-ipfs.rst
|
||||
deploying-to-swarm.rst
|
||||
plugins.rst
|
||||
using-embark-with-grunt.rst
|
||||
donations.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
Installation
|
||||
============
|
||||
|
||||
Requirements: geth (1.5.8 or higher), node (6.9.1 or higher is recommended) and npm
|
||||
serpent (develop) if using contracts with Serpent, testrpc (3.0 or higher)
|
||||
if using the simulator or the test functionality. Further: depending on
|
||||
the dapp stack you choose: `IPFS <https://ipfs.io/>`__
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ npm -g install embark
|
||||
|
||||
# If you plan to use the simulator instead of a real ethereum node.
|
||||
$ npm -g install ethereumjs-testrpc
|
||||
|
||||
See `Complete Installation
|
||||
Instructions <https://github.com/iurimatias/embark-framework/wiki/Installation>`__.
|
||||
|
||||
**updating from embark 1**
|
||||
|
||||
Embark's npm package has changed from ``embark-framework`` to
|
||||
``embark``, this sometimes can create conflicts. To update first
|
||||
uninstall embark-framework 1 to avoid any conflicts.
|
||||
``npm uninstall -g embark-framework`` then ``npm install -g embark``
|
|
@ -0,0 +1,14 @@
|
|||
Libraries and languages available
|
||||
=================================
|
||||
|
||||
Embark can build and deploy contracts coded in Solidity or Serpent. It
|
||||
will make them available on the client side using EmbarkJS and Web3.js.
|
||||
|
||||
Further documentation for these can be found below:
|
||||
|
||||
- Smart Contracts:
|
||||
`Solidity <https://solidity.readthedocs.io/en/develop/>`__ and
|
||||
`Serpent <https://github.com/ethereum/wiki/wiki/Serpent>`__
|
||||
- Client Side:
|
||||
`Web3.js <https://github.com/ethereum/wiki/wiki/JavaScript-API>`__
|
||||
and `EmbarkJS <#embarkjs>`__
|
|
@ -0,0 +1,36 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=embark
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,296 @@
|
|||
Extending functionality with plugins
|
||||
====================================
|
||||
|
||||
**To add a plugin to embark:**
|
||||
|
||||
1. Add the npm package to package.json
|
||||
e.g ``npm install embark-babel --save``
|
||||
2. Then add the package to ``plugins:`` in embark.json
|
||||
e.g ``"plugins": { "embark-babel": {} }``
|
||||
|
||||
**Creating a plugin:**
|
||||
|
||||
1. ``mkdir yourpluginname``
|
||||
2. ``cd yourpluginname``
|
||||
3. ``npm init``
|
||||
4. create and edit ``index.js``
|
||||
5. add the following code:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
}
|
||||
|
||||
The ``embark`` object then provides an api to extend different functionality of embark.
|
||||
|
||||
**Usecases examples**
|
||||
|
||||
* plugin to add support for es6, jsx, coffescript, etc (``embark.registerPipeline``)
|
||||
* plugin to add standard contracts or a contract framework (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||
* plugin to make some contracts available in all environments for use by other contracts or the dapp itself e.g a Token, a DAO, ENS, etc.. (``embark.registerContractConfiguration`` and ``embark.addContractFile``)
|
||||
* plugin to add a libraries such as react or boostrap (``embark.addFileToPipeline``)
|
||||
* plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``)
|
||||
* plugin to create a different contract wrapper (``embark.registerContractsGeneration``)
|
||||
* plugin to add new console commands (``embark.registerConsoleCommand``)
|
||||
* plugin to add support for another contract language such as viper, LLL, etc (``embark.registerCompiler``)
|
||||
* plugin that executes certain actions when contracts are deployed (``embark.events.on``)
|
||||
|
||||
**embark.pluginConfig**
|
||||
|
||||
Object containing the config for the plugin specified in embark.json, for e.g with:
|
||||
|
||||
.. code:: json
|
||||
|
||||
"plugins": {
|
||||
"embark-babel": { "files": ["**/*.js", "!**/jquery.min.js"], "presets": ["es2015", "react"] }
|
||||
}
|
||||
|
||||
``embark.pluginConfig`` will contain ``{ "files": ["**/*.js", "!**/jquery.min.js"], "presets": ["es2015", "react"] }``
|
||||
|
||||
**embark.registerPipeline(matchingFiles, callback(options))**
|
||||
|
||||
This call will return the content of the current asset file so the plugin can transform it in some way. Typically this is used to implement pipeline plugins such as Babel, JSX, sass to css, etc..
|
||||
|
||||
``matchingFiles`` is an array of matching files the plugin should be called for e.g [``**/*.js``, ``!vendor/jquery.js``] matches all javascript files except vendor/jquery.js
|
||||
|
||||
options available:
|
||||
* targetFile - filename to be generated
|
||||
* source - content of the file
|
||||
|
||||
expected return: ``string``
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
var babel = require("babel-core");
|
||||
require("babel-preset-react");
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerPipeline(["**/*.js", "**/*.jsx"], function(options) {
|
||||
return babel.transform(options.source, {minified: true, presets: ['react']}).code;
|
||||
});
|
||||
}
|
||||
|
||||
**embark.registerContractConfiguration(contractsConfig)**
|
||||
|
||||
This call is used to specify a configure of one or more contracts in one or
|
||||
several environments. This is useful for specifying the different configurations
|
||||
a contract might have depending on the enviroment. For instance in the code
|
||||
bellow, the ``DGDToken`` contract code will redeployed with the arguments
|
||||
``100`` in any environment, except for the livenet since it's already deployed
|
||||
there at a particular address.
|
||||
|
||||
Typically this call is used in combination with ``embark.addContractFile``
|
||||
|
||||
``contractsConfig`` is an object in the same structure as the one found in the
|
||||
contracts configuration at ``config/contracts.json``. The users own
|
||||
configuration will be merged with the one specified in the plugins.
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerContractConfiguration({
|
||||
"default": {
|
||||
"contracts": {
|
||||
"DGDToken": {
|
||||
"args": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"livenet": {
|
||||
"contracts": {
|
||||
"DGDToken": {
|
||||
"address": "0xe0b7927c4af23765cb51314a0e0521a9645f0e2a"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
**embark.addContractFile(file)**
|
||||
|
||||
Typically this call is used in combination with ``embark.registerContractConfiguration``. If you want to make the contract available but not automatically deployed without the user specifying so you can use ``registerContractConfiguration`` to set the contract config to ``deploy: false``, this is particularly useful for when the user is meant to extend the contract being given (e.g ``contract MyToken is StandardToken``)
|
||||
|
||||
``file`` is the contract file to add to embark, the path should relative to the plugin.
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.addContractFile("./DGDToken.sol");
|
||||
}
|
||||
|
||||
**embark.addFileToPipeline(file, options)**
|
||||
|
||||
This call is used to add a file to the pipeline so it's included with the dapp on the client side.
|
||||
|
||||
``file`` is the file to add to the pipeline, the path should relative to the plugin.
|
||||
|
||||
``options`` available:
|
||||
* skipPipeline - If true it will not apply transformations to the file. For
|
||||
example if you have a babel plugin to transform es6 code or a minifier plugin, setting this to
|
||||
true will not apply the plugin on this file.
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.addFileToPipeline("./jquery.js", {skipPipeline: true});
|
||||
}
|
||||
|
||||
|
||||
**embark.registerClientWeb3Provider(callback(options))**
|
||||
|
||||
This call can be used to override the default web3 object generation in the dapp. it's useful if you want to add a plugin to interact with services like http://infura.io or if you want to use your own web3.js library extension.
|
||||
|
||||
options available:
|
||||
* rpcHost - configured rpc Host to connect to
|
||||
* rpcPort - configured rpc Port to connect to
|
||||
* blockchainConfig - object containing the full blockchain configuration for the current environment
|
||||
|
||||
expected return: ``string``
|
||||
|
||||
example:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerClientWeb3Provider(function(options) {
|
||||
return "web3 = new Web3(new Web3.providers.HttpProvider('http://" + options.rpcHost + ":" + options.rpcPort + "');";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
**embark.registerContractsGeneration(callback(options))**
|
||||
|
||||
By default Embark will use EmbarkJS to declare contracts in the dapp. You can override and use your own client side library.
|
||||
|
||||
options available:
|
||||
* contracts - Hash of objects containing all the deployed contracts. (key: contractName, value: contract object)
|
||||
* abiDefinition
|
||||
* code
|
||||
* deployedAddress
|
||||
* gasEstimates
|
||||
* gas
|
||||
* gasPrice
|
||||
* runtimeByteCode
|
||||
|
||||
expected return: ``string``
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerContractsGeneration(function(options) {
|
||||
for(var className in this.contractsManager.contracts) {
|
||||
var abi = JSON.stringify(contract.abiDefinition);
|
||||
|
||||
return className + " = " + web3.eth.contract(" + abi + ").at('" + contract.deployedAddress + "');";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
**embark.registerConsoleCommand(callback(options))**
|
||||
|
||||
This call is used to extend the console with custom commands.
|
||||
|
||||
expected return: ``string`` (output to print in console) or ``boolean`` (skip command if false)
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerConsoleCommand(function(cmd, options) {
|
||||
if (cmd === "hello") {
|
||||
return "hello there!";
|
||||
}
|
||||
// continue to embark or next plugin;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
**embark.registerCompiler(extension, callback(contractFiles, doneCallback))**
|
||||
|
||||
expected doneCallback arguments: ``err`` and ``hash`` of compiled contracts
|
||||
|
||||
* Hash of objects containing the compiled contracts. (key: contractName, value: contract object)
|
||||
|
||||
* code - contract bytecode (string)
|
||||
|
||||
* runtimeBytecode - contract runtimeBytecode (string)
|
||||
|
||||
* gasEstimates - gas estimates for constructor and methods (hash)
|
||||
* e.g ``{"creation":[20131,38200],"external":{"get()":269,"set(uint256)":20163,"storedData()":224},"internal":{}}``
|
||||
* functionHashes - object with methods and their corresponding hash identifier (hash)
|
||||
* e.g ``{"get()":"6d4ce63c","set(uint256)":"60fe47b1","storedData()":"2a1afcd9"}``
|
||||
* abiDefinition - contract abi (array of objects)
|
||||
* e.g ``[{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}, etc...``
|
||||
|
||||
below a possible implementation of a solcjs plugin:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
var solc = require('solc');
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.registerCompiler(".sol", function(contractFiles, cb) {
|
||||
// prepare input for solc
|
||||
var input = {};
|
||||
for (var i = 0; i < contractFiles.length; i++) {
|
||||
var filename = contractFiles[i].filename.replace('app/contracts/','');
|
||||
input[filename] = contractFiles[i].content.toString();
|
||||
}
|
||||
|
||||
// compile files
|
||||
var output = solc.compile({sources: input}, 1);
|
||||
|
||||
// generate the compileObject expected by embark
|
||||
var json = output.contracts;
|
||||
var compiled_object = {};
|
||||
for (var className in json) {
|
||||
var contract = json[className];
|
||||
|
||||
compiled_object[className] = {};
|
||||
compiled_object[className].code = contract.bytecode;
|
||||
compiled_object[className].runtimeBytecode = contract.runtimeBytecode;
|
||||
compiled_object[className].gasEstimates = contract.gasEstimates;
|
||||
compiled_object[className].functionHashes = contract.functionHashes;
|
||||
compiled_object[className].abiDefinition = JSON.parse(contract.interface);
|
||||
}
|
||||
|
||||
cb(null, compiled_object);
|
||||
});
|
||||
}
|
||||
|
||||
**embark.logger**
|
||||
|
||||
To print messages to the embark log is it better to use ``embark.logger``
|
||||
instead of ``console``.
|
||||
|
||||
e.g ``embark.logger.info("hello")``
|
||||
|
||||
**embark.events.on(eventName, callback(*args))**
|
||||
|
||||
This call is used to listen and react to events that happen in Embark such as contract deployment
|
||||
|
||||
* eventName - name of event to listen to
|
||||
* available events:
|
||||
* "contractsDeployed" - triggered when contracts have been deployed
|
||||
* "file-add", "file-change", "file-remove", "file-event" - triggered on
|
||||
a file change, args is (filetype, path)
|
||||
* "abi", "abi-vanila", "abi-contracts-vanila" - triggered when contracts
|
||||
have been deployed and returns the generated JS code
|
||||
* "outputDone" - triggered when dapp is (re)generated
|
||||
* "firstDeploymentDone" - triggered when the dapp is deployed and generated
|
||||
for the first time
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
module.exports = function(embark) {
|
||||
embark.events.on("contractsDeployed", function() {
|
||||
embark.logger.info("plugin says: your contracts have been deployed");
|
||||
});
|
||||
embark.events.on("file-changed", function(filetype, path) {
|
||||
if (type === 'contract') {
|
||||
embark.logger.info("plugin says: you just changed the contract at " + path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
Structuring Application
|
||||
=======================
|
||||
|
||||
Embark is quite flexible and you can configure you're own directory
|
||||
structure using ``embark.json``
|
||||
|
||||
.. code:: json
|
||||
|
||||
# embark.json
|
||||
{
|
||||
"contracts": ["app/contracts/**"],
|
||||
"app": {
|
||||
"css/app.css": ["app/css/**"],
|
||||
"images/": ["app/images/**"],
|
||||
"js/app.js": ["embark.js", "app/js/**"],
|
||||
"index.html": "app/index.html"
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"plugins": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
Testing Ethereum Contracts
|
||||
==========================
|
||||
|
||||
You can run specs with ``embark test``, it will run any test files under
|
||||
``test/``.
|
||||
|
||||
Embark includes a testing lib to fastly run & test your contracts in a
|
||||
EVM.
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
# test/simple_storage_spec.js
|
||||
|
||||
var assert = require('assert');
|
||||
var Embark = require('embark');
|
||||
var EmbarkSpec = Embark.initTests();
|
||||
var web3 = EmbarkSpec.web3;
|
||||
|
||||
describe("SimpleStorage", function() {
|
||||
before(function(done) {
|
||||
var contractsConfig = {
|
||||
"SimpleStorage": {
|
||||
args: [100]
|
||||
}
|
||||
};
|
||||
EmbarkSpec.deployAll(contractsConfig, done);
|
||||
});
|
||||
|
||||
it("should set constructor value", function(done) {
|
||||
SimpleStorage.storedData(function(err, result) {
|
||||
assert.equal(result.toNumber(), 100);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("set storage value", function(done) {
|
||||
SimpleStorage.set(150, function() {
|
||||
SimpleStorage.get(function(err, result) {
|
||||
assert.equal(result.toNumber(), 150);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Embark uses `Mocha <http://mochajs.org/>`__ by default, but you can use
|
||||
any testing framework you want.
|
|
@ -0,0 +1,44 @@
|
|||
Usage
|
||||
=====
|
||||
|
||||
Usage - Demo
|
||||
============
|
||||
|
||||
You can easily create a sample working DApp with the following:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark demo
|
||||
$ cd embark_demo
|
||||
|
||||
You can run a REAL ethereum node for development purposes:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark blockchain
|
||||
|
||||
Alternatively, to use an ethereum rpc simulator simply run:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark simulator
|
||||
|
||||
By default embark blockchain will mine a minimum amount of ether and
|
||||
will only mine when new transactions come in. This is quite usefull to
|
||||
keep a low CPU. The option can be configured at
|
||||
``config/blockchain.json``. Note that running a real node requires at
|
||||
least 2GB of free ram, please take this into account if running it in a
|
||||
VM.
|
||||
|
||||
Then, in another command line:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
$ embark run
|
||||
|
||||
This will automatically deploy the contracts, update their JS bindings
|
||||
and deploy your DApp to a local server at http://localhost:8000
|
||||
|
||||
Note that if you update your code it will automatically be re-deployed,
|
||||
contracts included. There is no need to restart embark, refreshing the
|
||||
page on the browser will do.
|
|
@ -0,0 +1,138 @@
|
|||
Configuring & Using Contracts
|
||||
===============
|
||||
|
||||
Embark will automatically take care of deployment for you and set all
|
||||
needed JS bindings. For example, the contract below:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
# app/contracts/simple_storage.sol
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
function SimpleStorage(uint initialValue) {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
function set(uint x) {
|
||||
storedData = x;
|
||||
}
|
||||
function get() constant returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
}
|
||||
|
||||
Will automatically be available in Javascript as:
|
||||
|
||||
.. code:: javascript
|
||||
|
||||
# app/js/index.js
|
||||
SimpleStorage.set(100);
|
||||
SimpleStorage.get().then(function(value) { console.log(value.toNumber()) });
|
||||
SimpleStorage.storedData().then(function(value) { console.log(value.toNumber()) });
|
||||
|
||||
You can specify for each contract and environment its gas costs and
|
||||
arguments:
|
||||
|
||||
.. code:: json
|
||||
|
||||
# config/contracts.json
|
||||
{
|
||||
"development": {
|
||||
"gas": "auto",
|
||||
"contracts": {
|
||||
"SimpleStorage": {
|
||||
"args": [
|
||||
100
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
If you are using multiple contracts, you can pass a reference to another
|
||||
contract as ``$ContractName``, Embark will automatically replace this
|
||||
with the correct address for the contract.
|
||||
|
||||
.. code:: json
|
||||
|
||||
# config/contracts.json
|
||||
{
|
||||
...
|
||||
"development": {
|
||||
"contracts": {
|
||||
"SimpleStorage": {
|
||||
"args": [
|
||||
100,
|
||||
$MyStorage
|
||||
]
|
||||
},
|
||||
"MyStorage": {
|
||||
"args": [
|
||||
"initial string"
|
||||
]
|
||||
},
|
||||
"MyMainContract": {
|
||||
"args": [
|
||||
$SimpleStorage
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
You can now deploy many instances of the same contract. e.g
|
||||
|
||||
.. code:: json
|
||||
|
||||
# config/contracts.json
|
||||
{
|
||||
"development": {
|
||||
"contracts": {
|
||||
"Currency": {
|
||||
"deploy": false,
|
||||
"args": [
|
||||
100
|
||||
]
|
||||
},
|
||||
"Usd": {
|
||||
"instanceOf": "Currency",
|
||||
"args": [
|
||||
200
|
||||
]
|
||||
},
|
||||
"MyCoin": {
|
||||
"instanceOf": "Currency",
|
||||
"args": [
|
||||
200
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
Contracts addresses can be defined, If an address is defined the
|
||||
contract wouldn't be deployed but its defined address will be used
|
||||
instead.
|
||||
|
||||
.. code:: json
|
||||
|
||||
# config/contracts.json
|
||||
{
|
||||
...
|
||||
"development": {
|
||||
"contracts": {
|
||||
"UserStorage": {
|
||||
"address": "0x123456"
|
||||
},
|
||||
"UserManagement": {
|
||||
"args": [
|
||||
"$UserStorage"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
Using Embark with Grunt
|
||||
====================================
|
||||
|
||||
**1. Edit embark.json**
|
||||
|
||||
Edit ``embark.json`` to have the line ``"js/app.js": ["embark.js"]``, this will make embark create the file containing the contracts initilization to ``dist/app.js``.
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"contracts": ["app/contracts/**"],
|
||||
"app": {
|
||||
"app.js": ["embark.js"]
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"plugins": {
|
||||
}
|
||||
}
|
||||
|
||||
**2. add the generated file to Grunt config file so it's included with the other assets**
|
||||
|
||||
.. code:: coffee
|
||||
|
||||
module.exports = (grunt) ->
|
||||
|
||||
grunt.initConfig(
|
||||
files:
|
||||
js:
|
||||
src: [
|
||||
"dist/app.js"
|
||||
"app/js/**/*.js"
|
||||
]
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Working with different chains
|
||||
=============================
|
||||
|
||||
You can specify which environment to deploy to:
|
||||
|
||||
``$ embark blockchain livenet``
|
||||
|
||||
``$ embark run livenet``
|
||||
|
||||
The environment is a specific blockchain configuration that can be
|
||||
managed at config/blockchain.json
|
||||
|
||||
.. code:: json
|
||||
|
||||
# config/blockchain.json
|
||||
...
|
||||
"livenet": {
|
||||
"networkType": "livenet",
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"account": {
|
||||
"password": "config/livenet/password"
|
||||
}
|
||||
},
|
||||
...
|
5476
js/bluebird.js
5476
js/bluebird.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
210
js/embark.js
210
js/embark.js
|
@ -1,4 +1,4 @@
|
|||
var Promise = require('bluebird');
|
||||
/*jshint esversion: 6 */
|
||||
//var Ipfs = require('./ipfs.js');
|
||||
|
||||
var EmbarkJS = {
|
||||
|
@ -10,7 +10,7 @@ EmbarkJS.Contract = function(options) {
|
|||
|
||||
this.abi = options.abi;
|
||||
this.address = options.address;
|
||||
this.code = options.code;
|
||||
this.code = '0x' + options.code;
|
||||
this.web3 = options.web3 || web3;
|
||||
|
||||
var ContractClass = this.web3.eth.contract(this.abi);
|
||||
|
@ -59,40 +59,73 @@ EmbarkJS.Contract = function(options) {
|
|||
};
|
||||
return true;
|
||||
} else if (typeof self._originalContractObject[p] === 'function') {
|
||||
self[p] = Promise.promisify(self._originalContractObject[p]);
|
||||
self[p] = function(_args) {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var fn = self._originalContractObject[p];
|
||||
var props = self.abi.find((x) => x.name == p);
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
args.push(function(err, transaction) {
|
||||
promise.tx = transaction;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
var getConfirmation = function() {
|
||||
self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (receipt !== null) {
|
||||
return resolve(receipt);
|
||||
}
|
||||
|
||||
setTimeout(getConfirmation, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
if (typeof(transaction) !== "string" || props.constant) {
|
||||
resolve(transaction);
|
||||
} else {
|
||||
getConfirmation();
|
||||
}
|
||||
});
|
||||
|
||||
fn.apply(fn, args);
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
EmbarkJS.Contract.prototype.deploy = function(args) {
|
||||
EmbarkJS.Contract.prototype.deploy = function(args, _options) {
|
||||
var self = this;
|
||||
var contractParams;
|
||||
var options = _options || {};
|
||||
|
||||
contractParams = args || [];
|
||||
|
||||
contractParams.push({
|
||||
from: this.web3.eth.accounts[0],
|
||||
data: this.code,
|
||||
gas: 500000,
|
||||
gasPrice: 10000000000000
|
||||
gas: options.gas || 800000
|
||||
});
|
||||
|
||||
var contractObject = this.web3.eth.contract(this.abi);
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
contractParams.push(function(err, transaction) {
|
||||
console.log("callback");
|
||||
if (err) {
|
||||
console.log("error");
|
||||
reject(err);
|
||||
} else if (transaction.address !== undefined) {
|
||||
console.log("address contract: " + transaction.address);
|
||||
resolve(new EmbarkJS.Contract({abi: self.abi, code: self.code, address: transaction.address}));
|
||||
}
|
||||
});
|
||||
console.log(contractParams);
|
||||
|
||||
// returns promise
|
||||
// deploys contract
|
||||
|
@ -109,13 +142,14 @@ EmbarkJS.IPFS = 'ipfs';
|
|||
EmbarkJS.Storage = {
|
||||
};
|
||||
|
||||
// EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'})<F37>
|
||||
//{server: ‘localhost’, port: ‘5001’};
|
||||
|
||||
EmbarkJS.Storage.setProvider = function(provider, options) {
|
||||
if (provider === 'ipfs') {
|
||||
this.currentStorage = EmbarkJS.Storage.IPFS;
|
||||
this.ipfsConnection = IpfsApi(options.server, options.port);
|
||||
if (options === undefined) {
|
||||
this.ipfsConnection = IpfsApi('localhost', '5001');
|
||||
} else {
|
||||
this.ipfsConnection = IpfsApi(options.server, options.port);
|
||||
}
|
||||
} else {
|
||||
throw Error('unknown provider');
|
||||
}
|
||||
|
@ -123,6 +157,9 @@ EmbarkJS.Storage.setProvider = function(provider, options) {
|
|||
|
||||
EmbarkJS.Storage.saveText = function(text) {
|
||||
var self = this;
|
||||
if (!this.ipfsConnection) {
|
||||
this.setProvider('ipfs');
|
||||
}
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self.ipfsConnection.add((new self.ipfsConnection.Buffer(text)), function(err, result) {
|
||||
if (err) {
|
||||
|
@ -144,6 +181,10 @@ EmbarkJS.Storage.uploadFile = function(inputSelector) {
|
|||
throw new Error('no file found');
|
||||
}
|
||||
|
||||
if (!this.ipfsConnection) {
|
||||
this.setProvider('ipfs');
|
||||
}
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
|
@ -167,6 +208,9 @@ EmbarkJS.Storage.get = function(hash) {
|
|||
var self = this;
|
||||
// TODO: detect type, then convert if needed
|
||||
//var ipfsHash = web3.toAscii(hash);
|
||||
if (!this.ipfsConnection) {
|
||||
this.setProvider('ipfs');
|
||||
}
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self.ipfsConnection.object.get([hash]).then(function(node) {
|
||||
|
@ -186,20 +230,45 @@ EmbarkJS.Storage.getUrl = function(hash) {
|
|||
EmbarkJS.Messages = {
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.setProvider = function(provider) {
|
||||
EmbarkJS.Messages.setProvider = function(provider, options) {
|
||||
var self = this;
|
||||
var ipfs;
|
||||
if (provider === 'whisper') {
|
||||
this.currentMessages = EmbarkJS.Messages.Whisper;
|
||||
if (typeof variable === 'undefined') {
|
||||
if (options === undefined) {
|
||||
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
|
||||
} else {
|
||||
web3 = new Web3(new Web3.providers.HttpProvider("http://" + options.server + ':' + options.port));
|
||||
}
|
||||
}
|
||||
web3.version.getWhisper(function(err, res) {
|
||||
if (err) {
|
||||
console.log("whisper not available");
|
||||
} else {
|
||||
self.currentMessages.identity = web3.shh.newIdentity();
|
||||
}
|
||||
});
|
||||
} else if (provider === 'orbit') {
|
||||
this.currentMessages = EmbarkJS.Messages.Orbit;
|
||||
if (options === undefined) {
|
||||
ipfs = HaadIpfsApi('localhost', '5001');
|
||||
} else {
|
||||
ipfs = HaadIpfsApi(options.server, options.port);
|
||||
}
|
||||
this.currentMessages.orbit = new Orbit(ipfs);
|
||||
this.currentMessages.orbit.connect(web3.eth.accounts[0]);
|
||||
} else {
|
||||
throw Error('unknown provider');
|
||||
}
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.sendMessage = function(options) {
|
||||
return EmbarkJS.Messages.Whisper.sendMessage(options);
|
||||
return this.currentMessages.sendMessage(options);
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.listenTo = function(options) {
|
||||
return EmbarkJS.Messages.Whisper.listenTo(options);
|
||||
return this.currentMessages.listenTo(options);
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.Whisper = {
|
||||
|
@ -208,9 +277,10 @@ EmbarkJS.Messages.Whisper = {
|
|||
EmbarkJS.Messages.Whisper.sendMessage = function(options) {
|
||||
var topics = options.topic || options.topics;
|
||||
var data = options.data || options.payload;
|
||||
var identity = options.identity || web3.shh.newIdentity();
|
||||
var identity = options.identity || this.identity || web3.shh.newIdentity();
|
||||
var ttl = options.ttl || 100;
|
||||
var priority = options.priority || 1000;
|
||||
var _topics;
|
||||
|
||||
if (topics === undefined) {
|
||||
throw new Error("missing option: topic");
|
||||
|
@ -222,42 +292,41 @@ EmbarkJS.Messages.Whisper.sendMessage = function(options) {
|
|||
|
||||
// do fromAscii to each topics unless it's already a string
|
||||
if (typeof topics === 'string') {
|
||||
topics = topics;
|
||||
_topics = [web3.fromAscii(topics)];
|
||||
} else {
|
||||
// TODO: replace with es6 + babel;
|
||||
var _topics = [];
|
||||
for (var i = 0; i < topics.length; i++) {
|
||||
_topics.push(web3.fromAscii(topics[i]));
|
||||
}
|
||||
topics = _topics;
|
||||
}
|
||||
topics = _topics;
|
||||
|
||||
var payload = JSON.stringify(data);
|
||||
|
||||
var message = {
|
||||
from: identity,
|
||||
topics: [web3.fromAscii(topics)],
|
||||
topics: topics,
|
||||
payload: web3.fromAscii(payload),
|
||||
ttl: ttl,
|
||||
priority: priority
|
||||
};
|
||||
|
||||
return web3.shh.post(message);
|
||||
return web3.shh.post(message, function() {});
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.Whisper.listenTo = function(options) {
|
||||
var topics = options.topic || options.topics;
|
||||
var _topics = [];
|
||||
|
||||
if (typeof topics === 'string') {
|
||||
topics = [topics];
|
||||
_topics = [topics];
|
||||
} else {
|
||||
// TODO: replace with es6 + babel;
|
||||
var _topics = [];
|
||||
for (var i = 0; i < topics.length; i++) {
|
||||
_topics.push(web3.fromAscii(topics[i]));
|
||||
_topics.push(topics[i]);
|
||||
}
|
||||
topics = _topics;
|
||||
}
|
||||
topics = _topics;
|
||||
|
||||
var filterOptions = {
|
||||
topics: topics
|
||||
|
@ -275,17 +344,102 @@ EmbarkJS.Messages.Whisper.listenTo = function(options) {
|
|||
return err;
|
||||
};
|
||||
|
||||
messageEvents.prototype.stop = function() {
|
||||
this.filter.stopWatching();
|
||||
};
|
||||
|
||||
var promise = new messageEvents();
|
||||
|
||||
var filter = web3.shh.filter(filterOptions, function(err, result) {
|
||||
var payload = JSON.parse(web3.toAscii(result.payload));
|
||||
var data;
|
||||
if (err) {
|
||||
promise.error(err);
|
||||
} else {
|
||||
promise.cb(payload);
|
||||
data = {
|
||||
topic: topics,
|
||||
data: payload,
|
||||
from: result.from,
|
||||
time: (new Date(result.sent * 1000))
|
||||
};
|
||||
promise.cb(payload, data, result);
|
||||
}
|
||||
});
|
||||
|
||||
promise.filter = filter;
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.Orbit = {
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.Orbit.sendMessage = function(options) {
|
||||
var topics = options.topic || options.topics;
|
||||
var data = options.data || options.payload;
|
||||
|
||||
if (topics === undefined) {
|
||||
throw new Error("missing option: topic");
|
||||
}
|
||||
|
||||
if (data === undefined) {
|
||||
throw new Error("missing option: data");
|
||||
}
|
||||
|
||||
if (typeof topics === 'string') {
|
||||
topics = topics;
|
||||
} else {
|
||||
// TODO: better to just send to different channels instead
|
||||
topics = topics.join(',');
|
||||
}
|
||||
|
||||
this.orbit.join(topics);
|
||||
|
||||
var payload = JSON.stringify(data);
|
||||
|
||||
this.orbit.send(topics, data);
|
||||
};
|
||||
|
||||
EmbarkJS.Messages.Orbit.listenTo = function(options) {
|
||||
var self = this;
|
||||
var topics = options.topic || options.topics;
|
||||
|
||||
if (typeof topics === 'string') {
|
||||
topics = topics;
|
||||
} else {
|
||||
topics = topics.join(',');
|
||||
}
|
||||
|
||||
this.orbit.join(topics);
|
||||
|
||||
var messageEvents = function() {
|
||||
this.cb = function() {};
|
||||
};
|
||||
|
||||
messageEvents.prototype.then = function(cb) {
|
||||
this.cb = cb;
|
||||
};
|
||||
|
||||
messageEvents.prototype.error = function(err) {
|
||||
return err;
|
||||
};
|
||||
|
||||
var promise = new messageEvents();
|
||||
|
||||
this.orbit.events.on('message', (channel, message) => {
|
||||
// TODO: looks like sometimes it's receving messages from all topics
|
||||
if (topics !== channel) return;
|
||||
self.orbit.getPost(message.payload.value, true).then((post) => {
|
||||
var data = {
|
||||
topic: channel,
|
||||
data: post.content,
|
||||
from: post.meta.from.name,
|
||||
time: (new Date(post.meta.ts))
|
||||
};
|
||||
promise.cb(post.content, data, post);
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
694
js/web3.js
694
js/web3.js
File diff suppressed because it is too large
Load Diff
52
lib/abi.js
52
lib/abi.js
|
@ -1,52 +0,0 @@
|
|||
|
||||
var ABIGenerator = function(blockchainConfig, contractsManager) {
|
||||
this.blockchainConfig = blockchainConfig;
|
||||
this.contractsManager = contractsManager;
|
||||
this.rpcHost = blockchainConfig.rpcHost;
|
||||
this.rpcPort = blockchainConfig.rpcPort;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateProvider = function() {
|
||||
var result = "";
|
||||
|
||||
result += "\nif (typeof web3 !== 'undefined' && typeof Web3 !== 'undefined') {";
|
||||
result += '\n\tweb3 = new Web3(web3.currentProvider);';
|
||||
result += "\n} else if (typeof Web3 !== 'undefined') {";
|
||||
result += '\n\tweb3 = new Web3(new Web3.providers.HttpProvider("http://' + this.rpcHost + ':' + this.rpcPort + '"));';
|
||||
result += '\n}';
|
||||
result += "\nweb3.eth.defaultAccount = web3.eth.accounts[0];";
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateContracts = function(useEmbarkJS) {
|
||||
var result = "\n";
|
||||
|
||||
for(var className in this.contractsManager.contracts) {
|
||||
var contract = this.contractsManager.contracts[className];
|
||||
|
||||
var abi = JSON.stringify(contract.abiDefinition);
|
||||
var gasEstimates = JSON.stringify(contract.gasEstimates);
|
||||
|
||||
if (useEmbarkJS) {
|
||||
result += "\n" + className + " = new EmbarkJS.Contract({abi: " + abi + ", address: '" + contract.deployedAddress + "', code: '" + contract.code + "', gasEstimates: " + gasEstimates + "});";
|
||||
} else {
|
||||
result += "\n" + className + "Abi = " + abi + ";";
|
||||
result += "\n" + className + "Contract = web3.eth.contract(" + className + "Abi);";
|
||||
result += "\n" + className + " = " + className + "Contract.at('" + contract.deployedAddress + "');";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateABI = function(options) {
|
||||
var result = "";
|
||||
|
||||
result += this.generateProvider();
|
||||
result += this.generateContracts(options.useEmbarkJS);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = ABIGenerator;
|
89
lib/cmd.js
89
lib/cmd.js
|
@ -1,9 +1,10 @@
|
|||
var program = require('commander');
|
||||
var colors = require('colors');
|
||||
var shelljs = require('shelljs');
|
||||
|
||||
var Cmd = function(Embark) {
|
||||
this.Embark = Embark;
|
||||
program.version('2.1.4');
|
||||
program.version(Embark.version);
|
||||
};
|
||||
|
||||
Cmd.prototype.process = function(args) {
|
||||
|
@ -14,8 +15,14 @@ Cmd.prototype.process = function(args) {
|
|||
this.blockchain();
|
||||
this.simulator();
|
||||
this.test();
|
||||
this.ipfs();
|
||||
this.upload();
|
||||
this.otherCommands();
|
||||
|
||||
//If no arguments are passed display help by default
|
||||
if (!process.argv.slice(2).length) {
|
||||
program.help();
|
||||
}
|
||||
|
||||
program.parse(args);
|
||||
};
|
||||
|
||||
|
@ -29,7 +36,7 @@ Cmd.prototype.newApp = function() {
|
|||
console.log("please specify your app Name".red);
|
||||
console.log("e.g embark new MyApp".green);
|
||||
console.log("e.g embark new --help for more information".green);
|
||||
exit();
|
||||
process.exit(code);
|
||||
}
|
||||
self.Embark.generateTemplate('boilerplate', './', name);
|
||||
});
|
||||
|
@ -51,10 +58,7 @@ Cmd.prototype.build = function() {
|
|||
.command('build [environment]')
|
||||
.description('deploy and build dapp at dist/ (default: development)')
|
||||
.action(function(env, options) {
|
||||
self.Embark.initConfig(env || 'development', {
|
||||
embarkConfig: 'embark.json'
|
||||
});
|
||||
self.Embark.build(env || 'development');
|
||||
self.Embark.build({env: env || 'development'});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -62,13 +66,20 @@ Cmd.prototype.run = function() {
|
|||
var self = this;
|
||||
program
|
||||
.command('run [environment]')
|
||||
.option('-p, --port [port]', 'port to run the dev webserver')
|
||||
.option('-p, --port [port]', 'port to run the dev webserver (default: 8000)')
|
||||
.option('-b, --host [host]', 'host to run the dev webserver (default: localhost)')
|
||||
.option('--noserver', 'disable the development webserver')
|
||||
.option('--nodashboard', 'simple mode, disables the dashboard')
|
||||
.option('--no-color', 'no colors in case it\'s needed for compatbility purposes')
|
||||
.description('run dapp (default: development)')
|
||||
.action(function(env, options) {
|
||||
self.Embark.initConfig(env || 'development', {
|
||||
embarkConfig: 'embark.json'
|
||||
self.Embark.run({
|
||||
env: env || 'development',
|
||||
serverPort: options.port,
|
||||
serverHost: options.host,
|
||||
runWebserver: !options.noserver,
|
||||
useDashboard: !options.nodashboard
|
||||
});
|
||||
self.Embark.run({env: env || 'development', serverPort: options.port});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -80,41 +91,27 @@ Cmd.prototype.blockchain = function() {
|
|||
.description('run blockchain server (default: development)')
|
||||
.action(function(env ,options) {
|
||||
self.Embark.initConfig(env || 'development', {
|
||||
embarkConfig: 'embark.json'
|
||||
embarkConfig: 'embark.json',
|
||||
interceptLogs: false
|
||||
});
|
||||
self.Embark.blockchain(env || 'development', options.client || 'geth');
|
||||
});
|
||||
};
|
||||
|
||||
Cmd.prototype.simulator = function() {
|
||||
var self = this;
|
||||
program
|
||||
.command('simulator')
|
||||
.command('simulator [environment]')
|
||||
.description('run a fast ethereum rpc simulator')
|
||||
.option('--testrpc', 'use testrpc as the rpc simulator [default]')
|
||||
.option('--ethersim', 'use ethersim as the rpc simulator')
|
||||
.action(function(options) {
|
||||
var Sim;
|
||||
|
||||
if (options.ethersim) {
|
||||
try {
|
||||
Sim = require('ethersim');
|
||||
} catch(e) {
|
||||
console.log('EtherSim not found; Please install it with "npm install ethersim --save"');
|
||||
console.log('For more information see https://github.com/iurimatias/ethersim');
|
||||
process.exit(1);
|
||||
}
|
||||
Sim.startServer();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Sim = require('ethereumjs-testrpc');
|
||||
} catch(e) {
|
||||
console.log('TestRPC not found; Please install it with "npm install -g ethereumjs-testrpc');
|
||||
console.log('For more information see https://github.com/ethereumjs/testrpc');
|
||||
process.exit(1);
|
||||
}
|
||||
exec('testrpc');
|
||||
}
|
||||
.option('-p, --port [port]', 'port to run the rpc simulator (default: 8000)')
|
||||
.option('-h, --host [host]', 'host to run the rpc simulator (default: localhost)')
|
||||
.action(function(env, options) {
|
||||
self.Embark.initConfig(env || 'development', {
|
||||
embarkConfig: 'embark.json',
|
||||
interceptLogs: false
|
||||
});
|
||||
self.Embark.simulator({port: options.port, host: options.host});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -123,17 +120,21 @@ Cmd.prototype.test = function() {
|
|||
.command('test')
|
||||
.description('run tests')
|
||||
.action(function() {
|
||||
exec('mocha test/ --no-timeouts');
|
||||
shelljs.exec('mocha test/ --no-timeouts');
|
||||
});
|
||||
};
|
||||
|
||||
Cmd.prototype.ipfs = function() {
|
||||
Cmd.prototype.upload = function() {
|
||||
var self = this;
|
||||
program
|
||||
.command('ipfs')
|
||||
.description('deploy to IPFS')
|
||||
.action(function() {
|
||||
self.Embark.ipfs();
|
||||
.command('upload [platform] [environment]')
|
||||
.description('upload your dapp to a decentralized storage. possible options: ipfs, swarm (e.g embark upload swarm)')
|
||||
.action(function(platform, env, options) {
|
||||
// TODO: get env in cmd line as well
|
||||
self.Embark.initConfig(env || 'development', {
|
||||
embarkConfig: 'embark.json', interceptLogs: false
|
||||
});
|
||||
self.Embark.upload(platform);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -141,6 +142,8 @@ Cmd.prototype.otherCommands = function() {
|
|||
program
|
||||
.action(function(env){
|
||||
console.log('unknown command "%s"'.red, env);
|
||||
console.log("type embark --help to see the available commands");
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
var mkdirp = require('mkdirp');
|
||||
var wrench = require('wrench');
|
||||
var colors = require('colors');
|
||||
var shelljs = require('shelljs');
|
||||
|
||||
var fs = require('../../core/fs.js');
|
||||
|
||||
var GethCommands = require('./geth_commands.js');
|
||||
|
||||
var Blockchain = function(blockchainConfig, Client) {
|
||||
this.blockchainConfig = blockchainConfig;
|
||||
/*eslint complexity: ["error", 22]*/
|
||||
var Blockchain = function(options) {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
this.env = options.env || 'development';
|
||||
this.client = options.client;
|
||||
|
||||
this.config = {
|
||||
geth_bin: this.blockchainConfig.geth_bin || 'geth',
|
||||
networkType: this.blockchainConfig.networkType || 'custom',
|
||||
genesisBlock: this.blockchainConfig.genesisBlock || false,
|
||||
datadir: this.blockchainConfig.datadir || false,
|
||||
|
@ -18,43 +24,44 @@ var Blockchain = function(blockchainConfig, Client) {
|
|||
port: this.blockchainConfig.port || 30303,
|
||||
nodiscover: this.blockchainConfig.nodiscover || false,
|
||||
mine: this.blockchainConfig.mine || false,
|
||||
account: this.blockchainConfig.account || {}
|
||||
account: this.blockchainConfig.account || {},
|
||||
whisper: (this.blockchainConfig.whisper === undefined) || this.blockchainConfig.whisper,
|
||||
maxpeers: ((this.blockchainConfig.maxpeers === 0) ? 0 : (this.blockchainConfig.maxpeers || 25)),
|
||||
bootnodes: this.blockchainConfig.bootnodes || "",
|
||||
rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net']),
|
||||
vmdebug: this.blockchainConfig.vmdebug || false
|
||||
};
|
||||
|
||||
if (this.blockchainConfig.whisper === false) {
|
||||
this.config.whisper = false;
|
||||
} else {
|
||||
this.config.whisper = (this.blockchainConfig.whisper || true);
|
||||
}
|
||||
|
||||
this.client = new Client({config: this.config});
|
||||
this.client = new options.client({config: this.config, env: this.env});
|
||||
};
|
||||
|
||||
Blockchain.prototype.runCommand = function(cmd) {
|
||||
console.log(("running: " + cmd.underline).green);
|
||||
return exec(cmd);
|
||||
return shelljs.exec(cmd);
|
||||
};
|
||||
|
||||
Blockchain.prototype.run = function() {
|
||||
var self = this;
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log(("Embark Blockchain Using: " + this.client.name.underline).magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
console.log("===============================================================================".magenta);
|
||||
var address = this.initChainAndGetAddress();
|
||||
var mainCommand = this.client.mainCommand(address);
|
||||
this.runCommand(mainCommand);
|
||||
this.client.mainCommand(address, function(cmd) {
|
||||
self.runCommand(cmd);
|
||||
});
|
||||
};
|
||||
|
||||
Blockchain.prototype.initChainAndGetAddress = function() {
|
||||
var address = null, result;
|
||||
|
||||
// ensure datadir exists, bypassing the interactive liabilities prompt.
|
||||
this.datadir = '.embark/development/datadir';
|
||||
mkdirp.sync(this.datadir);
|
||||
this.datadir = '.embark/' + this.env + '/datadir';
|
||||
fs.mkdirpSync(this.datadir);
|
||||
|
||||
// copy mining script
|
||||
wrench.copyDirSyncRecursive(__dirname + "/../js", ".embark/development/js", {forceDelete: true});
|
||||
fs.copySync(fs.embarkPath("js"), ".embark/" + this.env + "/js", {overwrite: true});
|
||||
|
||||
// check if an account already exists, create one if not, return address
|
||||
result = this.runCommand(this.client.listAccountsCommand());
|
||||
|
@ -75,9 +82,9 @@ Blockchain.prototype.initChainAndGetAddress = function() {
|
|||
return address;
|
||||
};
|
||||
|
||||
var BlockchainClient = function(blockchainConfig, client) {
|
||||
var BlockchainClient = function(blockchainConfig, client, env) {
|
||||
if (client === 'geth') {
|
||||
return new Blockchain(blockchainConfig, GethCommands);
|
||||
return new Blockchain({blockchainConfig: blockchainConfig, client: GethCommands, env: env});
|
||||
} else {
|
||||
throw new Error('unknown client');
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
var async = require('async');
|
||||
|
||||
// TODO: make all of this async
|
||||
var GethCommands = function(options) {
|
||||
this.config = options.config;
|
||||
this.env = options.env || 'development';
|
||||
this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
|
||||
this.geth_bin = this.config.geth_bin || "geth";
|
||||
};
|
||||
|
||||
GethCommands.prototype.commonOptions = function() {
|
||||
var config = this.config;
|
||||
var cmd = "";
|
||||
|
||||
cmd += this.determineNetworkType(config);
|
||||
|
||||
if (config.datadir) {
|
||||
cmd += "--datadir=\"" + config.datadir + "\" ";
|
||||
}
|
||||
|
||||
if (config.light) {
|
||||
cmd += "--light ";
|
||||
}
|
||||
|
||||
if (config.fast) {
|
||||
cmd += "--fast ";
|
||||
}
|
||||
|
||||
if (config.account && config.account.password) {
|
||||
cmd += "--password " + config.account.password + " ";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
};
|
||||
|
||||
GethCommands.prototype.determineNetworkType = function(config) {
|
||||
var cmd = "";
|
||||
if (config.networkType === 'testnet') {
|
||||
cmd += "--testnet ";
|
||||
} else if (config.networkType === 'olympic') {
|
||||
cmd += "--olympic ";
|
||||
} else if (config.networkType === 'custom') {
|
||||
cmd += "--networkid " + config.networkId + " ";
|
||||
}
|
||||
return cmd;
|
||||
};
|
||||
|
||||
GethCommands.prototype.initGenesisCommmand = function() {
|
||||
var config = this.config;
|
||||
var cmd = this.geth_bin + " " + this.commonOptions();
|
||||
|
||||
if (config.genesisBlock) {
|
||||
cmd += "init \"" + config.genesisBlock + "\" ";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
};
|
||||
|
||||
GethCommands.prototype.newAccountCommand = function() {
|
||||
return this.geth_bin + " " + this.commonOptions() + "account new ";
|
||||
};
|
||||
|
||||
GethCommands.prototype.listAccountsCommand = function() {
|
||||
return this.geth_bin + " " + this.commonOptions() + "account list ";
|
||||
};
|
||||
|
||||
GethCommands.prototype.determineRpcOptions = function(config) {
|
||||
var cmd = "";
|
||||
|
||||
cmd += "--port " + config.port + " ";
|
||||
cmd += "--rpc ";
|
||||
cmd += "--rpcport " + config.rpcPort + " ";
|
||||
cmd += "--rpcaddr " + config.rpcHost + " ";
|
||||
if (config.rpcCorsDomain) {
|
||||
if (config.rpcCorsDomain === '*') {
|
||||
console.log('==================================');
|
||||
console.log('make sure you know what you are doing');
|
||||
console.log('==================================');
|
||||
}
|
||||
cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
|
||||
} else {
|
||||
console.log('==================================');
|
||||
console.log('warning: cors is not set');
|
||||
console.log('==================================');
|
||||
}
|
||||
|
||||
return cmd;
|
||||
};
|
||||
|
||||
GethCommands.prototype.mainCommand = function(address, done) {
|
||||
var self = this;
|
||||
var config = this.config;
|
||||
var rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net']);
|
||||
|
||||
async.series([
|
||||
function commonOptions(callback) {
|
||||
var cmd = self.commonOptions();
|
||||
callback(null, cmd);
|
||||
},
|
||||
function rpcOptions(callback) {
|
||||
var cmd = self.determineRpcOptions(self.config);
|
||||
callback(null, cmd);
|
||||
},
|
||||
function dontGetPeers(callback) {
|
||||
if (config.nodiscover) {
|
||||
return callback(null, "--nodiscover");
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function vmDebug(callback) {
|
||||
if (config.vmdebug) {
|
||||
return callback(null, "--vmdebug");
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function maxPeers(callback) {
|
||||
var cmd = "--maxpeers " + config.maxpeers;
|
||||
callback(null, cmd);
|
||||
},
|
||||
function mining(callback) {
|
||||
if (config.mineWhenNeeded || config.mine) {
|
||||
return callback(null, "--mine ");
|
||||
}
|
||||
callback("");
|
||||
},
|
||||
function bootnodes(callback) {
|
||||
if (config.bootnodes && config.bootnodes !== "" && config.bootnodes !== []) {
|
||||
return callback(null, "--bootnodes " + config.bootnodes);
|
||||
}
|
||||
callback("");
|
||||
},
|
||||
function whisper(callback) {
|
||||
if (config.whisper) {
|
||||
rpc_api.push('shh');
|
||||
return callback(null, "--shh ");
|
||||
}
|
||||
callback("");
|
||||
},
|
||||
function rpcApi(callback) {
|
||||
callback(null, '--rpcapi "' + rpc_api.join(',') + '"');
|
||||
},
|
||||
function accountToUnlock(callback) {
|
||||
var accountAddress = config.account.address || address;
|
||||
if (accountAddress) {
|
||||
return callback(null, "--unlock=" + accountAddress);
|
||||
}
|
||||
callback(null, "");
|
||||
},
|
||||
function mineWhenNeeded(callback) {
|
||||
if (config.mineWhenNeeded) {
|
||||
return callback(null, "js .embark/" + self.env + "/js/mine.js");
|
||||
}
|
||||
callback(null, "");
|
||||
}
|
||||
], function(err, results) {
|
||||
if (err) {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
done(self.geth_bin + " " + results.join(" "));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = GethCommands;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
var shelljs = require('shelljs');
|
||||
|
||||
var Simulator = function(options) {
|
||||
this.blockchainConfig = options.blockchainConfig;
|
||||
};
|
||||
|
||||
Simulator.prototype.run = function(options) {
|
||||
var cmds = [];
|
||||
|
||||
cmds.push("-p " + (this.blockchainConfig.rpcPort || options.port || 8545));
|
||||
cmds.push("-h " + (this.blockchainConfig.rpcHost || options.host || 'localhost'));
|
||||
cmds.push("-a " + (options.num || 10));
|
||||
|
||||
shelljs.exec('testrpc ' + cmds.join(' '));
|
||||
};
|
||||
|
||||
module.exports = Simulator;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
var fs = require('../core/fs.js');
|
||||
var utils = require('../core/utils.js');
|
||||
|
||||
var TemplateGenerator = function(templateName) {
|
||||
this.templateName = templateName;
|
||||
};
|
||||
|
||||
TemplateGenerator.prototype.generate = function(destinationFolder, name) {
|
||||
var templatePath = fs.embarkPath(this.templateName);
|
||||
console.log('Initializing Embark Template....'.green);
|
||||
|
||||
fs.copySync(templatePath, destinationFolder + name);
|
||||
utils.cd(destinationFolder + name);
|
||||
utils.sed('package.json', '%APP_NAME%', name);
|
||||
|
||||
console.log('Installing packages.. this can take a few seconds'.green);
|
||||
utils.runCmd('npm install');
|
||||
console.log('Init complete'.green);
|
||||
console.log('\nApp ready at '.green + destinationFolder + name);
|
||||
|
||||
if (name === 'embark_demo') {
|
||||
console.log('-------------------'.yellow);
|
||||
console.log('Next steps:'.green);
|
||||
console.log(('-> ' + ('cd ' + destinationFolder + name).bold.cyan).green);
|
||||
console.log('-> '.green + 'embark blockchain'.bold.cyan + ' or '.green + 'embark simulator'.bold.cyan);
|
||||
console.log('open another console in the same directory and run'.green);
|
||||
console.log('-> '.green + 'embark run'.bold.cyan);
|
||||
console.log('For more info go to http://github.com/iurimatias/embark-framework'.green);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = TemplateGenerator;
|
112
lib/compiler.js
112
lib/compiler.js
|
@ -1,112 +0,0 @@
|
|||
var shelljs = require('shelljs');
|
||||
var shelljs_global = require('shelljs/global');
|
||||
var fs = require('fs');
|
||||
var solc = require('solc');
|
||||
|
||||
var Compiler = function() {
|
||||
};
|
||||
|
||||
Compiler.prototype.compile_solidity = function(contractFiles) {
|
||||
var input = {};
|
||||
|
||||
for (var i = 0; i < contractFiles.length; i++){
|
||||
// TODO: this depends on the config
|
||||
var filename = contractFiles[i].filename.replace('app/contracts/','');
|
||||
input[filename] = contractFiles[i].content.toString();
|
||||
}
|
||||
|
||||
var output = solc.compile({sources: input}, 1);
|
||||
|
||||
if (output.errors) {
|
||||
throw new Error ("Solidity errors: " + output.errors);
|
||||
}
|
||||
|
||||
var json = output.contracts;
|
||||
|
||||
compiled_object = {};
|
||||
|
||||
for (var className in json) {
|
||||
var contract = json[className];
|
||||
|
||||
compiled_object[className] = {};
|
||||
compiled_object[className].code = contract.bytecode;
|
||||
compiled_object[className].runtimeBytecode = contract.runtimeBytecode;
|
||||
compiled_object[className].gasEstimates = contract.gasEstimates;
|
||||
compiled_object[className].functionHashes = contract.functionHashes;
|
||||
compiled_object[className].abiDefinition = JSON.parse(contract.interface);
|
||||
}
|
||||
|
||||
return compiled_object;
|
||||
};
|
||||
|
||||
Compiler.prototype.compile_serpent = function(contractFiles) {
|
||||
var cmd, result, output, json, compiled_object;
|
||||
|
||||
//TODO: figure out how to compile multiple files and get the correct json
|
||||
var contractFile = contractFiles[0];
|
||||
|
||||
cmd = "serpent compile " + contractFile;
|
||||
|
||||
result = exec(cmd, {silent: true});
|
||||
code = result.output;
|
||||
|
||||
if (result.code === 1) {
|
||||
throw new Error(result.output);
|
||||
}
|
||||
|
||||
cmd = "serpent mk_full_signature " + contractFile;
|
||||
result = exec(cmd, {silent: true});
|
||||
|
||||
if (result.code === 1) {
|
||||
throw new Error(result.output);
|
||||
}
|
||||
|
||||
json = JSON.parse(result.output.trim());
|
||||
className = contractFile.split('.')[0].split("/").pop();
|
||||
|
||||
for (var i=0; i < json.length; i++) {
|
||||
var elem = json[i];
|
||||
|
||||
if (elem.outputs.length > 0) {
|
||||
elem.constant = true;
|
||||
}
|
||||
}
|
||||
|
||||
compiled_object = {};
|
||||
compiled_object[className] = {};
|
||||
compiled_object[className].code = code.trim();
|
||||
compiled_object[className].info = {};
|
||||
compiled_object[className].abiDefinition = json;
|
||||
|
||||
return compiled_object;
|
||||
};
|
||||
|
||||
Compiler.prototype.compile = function(contractFiles) {
|
||||
var solidity = [], serpent = [];
|
||||
|
||||
for (var i = 0; i < contractFiles.length; i++) {
|
||||
var contractParts = contractFiles[i].split('.'),
|
||||
extension = contractParts[contractParts.length-1];
|
||||
|
||||
if (extension === 'sol') {
|
||||
solidity.push(contractFiles[i]);
|
||||
}
|
||||
else if (extension === 'se') {
|
||||
serpent.push(contractFiles[i]);
|
||||
}
|
||||
else {
|
||||
throw new Error("extension not known, got " + extension);
|
||||
}
|
||||
}
|
||||
|
||||
var contracts = [];
|
||||
if (solidity.length > 0) {
|
||||
contracts.concat(this.compile_solidity(solidity));
|
||||
}
|
||||
if (serpent.length > 0) {
|
||||
contracts.concat(this.compile_serpent(serpent));
|
||||
}
|
||||
return contracts;
|
||||
};
|
||||
|
||||
module.exports = Compiler;
|
|
@ -1,97 +0,0 @@
|
|||
var fs = require('fs');
|
||||
var grunt = require('grunt');
|
||||
var merge = require('merge');
|
||||
|
||||
// TODO: add wrapper for fs so it can also work in the browser
|
||||
// can work with both read and save
|
||||
var Config = function(options) {
|
||||
this.env = options.env;
|
||||
this.blockchainConfig = {};
|
||||
this.contractsConfig = {};
|
||||
this.pipelineConfig = {};
|
||||
this.chainTracker = {};
|
||||
this.assetFiles = {};
|
||||
this.contractsFiles = [];
|
||||
this.configDir = options.configDir || 'config/';
|
||||
this.chainsFile = options.chainsFile || './chains.json';
|
||||
};
|
||||
|
||||
Config.prototype.loadConfigFiles = function(options) {
|
||||
this.embarkConfig = JSON.parse(fs.readFileSync(options.embarkConfig));
|
||||
|
||||
this.loadPipelineConfigFile();
|
||||
this.loadBlockchainConfigFile();
|
||||
this.loadContractsConfigFile();
|
||||
this.loadChainTrackerFile();
|
||||
};
|
||||
|
||||
Config.prototype.reloadConfig = function() {
|
||||
this.loadPipelineConfigFile();
|
||||
this.loadBlockchainConfigFile();
|
||||
this.loadContractsConfigFile();
|
||||
this.loadChainTrackerFile();
|
||||
};
|
||||
|
||||
Config.prototype.loadBlockchainConfigFile = function() {
|
||||
var defaultBlockchainConfig = JSON.parse(fs.readFileSync(this.configDir + "blockchain.json"))[this.env];
|
||||
this.blockchainConfig = defaultBlockchainConfig;
|
||||
};
|
||||
|
||||
Config.prototype.loadContractsConfigFile = function() {
|
||||
var contractsConfig = JSON.parse(fs.readFileSync(this.configDir + "contracts.json"));
|
||||
var defaultContractsConfig = contractsConfig['default'];
|
||||
var envContractsConfig = contractsConfig[this.env];
|
||||
|
||||
var mergedConfig = merge.recursive(defaultContractsConfig, envContractsConfig);
|
||||
this.contractsConfig = mergedConfig;
|
||||
};
|
||||
|
||||
Config.prototype.loadPipelineConfigFile = function() {
|
||||
var contracts = this.embarkConfig.contracts;
|
||||
this.contractsFiles = this.loadFiles(contracts);
|
||||
|
||||
var assets = this.embarkConfig.app;
|
||||
for(var targetFile in assets) {
|
||||
this.assetFiles[targetFile] = this.loadFiles(assets[targetFile]);
|
||||
}
|
||||
|
||||
this.buildDir = this.embarkConfig.buildDir;
|
||||
this.configDir = this.embarkConfig.config;
|
||||
};
|
||||
|
||||
Config.prototype.loadChainTrackerFile = function() {
|
||||
//var self = this;
|
||||
var chainTracker;
|
||||
try {
|
||||
chainTracker = JSON.parse(fs.readFileSync(this.chainsFile));
|
||||
}
|
||||
catch(err) {
|
||||
//self.logger.info(this.chainsFile + ' file not found, creating it...');
|
||||
chainTracker = {};
|
||||
fs.writeFileSync(this.chainsFile, '{}');
|
||||
}
|
||||
this.chainTracker = chainTracker;
|
||||
};
|
||||
|
||||
Config.prototype.loadFiles = function(files) {
|
||||
var originalFiles = grunt.file.expand({nonull: true}, files);
|
||||
var readFiles = [];
|
||||
|
||||
originalFiles.filter(function(file) {
|
||||
return file.indexOf('.') >= 0;
|
||||
}).filter(function(file) {
|
||||
if (file === 'embark.js') {
|
||||
//readFiles.push({filename: 'bluebird.js', content: fs.readFileSync("../js/bluebird.js").toString()});
|
||||
readFiles.push({filename: 'web3.js', content: fs.readFileSync(__dirname + "/../js/web3.js").toString()});
|
||||
//readFiles.push({filename: 'embark.js', content: fs.readFileSync("../js/ipfs.js").toString()+ fs.readFileSync("../js/build/embark.bundle.js").toString()});
|
||||
readFiles.push({filename: 'ipfs.js', content: fs.readFileSync(__dirname + "/../js/ipfs.js").toString()});
|
||||
readFiles.push({filename: 'embark.js', content: fs.readFileSync(__dirname + "/../js/build/embark.bundle.js").toString()});
|
||||
} else {
|
||||
readFiles.push({filename: file, content: fs.readFileSync(file).toString()});
|
||||
}
|
||||
});
|
||||
|
||||
return readFiles;
|
||||
};
|
||||
|
||||
module.exports = Config;
|
|
@ -1,35 +0,0 @@
|
|||
var Web3 = require('web3');
|
||||
|
||||
var Console = function(options) {
|
||||
};
|
||||
|
||||
Console.prototype.runCode = function(code) {
|
||||
eval(code); // jshint ignore:line
|
||||
};
|
||||
|
||||
Console.prototype.executeCmd = function(cmd, callback) {
|
||||
if (cmd === 'help') {
|
||||
var helpText = [
|
||||
'Welcome to Embark 2',
|
||||
'',
|
||||
'possible commands are:',
|
||||
'quit - to immediatly exit',
|
||||
'',
|
||||
'The web3 object and the interfaces for the deployed contrats and their methods are also available'
|
||||
];
|
||||
return callback(helpText.join('\n'));
|
||||
} else if (cmd === 'quit') {
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
var result = eval(cmd); // jshint ignore:line
|
||||
return callback(result);
|
||||
}
|
||||
catch(e) {
|
||||
return callback(e.message.red);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Console;
|
||||
|
214
lib/contracts.js
214
lib/contracts.js
|
@ -1,214 +0,0 @@
|
|||
var Compiler = require('./compiler.js');
|
||||
var toposort = require('toposort');
|
||||
|
||||
// TODO: create a contract object
|
||||
|
||||
var ContractsManager = function(options) {
|
||||
this.contractFiles = options.contractFiles;
|
||||
this.contractsConfig = options.contractsConfig;
|
||||
this.contracts = {};
|
||||
this.logger = options.logger;
|
||||
|
||||
this.contractDependencies = {};
|
||||
};
|
||||
|
||||
ContractsManager.prototype.compileContracts = function() {
|
||||
var compiler = new Compiler();
|
||||
return compiler.compile_solidity(this.contractFiles);
|
||||
};
|
||||
|
||||
ContractsManager.prototype.build = function() {
|
||||
this.compiledContracts = this.compileContracts();
|
||||
var className;
|
||||
var contract;
|
||||
|
||||
// go through config file first
|
||||
for(className in this.contractsConfig.contracts) {
|
||||
contract = this.contractsConfig.contracts[className];
|
||||
|
||||
contract.className = className;
|
||||
contract.args = contract.args || [];
|
||||
|
||||
this.contracts[className] = contract;
|
||||
}
|
||||
|
||||
// compile contracts
|
||||
for(className in this.compiledContracts) {
|
||||
var compiledContract = this.compiledContracts[className];
|
||||
var contractConfig = this.contractsConfig.contracts[className];
|
||||
|
||||
contract = this.contracts[className] || {className: className, args: []};
|
||||
|
||||
contract.code = compiledContract.code;
|
||||
contract.runtimeBytecode = compiledContract.runtimeBytecode;
|
||||
contract.gasEstimates = compiledContract.gasEstimates;
|
||||
contract.functionHashes = compiledContract.functionHashes;
|
||||
contract.abiDefinition = compiledContract.abiDefinition;
|
||||
contract.gas = (contractConfig && contractConfig.gas) || this.contractsConfig.gas;
|
||||
|
||||
if (contract.deploy === undefined) {
|
||||
contract.deploy = true;
|
||||
}
|
||||
|
||||
if (contract.gas === 'auto') {
|
||||
var maxGas;
|
||||
if (contract.deploy) {
|
||||
maxGas = Math.max(contract.gasEstimates.creation[0], contract.gasEstimates.creation[1], 500000);
|
||||
} else {
|
||||
maxGas = 500000;
|
||||
}
|
||||
// TODO: put a check so it doesn't go over the block limit
|
||||
var adjustedGas = Math.round(maxGas * 1.40);
|
||||
contract.gas = adjustedGas;
|
||||
}
|
||||
contract.gasPrice = contract.gasPrice || this.contractsConfig.gasPrice;
|
||||
contract.type = 'file';
|
||||
contract.className = className;
|
||||
|
||||
this.contracts[className] = contract;
|
||||
}
|
||||
|
||||
// deal with special configs
|
||||
for(className in this.contracts) {
|
||||
contract = this.contracts[className];
|
||||
|
||||
// if deploy intention is not specified default is true
|
||||
if (contract.deploy === undefined) {
|
||||
contract.deploy = true;
|
||||
}
|
||||
|
||||
if (contract.instanceOf !== undefined) {
|
||||
var parentContractName = contract.instanceOf;
|
||||
var parentContract = this.contracts[parentContractName];
|
||||
|
||||
if (parentContract === className) {
|
||||
this.logger.error(className + ": instanceOf is set to itself");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parentContract === undefined) {
|
||||
this.logger.error(className + ": couldn't find instanceOf contract " + parentContractName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parentContract.args && parentContract.args.length > 0 && contract.args === []) {
|
||||
contract.args = parentContract.args;
|
||||
}
|
||||
|
||||
if (contract.code !== undefined) {
|
||||
this.logger.error(className + " has code associated to it but it's configured as an instanceOf " + parentContractName);
|
||||
}
|
||||
|
||||
contract.code = parentContract.code;
|
||||
contract.runtimeBytecode = parentContract.runtimeBytecode;
|
||||
contract.gasEstimates = parentContract.gasEstimates;
|
||||
contract.functionHashes = parentContract.functionHashes;
|
||||
contract.abiDefinition = parentContract.abiDefinition;
|
||||
|
||||
contract.gas = contract.gas || parentContract.gas;
|
||||
contract.gasPrice = contract.gasPrice || parentContract.gasPrice;
|
||||
}
|
||||
}
|
||||
|
||||
// remove contracts that don't have code
|
||||
for(className in this.contracts) {
|
||||
contract = this.contracts[className];
|
||||
|
||||
if (contract.code === undefined) {
|
||||
this.logger.error(className + " has no code associated");
|
||||
delete this.contracts[className];
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.trace(this.contracts);
|
||||
|
||||
// determine dependencies
|
||||
for(className in this.contracts) {
|
||||
contract = this.contracts[className];
|
||||
|
||||
if (contract.args === []) continue;
|
||||
|
||||
var ref = contract.args;
|
||||
for (var j = 0; j < ref.length; j++) {
|
||||
var arg = ref[j];
|
||||
if (arg[0] === "$") {
|
||||
if (this.contractDependencies[className] === void 0) {
|
||||
this.contractDependencies[className] = [];
|
||||
}
|
||||
this.contractDependencies[className].push(arg.substr(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ContractsManager.prototype.getContract = function(className) {
|
||||
return this.contracts[className];
|
||||
};
|
||||
|
||||
ContractsManager.prototype.sortContracts = function(contractList) {
|
||||
var converted_dependencies = [], i;
|
||||
|
||||
for(var contract in this.contractDependencies) {
|
||||
var dependencies = this.contractDependencies[contract];
|
||||
for(i=0; i < dependencies.length; i++) {
|
||||
converted_dependencies.push([contract, dependencies[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
var orderedDependencies = toposort(converted_dependencies).reverse();
|
||||
|
||||
var newList = contractList.sort(function(a,b) {
|
||||
var order_a = orderedDependencies.indexOf(a.className);
|
||||
var order_b = orderedDependencies.indexOf(b.className);
|
||||
return order_a - order_b;
|
||||
});
|
||||
|
||||
return newList;
|
||||
};
|
||||
|
||||
// TODO: should be built contracts
|
||||
ContractsManager.prototype.listContracts = function() {
|
||||
var contracts = [];
|
||||
for(var className in this.contracts) {
|
||||
var contract = this.contracts[className];
|
||||
contracts.push(contract);
|
||||
}
|
||||
return this.sortContracts(contracts);
|
||||
};
|
||||
|
||||
ContractsManager.prototype.contractsState = function() {
|
||||
var data = [];
|
||||
|
||||
for(var className in this.contracts) {
|
||||
var contract = this.contracts[className];
|
||||
|
||||
var contractData;
|
||||
|
||||
if (contract.deploy === false) {
|
||||
contractData = [
|
||||
className.green,
|
||||
'Interface or set to not deploy'.green,
|
||||
"\t\tn/a".green
|
||||
];
|
||||
} else if (contract.error) {
|
||||
contractData = [
|
||||
className.green,
|
||||
(contract.error).red,
|
||||
'\t\tError'.red
|
||||
];
|
||||
} else {
|
||||
contractData = [
|
||||
className.green,
|
||||
(contract.deployedAddress || '...').green,
|
||||
((contract.deployedAddress !== undefined) ? "\t\tDeployed".green : "\t\tPending".magenta)
|
||||
];
|
||||
}
|
||||
|
||||
data.push(contractData);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
module.exports = ContractsManager;
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
var ABIGenerator = function(options) {
|
||||
this.blockchainConfig = options.blockchainConfig || {};
|
||||
this.storageConfig = options.storageConfig || {};
|
||||
this.communicationConfig = options.communicationConfig || {};
|
||||
this.contractsManager = options.contractsManager;
|
||||
this.rpcHost = options.blockchainConfig && options.blockchainConfig.rpcHost;
|
||||
this.rpcPort = options.blockchainConfig && options.blockchainConfig.rpcPort;
|
||||
this.plugins = options.plugins;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateProvider = function() {
|
||||
var self = this;
|
||||
var result = "";
|
||||
var providerPlugins;
|
||||
|
||||
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (this.plugins) {
|
||||
providerPlugins = this.plugins.getPluginsFor('clientWeb3Provider');
|
||||
}
|
||||
|
||||
if (this.plugins && providerPlugins.length > 0) {
|
||||
providerPlugins.forEach(function(plugin) {
|
||||
result += plugin.generateProvider(self) + "\n";
|
||||
});
|
||||
} else {
|
||||
result += "\nif (typeof web3 !== 'undefined' && typeof Web3 !== 'undefined') {";
|
||||
result += '\n\tweb3 = new Web3(web3.currentProvider);';
|
||||
result += "\n} else if (typeof Web3 !== 'undefined') {";
|
||||
result += '\n\tweb3 = new Web3(new Web3.providers.HttpProvider("http://' + this.rpcHost + ':' + this.rpcPort + '"));';
|
||||
result += '\n}';
|
||||
result += "\nweb3.eth.defaultAccount = web3.eth.accounts[0];";
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateContracts = function(useEmbarkJS) {
|
||||
var self = this;
|
||||
var result = "\n";
|
||||
var contractsPlugins;
|
||||
|
||||
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (this.plugins) {
|
||||
contractsPlugins = this.plugins.getPluginsFor('contractGeneration');
|
||||
}
|
||||
|
||||
if (this.plugins && contractsPlugins.length > 0) {
|
||||
contractsPlugins.forEach(function(plugin) {
|
||||
result += plugin.generateContracts({contracts: self.contractsManager.contracts});
|
||||
});
|
||||
} else {
|
||||
for(var className in this.contractsManager.contracts) {
|
||||
var contract = this.contractsManager.contracts[className];
|
||||
|
||||
var abi = JSON.stringify(contract.abiDefinition);
|
||||
var gasEstimates = JSON.stringify(contract.gasEstimates);
|
||||
|
||||
if (useEmbarkJS) {
|
||||
result += "\n" + className + " = new EmbarkJS.Contract({abi: " + abi + ", address: '" + contract.deployedAddress + "', code: '" + contract.code + "', gasEstimates: " + gasEstimates + "});";
|
||||
} else {
|
||||
result += "\n" + className + "Abi = " + abi + ";";
|
||||
result += "\n" + className + "Contract = web3.eth.contract(" + className + "Abi);";
|
||||
result += "\n" + className + " = " + className + "Contract.at('" + contract.deployedAddress + "');";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateStorageInitialization = function(useEmbarkJS) {
|
||||
var self = this;
|
||||
var result = "\n";
|
||||
|
||||
if (!useEmbarkJS || self.storageConfig === {}) return "";
|
||||
|
||||
if (self.storageConfig.provider === 'ipfs' && self.storageConfig.enabled === true) {
|
||||
result += "\nEmbarkJS.Storage.setProvider('" + self.storageConfig.provider + "', {server: '" + self.storageConfig.host + "', port: '" + self.storageConfig.port + "'});";
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateCommunicationInitialization = function(useEmbarkJS) {
|
||||
var self = this;
|
||||
var result = "\n";
|
||||
|
||||
if (!useEmbarkJS || self.communicationConfig === {}) return "";
|
||||
|
||||
if (self.communicationConfig.provider === 'whisper' && self.communicationConfig.enabled === true) {
|
||||
result += "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "');";
|
||||
} else if (self.communicationConfig.provider === 'orbit' && self.communicationConfig.enabled === true) {
|
||||
result += "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "', {server: '" + self.communicationConfig.host + "', port: '" + self.communicationConfig.port + "'});";
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
ABIGenerator.prototype.generateABI = function(options) {
|
||||
var result = "";
|
||||
|
||||
result += this.generateProvider();
|
||||
result += this.generateContracts(options.useEmbarkJS);
|
||||
result += this.generateStorageInitialization(options.useEmbarkJS);
|
||||
result += this.generateCommunicationInitialization(options.useEmbarkJS);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = ABIGenerator;
|
|
@ -0,0 +1,118 @@
|
|||
/*jshint esversion: 6, loopfunc: true */
|
||||
var async = require('async');
|
||||
var SolcW = require('./solcW.js');
|
||||
|
||||
function asyncEachObject(object, iterator, callback) {
|
||||
async.each(
|
||||
Object.keys(object || {}),
|
||||
function(key, next){
|
||||
iterator(key, object[key], next);
|
||||
},
|
||||
callback
|
||||
);
|
||||
}
|
||||
async.eachObject = asyncEachObject;
|
||||
|
||||
var Compiler = function(options) {
|
||||
this.plugins = options.plugins;
|
||||
this.logger = options.logger;
|
||||
};
|
||||
|
||||
Compiler.prototype.compile_contracts = function(contractFiles, cb) {
|
||||
var self = this;
|
||||
|
||||
var available_compilers = {
|
||||
//".se": this.compile_serpent
|
||||
".sol": this.compile_solidity.bind(this)
|
||||
};
|
||||
|
||||
if (this.plugins) {
|
||||
var compilerPlugins = this.plugins.getPluginsFor('compilers');
|
||||
if (compilerPlugins.length > 0) {
|
||||
compilerPlugins.forEach(function(plugin) {
|
||||
plugin.compilers.forEach(function(compilerObject) {
|
||||
available_compilers[compilerObject.extension] = compilerObject.cb;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var compiledObject = {};
|
||||
|
||||
async.eachObject(available_compilers,
|
||||
function(extension, compiler, callback) {
|
||||
// TODO: warn about files it doesn't know how to compile
|
||||
var matchingFiles = contractFiles.filter(function(file) {
|
||||
return (file.filename.match(/\.[0-9a-z]+$/)[0] === extension);
|
||||
});
|
||||
|
||||
compiler.call(compiler, matchingFiles || [], function(err, compileResult) {
|
||||
Object.assign(compiledObject, compileResult);
|
||||
callback(err, compileResult);
|
||||
});
|
||||
},
|
||||
function (err) {
|
||||
cb(err, compiledObject);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Compiler.prototype.compile_solidity = function(contractFiles, cb) {
|
||||
var self = this;
|
||||
var input = {};
|
||||
var solcW;
|
||||
async.waterfall([
|
||||
function prepareInput(callback) {
|
||||
for (var i = 0; i < contractFiles.length; i++){
|
||||
// TODO: this depends on the config
|
||||
var filename = contractFiles[i].filename.replace('app/contracts/','');
|
||||
input[filename] = contractFiles[i].content.toString();
|
||||
}
|
||||
callback();
|
||||
},
|
||||
function loadCompiler(callback) {
|
||||
// TODO: there ino need to load this twice
|
||||
solcW = new SolcW();
|
||||
if (solcW.isCompilerLoaded()) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
self.logger.info("loading solc compiler..");
|
||||
solcW.load_compiler(function(){
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function compileContracts(callback) {
|
||||
self.logger.info("compiling contracts...");
|
||||
solcW.compile({sources: input}, 1, function(output) {
|
||||
if (output.errors) {
|
||||
return callback(new Error ("Solidity errors: " + output.errors).message);
|
||||
}
|
||||
callback(null, output);
|
||||
});
|
||||
},
|
||||
function createCompiledObject(output, callback) {
|
||||
var json = output.contracts;
|
||||
|
||||
compiled_object = {};
|
||||
|
||||
for (var className in json) {
|
||||
var contract = json[className];
|
||||
|
||||
compiled_object[className] = {};
|
||||
compiled_object[className].code = contract.bytecode;
|
||||
compiled_object[className].runtimeBytecode = contract.runtimeBytecode;
|
||||
compiled_object[className].realRuntimeBytecode = contract.runtimeBytecode.slice(0, -68);
|
||||
compiled_object[className].swarmHash = contract.runtimeBytecode.slice(-68).slice(0,64);
|
||||
compiled_object[className].gasEstimates = contract.gasEstimates;
|
||||
compiled_object[className].functionHashes = contract.functionHashes;
|
||||
compiled_object[className].abiDefinition = JSON.parse(contract.interface);
|
||||
}
|
||||
callback(null, compiled_object);
|
||||
}
|
||||
], function(err, result) {
|
||||
cb(err, result);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Compiler;
|
|
@ -0,0 +1,247 @@
|
|||
var toposort = require('toposort');
|
||||
var async = require('async');
|
||||
|
||||
var Compiler = require('./compiler.js');
|
||||
|
||||
// TODO: create a contract object
|
||||
|
||||
var adjustGas = function(contract) {
|
||||
var maxGas, adjustedGas;
|
||||
if (contract.gas === 'auto') {
|
||||
if (contract.deploy || contract.deploy === undefined) {
|
||||
if (contract.gasEstimates.creation !== undefined) {
|
||||
// TODO: should sum it instead
|
||||
maxGas = Math.max(contract.gasEstimates.creation[0], contract.gasEstimates.creation[1], 500000);
|
||||
} else {
|
||||
maxGas = 500000;
|
||||
}
|
||||
} else {
|
||||
maxGas = 500000;
|
||||
}
|
||||
// TODO: put a check so it doesn't go over the block limit
|
||||
adjustedGas = Math.round(maxGas * 1.40);
|
||||
adjustedGas += 25000;
|
||||
contract.gas = adjustedGas;
|
||||
}
|
||||
};
|
||||
|
||||
var ContractsManager = function(options) {
|
||||
this.contractFiles = options.contractFiles;
|
||||
this.contractsConfig = options.contractsConfig;
|
||||
this.contracts = {};
|
||||
this.logger = options.logger;
|
||||
this.plugins = options.plugins;
|
||||
|
||||
this.contractDependencies = {};
|
||||
};
|
||||
|
||||
ContractsManager.prototype.build = function(done) {
|
||||
var self = this;
|
||||
async.waterfall([
|
||||
function compileContracts(callback) {
|
||||
var compiler = new Compiler({plugins: self.plugins, logger: self.logger});
|
||||
compiler.compile_contracts(self.contractFiles, function(err, compiledObject) {
|
||||
self.compiledContracts = compiledObject;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function prepareContractsFromConfig(callback) {
|
||||
var className, contract;
|
||||
for(className in self.contractsConfig.contracts) {
|
||||
contract = self.contractsConfig.contracts[className];
|
||||
|
||||
contract.className = className;
|
||||
contract.args = contract.args || [];
|
||||
|
||||
self.contracts[className] = contract;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
function setDeployIntention(callback) {
|
||||
var className, contract;
|
||||
for(className in self.contracts) {
|
||||
contract = self.contracts[className];
|
||||
contract.deploy = (contract.deploy === undefined) || contract.deploy;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
function prepareContractsFromCompilation(callback) {
|
||||
var className, compiledContract, contractConfig, contract;
|
||||
for(className in self.compiledContracts) {
|
||||
compiledContract = self.compiledContracts[className];
|
||||
contractConfig = self.contractsConfig.contracts[className];
|
||||
|
||||
contract = self.contracts[className] || {className: className, args: []};
|
||||
|
||||
contract.code = compiledContract.code;
|
||||
contract.runtimeBytecode = compiledContract.runtimeBytecode;
|
||||
contract.realRuntimeBytecode = (contract.realRuntimeBytecode || contract.runtimeBytecode);
|
||||
contract.swarmHash = compiledContract.swarmHash;
|
||||
contract.gasEstimates = compiledContract.gasEstimates;
|
||||
contract.functionHashes = compiledContract.functionHashes;
|
||||
contract.abiDefinition = compiledContract.abiDefinition;
|
||||
|
||||
contract.gas = (contractConfig && contractConfig.gas) || self.contractsConfig.gas || 'auto';
|
||||
adjustGas(contract);
|
||||
|
||||
contract.gasPrice = contract.gasPrice || self.contractsConfig.gasPrice;
|
||||
contract.type = 'file';
|
||||
contract.className = className;
|
||||
|
||||
self.contracts[className] = contract;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
/*eslint complexity: ["error", 11]*/
|
||||
function dealWithSpecialConfigs(callback) {
|
||||
var className, contract, parentContractName, parentContract;
|
||||
|
||||
for(className in self.contracts) {
|
||||
contract = self.contracts[className];
|
||||
|
||||
if (contract.instanceOf === undefined) { continue; }
|
||||
|
||||
parentContractName = contract.instanceOf;
|
||||
parentContract = self.contracts[parentContractName];
|
||||
|
||||
if (parentContract === className) {
|
||||
self.logger.error(className + ": instanceOf is set to itself");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parentContract === undefined) {
|
||||
self.logger.error(className + ": couldn't find instanceOf contract " + parentContractName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parentContract.args && parentContract.args.length > 0 && ((contract.args && contract.args.length === 0) || contract.args === undefined)) {
|
||||
contract.args = parentContract.args;
|
||||
}
|
||||
|
||||
if (contract.code !== undefined) {
|
||||
self.logger.error(className + " has code associated to it but it's configured as an instanceOf " + parentContractName);
|
||||
}
|
||||
|
||||
contract.code = parentContract.code;
|
||||
contract.runtimeBytecode = parentContract.runtimeBytecode;
|
||||
contract.gasEstimates = parentContract.gasEstimates;
|
||||
contract.functionHashes = parentContract.functionHashes;
|
||||
contract.abiDefinition = parentContract.abiDefinition;
|
||||
|
||||
contract.gas = contract.gas || parentContract.gas;
|
||||
contract.gasPrice = contract.gasPrice || parentContract.gasPrice;
|
||||
contract.type = 'instance';
|
||||
|
||||
}
|
||||
callback();
|
||||
},
|
||||
function removeContractsWithNoCode(callback) {
|
||||
var className, contract;
|
||||
for(className in self.contracts) {
|
||||
contract = self.contracts[className];
|
||||
|
||||
if (contract.code === undefined) {
|
||||
self.logger.error(className + " has no code associated");
|
||||
delete self.contracts[className];
|
||||
}
|
||||
}
|
||||
self.logger.trace(self.contracts);
|
||||
callback();
|
||||
},
|
||||
function determineDependencies(callback) {
|
||||
var className, contract;
|
||||
for(className in self.contracts) {
|
||||
contract = self.contracts[className];
|
||||
|
||||
if (contract.args === []) continue;
|
||||
|
||||
var ref = contract.args;
|
||||
for (var j = 0; j < ref.length; j++) {
|
||||
var arg = ref[j];
|
||||
if (arg[0] === "$") {
|
||||
self.contractDependencies[className] = self.contractDependencies[className] || [];
|
||||
self.contractDependencies[className].push(arg.substr(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
self.logger.error("Error Compiling/Building contracts: " + err);
|
||||
}
|
||||
self.logger.trace("finished".underline);
|
||||
done(err, self);
|
||||
});
|
||||
};
|
||||
|
||||
ContractsManager.prototype.getContract = function(className) {
|
||||
return this.contracts[className];
|
||||
};
|
||||
|
||||
ContractsManager.prototype.sortContracts = function(contractList) {
|
||||
var converted_dependencies = [], i;
|
||||
|
||||
for(var contract in this.contractDependencies) {
|
||||
var dependencies = this.contractDependencies[contract];
|
||||
for(i=0; i < dependencies.length; i++) {
|
||||
converted_dependencies.push([contract, dependencies[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
var orderedDependencies = toposort(converted_dependencies).reverse();
|
||||
|
||||
var newList = contractList.sort(function(a,b) {
|
||||
var order_a = orderedDependencies.indexOf(a.className);
|
||||
var order_b = orderedDependencies.indexOf(b.className);
|
||||
return order_a - order_b;
|
||||
});
|
||||
|
||||
return newList;
|
||||
};
|
||||
|
||||
// TODO: should be built contracts
|
||||
ContractsManager.prototype.listContracts = function() {
|
||||
var contracts = [];
|
||||
for(var className in this.contracts) {
|
||||
var contract = this.contracts[className];
|
||||
contracts.push(contract);
|
||||
}
|
||||
return this.sortContracts(contracts);
|
||||
};
|
||||
|
||||
ContractsManager.prototype.contractsState = function() {
|
||||
var data = [];
|
||||
|
||||
for(var className in this.contracts) {
|
||||
var contract = this.contracts[className];
|
||||
|
||||
var contractData;
|
||||
|
||||
if (contract.deploy === false) {
|
||||
contractData = [
|
||||
className.green,
|
||||
'Interface or set to not deploy'.green,
|
||||
"\t\tn/a".green
|
||||
];
|
||||
} else if (contract.error) {
|
||||
contractData = [
|
||||
className.green,
|
||||
(contract.error).red,
|
||||
'\t\tError'.red
|
||||
];
|
||||
} else {
|
||||
contractData = [
|
||||
className.green,
|
||||
(contract.deployedAddress || '...').green,
|
||||
((contract.deployedAddress !== undefined) ? "\t\tDeployed".green : "\t\tPending".magenta)
|
||||
];
|
||||
}
|
||||
|
||||
data.push(contractData);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
module.exports = ContractsManager;
|
|
@ -1,8 +1,9 @@
|
|||
var async = require('async');
|
||||
var Compiler = require('./compiler.js');
|
||||
|
||||
var RunCode = require('../core/runCode.js');
|
||||
|
||||
var DeployTracker = require('./deploy_tracker.js');
|
||||
var ABIGenerator = require('./abi.js');
|
||||
var web3;
|
||||
|
||||
var Deploy = function(options) {
|
||||
this.web3 = options.web3;
|
||||
|
@ -15,6 +16,23 @@ var Deploy = function(options) {
|
|||
});
|
||||
};
|
||||
|
||||
Deploy.prototype.determineArguments = function(suppliedArgs) {
|
||||
var realArgs = [], l, arg, contractName, referedContract;
|
||||
|
||||
for (l = 0; l < suppliedArgs.length; l++) {
|
||||
arg = suppliedArgs[l];
|
||||
if (arg[0] === "$") {
|
||||
contractName = arg.substr(1);
|
||||
referedContract = this.contractsManager.getContract(contractName);
|
||||
realArgs.push(referedContract.deployedAddress);
|
||||
} else {
|
||||
realArgs.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return realArgs;
|
||||
};
|
||||
|
||||
Deploy.prototype.checkAndDeployContract = function(contract, params, callback) {
|
||||
var self = this;
|
||||
var suppliedArgs;
|
||||
|
@ -32,68 +50,41 @@ Deploy.prototype.checkAndDeployContract = function(contract, params, callback) {
|
|||
|
||||
if (contract.address !== undefined) {
|
||||
|
||||
// determine arguments
|
||||
suppliedArgs = (params || contract.args);
|
||||
realArgs = [];
|
||||
|
||||
for (l = 0; l < suppliedArgs.length; l++) {
|
||||
arg = suppliedArgs[l];
|
||||
if (arg[0] === "$") {
|
||||
contractName = arg.substr(1);
|
||||
referedContract = this.contractsManager.getContract(contractName);
|
||||
realArgs.push(referedContract.deployedAddress);
|
||||
} else {
|
||||
realArgs.push(arg);
|
||||
}
|
||||
}
|
||||
realArgs = self.determineArguments(params || contract.args);
|
||||
|
||||
contract.deployedAddress = contract.address;
|
||||
self.deployTracker.trackContract(contract.className, contract.code, realArgs, contract.address);
|
||||
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, contract.address);
|
||||
self.deployTracker.save();
|
||||
self.logger.contractsState(self.contractsManager.contractsState());
|
||||
return callback();
|
||||
}
|
||||
|
||||
var trackedContract = self.deployTracker.getContract(contract.className, contract.code, contract.args);
|
||||
var trackedContract = self.deployTracker.getContract(contract.className, contract.realRuntimeBytecode, contract.args);
|
||||
|
||||
if (trackedContract && this.web3.eth.getCode(trackedContract.address) !== "0x") {
|
||||
self.logger.info(contract.className + " already deployed " + trackedContract.address);
|
||||
self.logger.info(contract.className.bold.cyan + " already deployed at ".green + trackedContract.address.bold.cyan);
|
||||
contract.deployedAddress = trackedContract.address;
|
||||
self.logger.contractsState(self.contractsManager.contractsState());
|
||||
callback();
|
||||
return callback();
|
||||
} else {
|
||||
|
||||
// determine arguments
|
||||
suppliedArgs = (params || contract.args);
|
||||
realArgs = [];
|
||||
|
||||
for (l = 0; l < suppliedArgs.length; l++) {
|
||||
arg = suppliedArgs[l];
|
||||
if (arg[0] === "$") {
|
||||
contractName = arg.substr(1);
|
||||
referedContract = this.contractsManager.getContract(contractName);
|
||||
realArgs.push(referedContract.deployedAddress);
|
||||
} else {
|
||||
realArgs.push(arg);
|
||||
}
|
||||
}
|
||||
realArgs = self.determineArguments(params || contract.args);
|
||||
|
||||
this.deployContract(contract, realArgs, function(err, address) {
|
||||
self.deployTracker.trackContract(contract.className, contract.code, realArgs, address);
|
||||
if (err) {
|
||||
return callback(new Error(err));
|
||||
}
|
||||
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, address);
|
||||
self.deployTracker.save();
|
||||
self.logger.contractsState(self.contractsManager.contractsState());
|
||||
|
||||
// TODO: replace evals with separate process so it's isolated and with
|
||||
// a callback
|
||||
if (contract.onDeploy !== undefined) {
|
||||
self.logger.info('executing onDeploy commands');
|
||||
var abiGenerator = new ABIGenerator({}, self.contractsManager);
|
||||
web3 = self.web3;
|
||||
var abiGenerator = new ABIGenerator({contractsManager: self.contractsManager});
|
||||
var abi = abiGenerator.generateContracts(false);
|
||||
eval(abi); // jshint ignore:line
|
||||
|
||||
var cmds = contract.onDeploy.join(';\n');
|
||||
eval(cmds); // jshint ignore:line
|
||||
|
||||
RunCode.doEval(abi + "\n" + cmds, self.web3);
|
||||
}
|
||||
|
||||
callback();
|
||||
|
@ -109,7 +100,9 @@ Deploy.prototype.deployContract = function(contract, params, callback) {
|
|||
var contractParams = (params || contract.args).slice();
|
||||
|
||||
this.web3.eth.getAccounts(function(err, accounts) {
|
||||
//console.log("using address" + this.web3.eth.accounts[0]);
|
||||
if (err) {
|
||||
return callback(new Error(err));
|
||||
}
|
||||
|
||||
// TODO: probably needs to be defaultAccount
|
||||
// TODO: it wouldn't necessary be the first address
|
||||
|
@ -117,29 +110,29 @@ Deploy.prototype.deployContract = function(contract, params, callback) {
|
|||
contractParams.push({
|
||||
//from: this.web3.eth.coinbase,
|
||||
from: accounts[0],
|
||||
data: contract.code,
|
||||
data: "0x" + contract.code,
|
||||
gas: contract.gas,
|
||||
gasPrice: contract.gasPrice
|
||||
});
|
||||
|
||||
self.logger.info("deploying " + contract.className + " with " + contract.gas + " gas");
|
||||
self.logger.info("deploying " + contract.className.bold.cyan + " with ".green + contract.gas + " gas".green);
|
||||
contractParams.push(function(err, transaction) {
|
||||
self.logger.contractsState(self.contractsManager.contractsState());
|
||||
|
||||
if (err) {
|
||||
self.logger.error("error deploying contract: " + contract.className);
|
||||
self.logger.error("error deploying contract: " + contract.className.cyan);
|
||||
var errMsg = err.toString();
|
||||
if (errMsg === 'Error: The contract code couldn\'t be stored, please check your gas amount.') {
|
||||
errMsg = 'The contract code couldn\'t be stored, out of gas or constructor error';
|
||||
}
|
||||
self.logger.error(errMsg);
|
||||
contract.error = errMsg;
|
||||
callback(new Error(err));
|
||||
return callback(new Error(err));
|
||||
} else if (transaction.address !== undefined) {
|
||||
self.logger.info(contract.className + " deployed at " + transaction.address);
|
||||
self.logger.info(contract.className.bold.cyan + " deployed at ".green + transaction.address.bold.cyan);
|
||||
contract.deployedAddress = transaction.address;
|
||||
contract.transactionHash = transaction.transactionHash;
|
||||
callback(null, transaction.address);
|
||||
return callback(null, transaction.address);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -157,7 +150,12 @@ Deploy.prototype.deployAll = function(done) {
|
|||
self.checkAndDeployContract(contract, null, callback);
|
||||
},
|
||||
function(err, results) {
|
||||
self.logger.info("finished");
|
||||
if (err) {
|
||||
self.logger.error("error deploying contracts");
|
||||
self.logger.error(err.message);
|
||||
self.logger.debug(err.stack);
|
||||
}
|
||||
self.logger.info("finished deploying contracts");
|
||||
self.logger.trace(arguments);
|
||||
done();
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
var async = require('async');
|
||||
var Web3 = require('web3');
|
||||
|
||||
var Deploy = require('./deploy.js');
|
||||
var ContractsManager = require('./contracts.js');
|
||||
|
||||
var DeployManager = function(options) {
|
||||
this.config = options.config;
|
||||
this.logger = options.logger;
|
||||
this.blockchainConfig = this.config.blockchainConfig;
|
||||
this.plugins = options.plugins;
|
||||
this.events = options.events;
|
||||
this.web3 = options.web3;
|
||||
this.chainConfig = (options.trackContracts !== false) ? this.config.chainTracker : false;
|
||||
};
|
||||
|
||||
DeployManager.prototype.deployContracts = function(done) {
|
||||
var self = this;
|
||||
|
||||
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
|
||||
self.logger.info("Blockchain component is disabled in the config".underline);
|
||||
self.events.emit('blockchainDisabled', {});
|
||||
return done();
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function buildContracts(callback) {
|
||||
var contractsManager = new ContractsManager({
|
||||
contractFiles: self.config.contractsFiles,
|
||||
contractsConfig: self.config.contractsConfig,
|
||||
logger: self.logger,
|
||||
plugins: self.plugins
|
||||
});
|
||||
contractsManager.build(callback);
|
||||
},
|
||||
function connectWithWeb3(contractsManager, callback) {
|
||||
var web3;
|
||||
if (self.web3) {
|
||||
web3 = self.web3;
|
||||
} else {
|
||||
web3 = new Web3();
|
||||
var web3Endpoint = 'http://' + self.config.blockchainConfig.rpcHost + ':' + self.config.blockchainConfig.rpcPort;
|
||||
web3.setProvider(new web3.providers.HttpProvider(web3Endpoint));
|
||||
if (!web3.isConnected()) {
|
||||
self.logger.error(("Couldn't connect to " + web3Endpoint.underline + " are you sure it's on?").red);
|
||||
self.logger.info("make sure you have an ethereum node or simulator running. e.g 'embark blockchain'".magenta);
|
||||
return callback(Error("error connecting to blockchain node"));
|
||||
}
|
||||
}
|
||||
callback(null, contractsManager, web3);
|
||||
},
|
||||
function setDefaultAccount(contractsManager, web3, callback) {
|
||||
web3.eth.getAccounts(function(err, accounts) {
|
||||
if (err) {
|
||||
return callback(new Error(err));
|
||||
}
|
||||
var accountConfig = self.config.blockchainConfig.account;
|
||||
var selectedAccount = accountConfig && accountConfig.address;
|
||||
web3.eth.defaultAccount = (selectedAccount || accounts[0]);
|
||||
callback(null, contractsManager, web3);
|
||||
});
|
||||
},
|
||||
function deployAllContracts(contractsManager, web3, callback) {
|
||||
var deploy = new Deploy({
|
||||
web3: web3,
|
||||
contractsManager: contractsManager,
|
||||
logger: self.logger,
|
||||
chainConfig: self.chainConfig,
|
||||
env: self.config.env
|
||||
});
|
||||
deploy.deployAll(function() {
|
||||
self.events.emit('contractsDeployed', contractsManager);
|
||||
callback(null, contractsManager);
|
||||
});
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
done(err, null);
|
||||
} else {
|
||||
done(null, result);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = DeployManager;
|
|
@ -1,5 +1,4 @@
|
|||
var fs = require('fs');
|
||||
var prettyJson = require("json-honey");
|
||||
var fs = require('../core/fs.js');
|
||||
|
||||
var DeployTracker = function(options) {
|
||||
this.logger = options.logger;
|
||||
|
@ -12,6 +11,7 @@ var DeployTracker = function(options) {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: need to make this async
|
||||
var block = this.web3.eth.getBlock(0);
|
||||
var chainId = block.hash;
|
||||
|
||||
|
@ -49,7 +49,7 @@ DeployTracker.prototype.getContract = function(contractName, code, args) {
|
|||
// chainConfig can be an abstract PersistentObject
|
||||
DeployTracker.prototype.save = function() {
|
||||
if (this.chainConfig === false) { return; }
|
||||
fs.writeFileSync("./chains.json", prettyJson(this.chainConfig));
|
||||
fs.writeJSONSync("./chains.json", this.chainConfig);
|
||||
};
|
||||
|
||||
module.exports = DeployTracker;
|
|
@ -0,0 +1,18 @@
|
|||
var solc;
|
||||
|
||||
process.on('message', function(msg) {
|
||||
if (msg.action === 'loadCompiler') {
|
||||
solc = require('solc');
|
||||
process.send({result: "loadedCompiler"});
|
||||
}
|
||||
|
||||
if (msg.action === 'compile') {
|
||||
var output = solc.compile(msg.obj, msg.optimize);
|
||||
process.send({result: "compilation", output: output});
|
||||
}
|
||||
});
|
||||
|
||||
process.on('exit', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
var utils = require('../core/utils.js');
|
||||
var solcProcess;
|
||||
var compilerLoaded = false;
|
||||
|
||||
var SolcW = function() {
|
||||
};
|
||||
|
||||
SolcW.prototype.load_compiler = function(done) {
|
||||
if (compilerLoaded) { done(); }
|
||||
solcProcess = require('child_process').fork(utils.joinPath(__dirname, '/solcP.js'));
|
||||
solcProcess.once('message', function(msg) {
|
||||
if (msg.result !== 'loadedCompiler') {
|
||||
return;
|
||||
}
|
||||
compilerLoaded = true;
|
||||
done();
|
||||
});
|
||||
solcProcess.send({action: 'loadCompiler'});
|
||||
};
|
||||
|
||||
SolcW.prototype.isCompilerLoaded = function() {
|
||||
return (compilerLoaded === true);
|
||||
};
|
||||
|
||||
SolcW.prototype.compile = function(obj, optimize, done) {
|
||||
solcProcess.once('message', function(msg) {
|
||||
if (msg.result !== 'compilation') {
|
||||
return;
|
||||
}
|
||||
done(msg.output);
|
||||
});
|
||||
solcProcess.send({action: 'compile', obj: obj, optimize: optimize});
|
||||
};
|
||||
|
||||
module.exports = SolcW;
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
var fs = require('./fs.js');
|
||||
var Plugins = require('./plugins.js');
|
||||
var utils = require('./utils.js');
|
||||
|
||||
// TODO: add wrapper for fs so it can also work in the browser
|
||||
// can work with both read and save
|
||||
var Config = function(options) {
|
||||
this.env = options.env;
|
||||
this.blockchainConfig = {};
|
||||
this.contractsConfig = {};
|
||||
this.pipelineConfig = {};
|
||||
this.webServerConfig = {};
|
||||
this.chainTracker = {};
|
||||
this.assetFiles = {};
|
||||
this.contractsFiles = [];
|
||||
this.configDir = options.configDir || 'config/';
|
||||
this.chainsFile = options.chainsFile || './chains.json';
|
||||
this.plugins = options.plugins;
|
||||
this.logger = options.logger;
|
||||
this.events = options.events;
|
||||
};
|
||||
|
||||
Config.prototype.loadConfigFiles = function(options) {
|
||||
var interceptLogs = options.interceptLogs;
|
||||
if (options.interceptLogs === undefined) {
|
||||
interceptLogs = true;
|
||||
}
|
||||
|
||||
//Check if the config file exists
|
||||
var embarkConfigExists = fs.existsSync(options.embarkConfig);
|
||||
if(!embarkConfigExists){
|
||||
this.logger.error('Cannot find file ' + options.embarkConfig + '. Please ensure you are running this command inside the Dapp folder');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
this.embarkConfig = fs.readJSONSync(options.embarkConfig);
|
||||
this.embarkConfig.plugins = this.embarkConfig.plugins || {};
|
||||
|
||||
this.plugins = new Plugins({plugins: this.embarkConfig.plugins, logger: this.logger, interceptLogs: interceptLogs, events: this.events, config: this});
|
||||
this.plugins.loadPlugins();
|
||||
|
||||
this.loadEmbarkConfigFile();
|
||||
this.loadBlockchainConfigFile();
|
||||
this.loadStorageConfigFile();
|
||||
this.loadCommunicationConfigFile();
|
||||
|
||||
this.loadPipelineConfigFile();
|
||||
|
||||
this.loadContractsConfigFile();
|
||||
this.loadWebServerConfigFile();
|
||||
this.loadChainTrackerFile();
|
||||
this.loadPluginContractFiles();
|
||||
};
|
||||
|
||||
Config.prototype.reloadConfig = function() {
|
||||
this.loadEmbarkConfigFile();
|
||||
this.loadBlockchainConfigFile();
|
||||
this.loadStorageConfigFile();
|
||||
this.loadCommunicationConfigFile();
|
||||
this.loadPipelineConfigFile();
|
||||
this.loadContractsConfigFile();
|
||||
this.loadChainTrackerFile();
|
||||
};
|
||||
|
||||
Config.prototype.loadBlockchainConfigFile = function() {
|
||||
var defaultBlockchainConfig = fs.readJSONSync(this.configDir + "blockchain.json");
|
||||
this.blockchainConfig = defaultBlockchainConfig[this.env] || {};
|
||||
|
||||
if (this.blockchainConfig.enabled === undefined) {
|
||||
this.blockchainConfig.enabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
Config.prototype.loadContractsConfigFile = function() {
|
||||
|
||||
var configObject = {};
|
||||
|
||||
var configPlugins = this.plugins.getPluginsFor('contractsConfig');
|
||||
if (configPlugins.length > 0) {
|
||||
configPlugins.forEach(function(plugin) {
|
||||
plugin.contractsConfigs.forEach(function(pluginConfig) {
|
||||
configObject = utils.recursiveMerge(configObject, pluginConfig);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var contractsConfig = fs.readJSONSync(this.configDir + "contracts.json");
|
||||
configObject = utils.recursiveMerge(configObject, contractsConfig);
|
||||
var defaultContractsConfig = configObject['default'];
|
||||
var envContractsConfig = configObject[this.env];
|
||||
|
||||
var mergedConfig = utils.recursiveMerge(defaultContractsConfig, envContractsConfig);
|
||||
this.contractsConfig = mergedConfig;
|
||||
};
|
||||
|
||||
|
||||
Config.prototype.loadStorageConfigFile = function() {
|
||||
var configObject = {
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"available_providers": ["ipfs"],
|
||||
"ipfs_bin": "ipfs",
|
||||
"provider": "ipfs",
|
||||
"host": "localhost",
|
||||
"port": 5001
|
||||
},
|
||||
"development": {
|
||||
}
|
||||
};
|
||||
|
||||
//var configPlugins = this.plugins.getPluginsFor('storageConfig');
|
||||
//if (configPlugins.length > 0) {
|
||||
// configPlugins.forEach(function(plugin) {
|
||||
// plugin.contractsConfigs.forEach(function(pluginConfig) {
|
||||
// configObject = utils.recursiveMerge(configObject, pluginConfig);
|
||||
// });
|
||||
// });
|
||||
//}
|
||||
|
||||
var storageConfig;
|
||||
if (fs.existsSync(this.configDir + "storage.json")) {
|
||||
storageConfig = fs.readJSONSync(this.configDir + "storage.json");
|
||||
configObject = utils.recursiveMerge(configObject, storageConfig);
|
||||
}
|
||||
|
||||
var defaultStorageConfig = configObject['default'];
|
||||
var envStorageConfig = configObject[this.env];
|
||||
|
||||
var mergedConfig = utils.recursiveMerge(defaultStorageConfig, envStorageConfig);
|
||||
this.storageConfig = mergedConfig || {};
|
||||
|
||||
if (this.storageConfig.enabled === undefined) {
|
||||
this.storageConfig.enabled = true;
|
||||
}
|
||||
if (this.storageConfig.available_providers === undefined) {
|
||||
this.storageConfig.available_providers = [];
|
||||
}
|
||||
};
|
||||
|
||||
Config.prototype.loadCommunicationConfigFile = function() {
|
||||
var configObject = {
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"provider": "whisper",
|
||||
"available_providers": ["whisper", "orbit"]
|
||||
}
|
||||
};
|
||||
|
||||
//var configPlugins = this.plugins.getPluginsFor('communicationConfig');
|
||||
//if (configPlugins.length > 0) {
|
||||
// configPlugins.forEach(function(plugin) {
|
||||
// plugin.contractsConfigs.forEach(function(pluginConfig) {
|
||||
// configObject = utils.recursiveMerge(configObject, pluginConfig);
|
||||
// });
|
||||
// });
|
||||
//}
|
||||
|
||||
var communicationConfig;
|
||||
|
||||
if (fs.existsSync(this.configDir + "communication.json")) {
|
||||
communicationConfig = fs.readJSONSync(this.configDir + "communication.json");
|
||||
configObject = utils.recursiveMerge(configObject, communicationConfig);
|
||||
}
|
||||
|
||||
var defaultCommunicationConfig = configObject['default'];
|
||||
var envCommunicationConfig = configObject[this.env];
|
||||
|
||||
var mergedConfig = utils.recursiveMerge(defaultCommunicationConfig, envCommunicationConfig);
|
||||
this.communicationConfig = mergedConfig || {};
|
||||
|
||||
// TODO: probably not necessary if the default object is done right
|
||||
if (this.communicationConfig.enabled === undefined) {
|
||||
this.communicationConfig.enabled = true;
|
||||
}
|
||||
if (this.communicationConfig.available_providers === undefined) {
|
||||
this.communicationConfig.available_providers = [];
|
||||
}
|
||||
};
|
||||
|
||||
Config.prototype.loadWebServerConfigFile = function() {
|
||||
var webServerConfigJSON;
|
||||
if (fs.existsSync(this.configDir + "webserver.json")) {
|
||||
webServerConfigJSON = fs.readJSONSync(this.configDir + "webserver.json");
|
||||
} else {
|
||||
webServerConfigJSON = {};
|
||||
}
|
||||
var defaultWebConfig = {
|
||||
"enabled": true,
|
||||
"host": "localhost",
|
||||
"port": 8000
|
||||
};
|
||||
this.webServerConfig = utils.recursiveMerge(defaultWebConfig, webServerConfigJSON);
|
||||
};
|
||||
|
||||
Config.prototype.loadEmbarkConfigFile = function() {
|
||||
var contracts = this.embarkConfig.contracts;
|
||||
this.contractsFiles = this.loadFiles(contracts);
|
||||
|
||||
this.buildDir = this.embarkConfig.buildDir;
|
||||
this.configDir = this.embarkConfig.config;
|
||||
};
|
||||
|
||||
Config.prototype.loadPipelineConfigFile = function() {
|
||||
var assets = this.embarkConfig.app;
|
||||
for(var targetFile in assets) {
|
||||
this.assetFiles[targetFile] = this.loadFiles(assets[targetFile]);
|
||||
}
|
||||
};
|
||||
|
||||
Config.prototype.loadChainTrackerFile = function() {
|
||||
//var self = this;
|
||||
var chainTracker;
|
||||
try {
|
||||
chainTracker = fs.readJSONSync(this.chainsFile);
|
||||
}
|
||||
catch(err) {
|
||||
//self.logger.info(this.chainsFile + ' file not found, creating it...');
|
||||
chainTracker = {};
|
||||
fs.writeJSONSync(this.chainsFile, {});
|
||||
}
|
||||
this.chainTracker = chainTracker;
|
||||
};
|
||||
|
||||
Config.prototype.loadFiles = function(files) {
|
||||
var self = this;
|
||||
var originalFiles = utils.filesMatchingPattern(files);
|
||||
var readFiles = [];
|
||||
|
||||
// get embark.js object first
|
||||
originalFiles.filter(function(file) {
|
||||
return file.indexOf('.') >= 0;
|
||||
}).filter(function(file) {
|
||||
if (file === 'embark.js') {
|
||||
|
||||
if (self.blockchainConfig.enabled || self.communicationConfig.provider === 'whisper' || self.communicationConfig.available_providers.indexOf('whisper') >= 0) {
|
||||
readFiles.push({filename: 'web3.js', content: fs.readFileSync(fs.embarkPath("js/web3.js")).toString(), path: fs.embarkPath("js/web3.js")});
|
||||
}
|
||||
|
||||
if (self.storageConfig.enabled && (self.storageConfig.provider === 'ipfs' || self.storageConfig.available_providers.indexOf('ipfs') >= 0)) {
|
||||
readFiles.push({filename: 'ipfs.js', content: fs.readFileSync(fs.embarkPath("js/ipfs.js")).toString(), path: fs.embarkPath("js/ipfs.js")});
|
||||
}
|
||||
|
||||
if (self.communicationConfig.enabled && (self.communicationConfig.provider === 'orbit' || self.communicationConfig.available_providers.indexOf('orbit') >= 0)) {
|
||||
// TODO: remove duplicated files if functionality is the same for storage and orbit
|
||||
readFiles.push({filename: 'ipfs-api.js', content: fs.readFileSync(fs.embarkPath("js/ipfs-api.min.js")).toString(), path: fs.embarkPath("js/ipfs-api.min.js")});
|
||||
readFiles.push({filename: 'orbit.js', content: fs.readFileSync(fs.embarkPath("js/orbit.min.js")).toString(), path: fs.embarkPath("js/orbit.min.js")});
|
||||
}
|
||||
|
||||
readFiles.push({filename: 'embark.js', content: fs.readFileSync(fs.embarkPath("js/build/embark.bundle.js")).toString(), path: fs.embarkPath("js/build/embark.bundle.js")});
|
||||
}
|
||||
});
|
||||
|
||||
// get plugins
|
||||
var filesFromPlugins = [];
|
||||
|
||||
var filePlugins = self.plugins.getPluginsFor('pipelineFiles');
|
||||
|
||||
if (filePlugins.length > 0) {
|
||||
filePlugins.forEach(function(plugin) {
|
||||
try {
|
||||
var fileObjects = plugin.runFilePipeline();
|
||||
for (var i=0; i < fileObjects.length; i++) {
|
||||
var fileObject = fileObjects[i];
|
||||
filesFromPlugins.push(fileObject);
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
self.logger.error(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
filesFromPlugins.filter(function(file) {
|
||||
if (utils.fileMatchesPattern(files, file.intendedPath)) {
|
||||
readFiles.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
// get user files
|
||||
originalFiles.filter(function(file) {
|
||||
return file.indexOf('.') >= 0;
|
||||
}).filter(function(file) {
|
||||
if (file === 'embark.js') {
|
||||
return;
|
||||
} else if (file === 'abi.js') {
|
||||
readFiles.push({filename: file, content: "", path: file});
|
||||
} else {
|
||||
readFiles.push({filename: file, content: fs.readFileSync(file).toString(), path: file});
|
||||
}
|
||||
});
|
||||
|
||||
return readFiles;
|
||||
};
|
||||
|
||||
Config.prototype.loadPluginContractFiles = function() {
|
||||
var self = this;
|
||||
|
||||
var contractsPlugins = this.plugins.getPluginsFor('contractFiles');
|
||||
if (contractsPlugins.length > 0) {
|
||||
contractsPlugins.forEach(function(plugin) {
|
||||
plugin.contractsFiles.forEach(function(file) {
|
||||
var filename = file.replace('./','');
|
||||
self.contractsFiles.push({filename: filename, content: plugin.loadPluginFile(file), path: plugin.pathToFile(file)});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Config;
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
var Core = function() {};
|
||||
|
||||
module.exports = Core;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// util to map async method names
|
||||
|
||||
function extend(filename, async) {
|
||||
if (async._waterfall !== undefined) {
|
||||
return;
|
||||
}
|
||||
async._waterfall = async.waterfall;
|
||||
async.waterfall = function(_tasks, callback) {
|
||||
var tasks = _tasks.map(function(t) {
|
||||
var fn = function() {
|
||||
console.log("async " + filename + ": " + t.name);
|
||||
t.apply(t, arguments);
|
||||
};
|
||||
return fn;
|
||||
});
|
||||
async._waterfall(tasks, callback);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = extend;
|
|
@ -0,0 +1,147 @@
|
|||
var Events = require('./events.js');
|
||||
var Logger = require('./logger.js');
|
||||
var Config = require('./config.js');
|
||||
|
||||
var DeployManager = require('../contracts/deploy_manager.js');
|
||||
var ABIGenerator = require('../contracts/abi.js');
|
||||
var Dashboard = require('../dashboard/dashboard.js');
|
||||
var ServicesMonitor = require('./services.js');
|
||||
var Pipeline = require('../pipeline/pipeline.js');
|
||||
var Server = require('../pipeline/server.js');
|
||||
var Watch = require('../pipeline/watch.js');
|
||||
|
||||
var Engine = function(options) {
|
||||
this.env = options.env;
|
||||
this.embarkConfig = options.embarkConfig;
|
||||
this.interceptLogs = options.interceptLogs;
|
||||
this.version = "2.4.0";
|
||||
};
|
||||
|
||||
Engine.prototype.init = function(_options) {
|
||||
var options = _options || {};
|
||||
this.events = new Events();
|
||||
this.logger = options.logger || new Logger({logLevel: 'debug'});
|
||||
this.config = new Config({env: this.env, logger: this.logger, events: this.events});
|
||||
this.config.loadConfigFiles({embarkConfig: this.embarkConfig, interceptLogs: this.interceptLogs});
|
||||
this.plugins = this.config.plugins;
|
||||
};
|
||||
|
||||
Engine.prototype.startService = function(serviceName, _options) {
|
||||
var options = _options || {};
|
||||
|
||||
var services = {
|
||||
"monitor": this.monitorService,
|
||||
"pipeline": this.pipelineService,
|
||||
"abi": this.abiService,
|
||||
"deployment": this.deploymentService,
|
||||
"fileWatcher": this.fileWatchService,
|
||||
"webServer": this.webServerService
|
||||
};
|
||||
|
||||
var service = services[serviceName];
|
||||
|
||||
if (!service) {
|
||||
throw new Error("unknown service: " + serviceName);
|
||||
}
|
||||
|
||||
// need to be careful with circular references due to passing the web3 object
|
||||
//this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")");
|
||||
return service.apply(this, [options]);
|
||||
};
|
||||
|
||||
Engine.prototype.monitorService = function(options) {
|
||||
var servicesMonitor = new ServicesMonitor({
|
||||
logger: this.logger,
|
||||
config: this.config,
|
||||
serverHost: options.serverHost,
|
||||
serverPort: options.serverPort,
|
||||
runWebserver: options.runWebserver,
|
||||
version: this.version
|
||||
});
|
||||
servicesMonitor.startMonitor();
|
||||
};
|
||||
|
||||
Engine.prototype.pipelineService = function(options) {
|
||||
var self = this;
|
||||
this.logger.setStatus("Building Assets");
|
||||
var pipeline = new Pipeline({
|
||||
buildDir: this.config.buildDir,
|
||||
contractsFiles: this.config.contractsFiles,
|
||||
assetFiles: this.config.assetFiles,
|
||||
logger: this.logger,
|
||||
plugins: this.plugins
|
||||
});
|
||||
this.events.on('abi', function(abi) {
|
||||
self.currentAbi = abi;
|
||||
pipeline.build(abi);
|
||||
self.events.emit('outputDone');
|
||||
});
|
||||
this.events.on('file-event', function(fileType, path) {
|
||||
if (fileType === 'asset') {
|
||||
self.config.reloadConfig();
|
||||
pipeline.build(self.abi, path);
|
||||
self.events.emit('outputDone');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Engine.prototype.abiService = function(options) {
|
||||
var self = this;
|
||||
var generateABICode = function(contractsManager) {
|
||||
var abiGenerator = new ABIGenerator({
|
||||
blockchainConfig: self.config.blockchainConfig,
|
||||
contractsManager: contractsManager,
|
||||
plugins: self.plugins,
|
||||
storageConfig: self.config.storageConfig,
|
||||
communicationConfig: self.config.communicationConfig
|
||||
});
|
||||
var embarkJSABI = abiGenerator.generateABI({useEmbarkJS: true});
|
||||
var vanillaABI = abiGenerator.generateABI({useEmbarkJS: false});
|
||||
var vanillaContractsABI = abiGenerator.generateContracts(false);
|
||||
|
||||
self.events.emit('abi-contracts-vanila', vanillaContractsABI);
|
||||
self.events.emit('abi-vanila', vanillaABI);
|
||||
self.events.emit('abi', embarkJSABI);
|
||||
};
|
||||
this.events.on('contractsDeployed', generateABICode);
|
||||
this.events.on('blockchainDisabled', generateABICode);
|
||||
};
|
||||
|
||||
Engine.prototype.deploymentService = function(options) {
|
||||
var self = this;
|
||||
this.deployManager = new DeployManager({
|
||||
web3: options.web3,
|
||||
trackContracts: options.trackContracts,
|
||||
config: this.config,
|
||||
logger: this.logger,
|
||||
plugins: this.plugins,
|
||||
events: this.events
|
||||
});
|
||||
|
||||
this.events.on('file-event', function(fileType, path) {
|
||||
if (fileType === 'contract' || fileType === 'config') {
|
||||
self.config.reloadConfig();
|
||||
self.deployManager.deployContracts(function() {});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Engine.prototype.fileWatchService = function(options) {
|
||||
this.logger.setStatus("Watching for changes");
|
||||
var watch = new Watch({logger: this.logger, events: this.events});
|
||||
watch.start();
|
||||
};
|
||||
|
||||
Engine.prototype.webServerService = function(options) {
|
||||
var webServerConfig = this.config.webServerConfig;
|
||||
if (!webServerConfig.enabled) { return; }
|
||||
this.logger.setStatus("Starting Server");
|
||||
var server = new Server({
|
||||
logger: this.logger,
|
||||
host: options.host || webServerConfig.host,
|
||||
port: options.port || webServerConfig.port
|
||||
});
|
||||
server.start(function(){});
|
||||
};
|
||||
|
||||
module.exports = Engine;
|
|
@ -0,0 +1,3 @@
|
|||
var EventEmitter = require('events');
|
||||
|
||||
module.exports = EventEmitter;
|
|
@ -0,0 +1,46 @@
|
|||
var fs = require('fs-extra');
|
||||
var utils = require('./utils.js');
|
||||
|
||||
function mkdirpSync() {
|
||||
return fs.mkdirpSync.apply(fs.mkdirpSync, arguments);
|
||||
}
|
||||
|
||||
function copySync() {
|
||||
return fs.copySync.apply(fs.copySync, arguments);
|
||||
}
|
||||
|
||||
function writeFileSync() {
|
||||
return fs.writeFileSync.apply(fs.writeFileSync, arguments);
|
||||
}
|
||||
|
||||
function readFileSync() {
|
||||
return fs.readFileSync.apply(fs.readFileSync, arguments);
|
||||
}
|
||||
|
||||
function readJSONSync() {
|
||||
return fs.readJSONSync.apply(fs.readJSONSync, arguments);
|
||||
}
|
||||
|
||||
function writeJSONSync() {
|
||||
return fs.writeJSONSync.apply(fs.writeJSONSync, arguments);
|
||||
}
|
||||
|
||||
function existsSync(){
|
||||
return fs.existsSync.apply(fs.existsSync, arguments);
|
||||
}
|
||||
|
||||
// returns embarks root directory
|
||||
function embarkPath(fileOrDir) {
|
||||
return utils.joinPath(__dirname, '/../../', fileOrDir);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mkdirpSync: mkdirpSync,
|
||||
copySync: copySync,
|
||||
readFileSync: readFileSync,
|
||||
writeFileSync: writeFileSync,
|
||||
readJSONSync: readJSONSync,
|
||||
writeJSONSync: writeJSONSync,
|
||||
existsSync: existsSync,
|
||||
embarkPath: embarkPath
|
||||
};
|
|
@ -4,8 +4,9 @@ var Logger = function(options) {
|
|||
this.logLevels = ['error', 'warn', 'info', 'debug', 'trace'];
|
||||
this.logLevel = options.logLevel || 'info';
|
||||
this.logFunction = options.logFunction || console.log;
|
||||
this.contractsState = options.contractsState || console.log;
|
||||
this.availableServices = options.availableServices || console.log;
|
||||
this.contractsState = options.contractsState || function() {};
|
||||
this.availableServices = options.availableServices || function() {};
|
||||
this.setStatus = options.setStatus || console.log;
|
||||
};
|
||||
|
||||
Logger.prototype.error = function(txt) {
|
|
@ -0,0 +1,159 @@
|
|||
/*jshint esversion: 6, loopfunc: true */
|
||||
var fs = require('./fs.js');
|
||||
var utils = require('./utils.js');
|
||||
|
||||
// TODO: pass other params like blockchainConfig, contract files, etc..
|
||||
var Plugin = function(options) {
|
||||
this.name = options.name;
|
||||
this.pluginModule = options.pluginModule;
|
||||
this.pluginPath = options.pluginPath;
|
||||
this.pluginConfig = options.pluginConfig;
|
||||
this.shouldInterceptLogs = options.interceptLogs;
|
||||
this.clientWeb3Providers = [];
|
||||
this.contractsGenerators = [];
|
||||
this.pipeline = [];
|
||||
this.pipelineFiles = [];
|
||||
this.console = [];
|
||||
this.contractsConfigs = [];
|
||||
this.contractsFiles = [];
|
||||
this.compilers = [];
|
||||
this.pluginTypes = [];
|
||||
this.logger = options.logger;
|
||||
this.events = options.events;
|
||||
this.config = options.config;
|
||||
};
|
||||
|
||||
Plugin.prototype.loadPlugin = function() {
|
||||
if (this.shouldInterceptLogs) {
|
||||
this.interceptLogs(this.pluginModule);
|
||||
}
|
||||
(this.pluginModule.call(this, this));
|
||||
};
|
||||
|
||||
Plugin.prototype.loadPluginFile = function(filename) {
|
||||
return fs.readFileSync(this.pathToFile(filename)).toString();
|
||||
};
|
||||
|
||||
Plugin.prototype.pathToFile = function(filename) {
|
||||
return utils.joinPath(this.pluginPath, filename);
|
||||
};
|
||||
|
||||
Plugin.prototype.interceptLogs = function(context) {
|
||||
var self = this;
|
||||
// TODO: this is a bit nasty, figure out a better way
|
||||
context.console = context.console || console;
|
||||
|
||||
//context.console.error = function(txt) {
|
||||
// // TODO: logger should support an array instead of a single argument
|
||||
// //self.logger.error.apply(self.logger, arguments);
|
||||
// self.logger.error(self.name + " > " + txt);
|
||||
//};
|
||||
context.console.log = function(txt) {
|
||||
self.logger.info(self.name + " > " + txt);
|
||||
};
|
||||
context.console.warn = function(txt) {
|
||||
self.logger.warn(self.name + " > " + txt);
|
||||
};
|
||||
context.console.info = function(txt) {
|
||||
self.logger.info(self.name + " > " + txt);
|
||||
};
|
||||
context.console.debug = function(txt) {
|
||||
// TODO: ue JSON.stringify
|
||||
self.logger.debug(self.name + " > " + txt);
|
||||
};
|
||||
context.console.trace = function(txt) {
|
||||
self.logger.trace(self.name + " > " + txt);
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: add deploy provider
|
||||
Plugin.prototype.registerClientWeb3Provider = function(cb) {
|
||||
this.clientWeb3Providers.push(cb);
|
||||
this.pluginTypes.push('clientWeb3Provider');
|
||||
};
|
||||
|
||||
Plugin.prototype.registerContractsGeneration = function(cb) {
|
||||
this.contractsGenerators.push(cb);
|
||||
this.pluginTypes.push('contractGeneration');
|
||||
};
|
||||
|
||||
Plugin.prototype.registerPipeline = function(matcthingFiles, cb) {
|
||||
// TODO: generate error for more than one pipeline per plugin
|
||||
this.pipeline.push({matcthingFiles: matcthingFiles, cb: cb});
|
||||
this.pluginTypes.push('pipeline');
|
||||
};
|
||||
|
||||
Plugin.prototype.addFileToPipeline = function(file, intendedPath, options) {
|
||||
this.pipelineFiles.push({file: file, intendedPath: intendedPath, options: options});
|
||||
this.pluginTypes.push('pipelineFiles');
|
||||
};
|
||||
|
||||
Plugin.prototype.addContractFile = function(file) {
|
||||
this.contractsFiles.push(file);
|
||||
this.pluginTypes.push('contractFiles');
|
||||
};
|
||||
|
||||
Plugin.prototype.registerConsoleCommand = function(cb) {
|
||||
this.console.push(cb);
|
||||
this.pluginTypes.push('console');
|
||||
};
|
||||
|
||||
Plugin.prototype.has = function(pluginType) {
|
||||
return this.pluginTypes.indexOf(pluginType) >= 0;
|
||||
};
|
||||
|
||||
Plugin.prototype.generateProvider = function(args) {
|
||||
return this.clientWeb3Providers.map(function(cb) {
|
||||
return cb.call(this, args);
|
||||
}).join("\n");
|
||||
};
|
||||
|
||||
Plugin.prototype.generateContracts = function(args) {
|
||||
return this.contractsGenerators.map(function(cb) {
|
||||
return cb.call(this, args);
|
||||
}).join("\n");
|
||||
};
|
||||
|
||||
Plugin.prototype.registerContractConfiguration = function(config) {
|
||||
this.contractsConfigs.push(config);
|
||||
this.pluginTypes.push('contractsConfig');
|
||||
};
|
||||
|
||||
Plugin.prototype.registerCompiler = function(extension, cb) {
|
||||
this.compilers.push({extension: extension, cb: cb});
|
||||
this.pluginTypes.push('compilers');
|
||||
};
|
||||
|
||||
Plugin.prototype.runCommands = function(cmd, options) {
|
||||
return this.console.map(function(cb) {
|
||||
return cb.call(this, cmd, options);
|
||||
}).join("\n");
|
||||
};
|
||||
|
||||
Plugin.prototype.runFilePipeline = function() {
|
||||
var self = this;
|
||||
|
||||
return this.pipelineFiles.map(function(file) {
|
||||
var obj = {};
|
||||
obj.filename = file.file.replace('./','');
|
||||
obj.content = self.loadPluginFile(file.file).toString();
|
||||
obj.intendedPath = file.intendedPath;
|
||||
obj.options = file.options;
|
||||
obj.path = self.pathToFile(obj.filename);
|
||||
|
||||
return obj;
|
||||
});
|
||||
};
|
||||
|
||||
Plugin.prototype.runPipeline = function(args) {
|
||||
// TODO: should iterate the pipelines
|
||||
var pipeline = this.pipeline[0];
|
||||
var shouldRunPipeline = utils.fileMatchesPattern(pipeline.matcthingFiles, args.targetFile);
|
||||
if (shouldRunPipeline) {
|
||||
return pipeline.cb.call(this, args);
|
||||
} else {
|
||||
return args.source;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Plugin;
|
|
@ -0,0 +1,45 @@
|
|||
var Plugin = require('./plugin.js');
|
||||
var utils = require('./utils.js');
|
||||
|
||||
var Plugins = function(options) {
|
||||
this.pluginList = options.plugins || [];
|
||||
this.interceptLogs = options.interceptLogs;
|
||||
this.plugins = [];
|
||||
// TODO: need backup 'NullLogger'
|
||||
this.logger = options.logger;
|
||||
this.events = options.events;
|
||||
this.config = options.config;
|
||||
};
|
||||
|
||||
Plugins.prototype.loadPlugins = function() {
|
||||
var pluginConfig;
|
||||
for (var pluginName in this.pluginList) {
|
||||
pluginConfig = this.pluginList[pluginName];
|
||||
this.loadPlugin(pluginName, pluginConfig);
|
||||
}
|
||||
};
|
||||
|
||||
Plugins.prototype.listPlugins = function() {
|
||||
var list = [];
|
||||
for (var className in this.pluginList) {
|
||||
list.push(className);
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
Plugins.prototype.loadPlugin = function(pluginName, pluginConfig) {
|
||||
var pluginPath = utils.joinPath(process.env.PWD, 'node_modules', pluginName);
|
||||
var plugin = require(pluginPath);
|
||||
|
||||
var pluginWrapper = new Plugin({name: pluginName, pluginModule: plugin, pluginConfig: pluginConfig, logger: this.logger, pluginPath: pluginPath, interceptLogs: this.interceptLogs, events: this.events, config: this.config});
|
||||
pluginWrapper.loadPlugin();
|
||||
this.plugins.push(pluginWrapper);
|
||||
};
|
||||
|
||||
Plugins.prototype.getPluginsFor = function(pluginType) {
|
||||
return this.plugins.filter(function(plugin) {
|
||||
return plugin.has(pluginType);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Plugins;
|
|
@ -0,0 +1,18 @@
|
|||
var Web3 = require('web3');
|
||||
var web3;
|
||||
|
||||
// ======================
|
||||
// the eval is used for evaluating some of the contact calls for different purposes
|
||||
// this should be at least moved to a different process and scope
|
||||
// for now it is defined here
|
||||
// ======================
|
||||
function doEval(code, _web3) {
|
||||
if (_web3) {
|
||||
web3 = _web3;
|
||||
}
|
||||
return eval(code); // jshint ignore:line
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
doEval: doEval
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
var Web3 = require('web3');
|
||||
var async = require('async');
|
||||
var http = require('http');
|
||||
var utils = require('./utils.js');
|
||||
|
||||
// TODO: needs a refactor and be done in a different way
|
||||
var ServicesMonitor = function(options) {
|
||||
this.logger = options.logger;
|
||||
this.interval = options.interval || 5000;
|
||||
this.config = options.config;
|
||||
this.serverHost = options.serverHost || 'localhost';
|
||||
this.serverPort = options.serverPort || 8000;
|
||||
this.runWebserver = options.runWebserver;
|
||||
this.version = options.version;
|
||||
};
|
||||
|
||||
ServicesMonitor.prototype.startMonitor = function() {
|
||||
this.check();
|
||||
this.monitor = setInterval(this.check.bind(this), this.interval);
|
||||
};
|
||||
|
||||
ServicesMonitor.prototype.stopMonitor = function() {
|
||||
};
|
||||
|
||||
ServicesMonitor.prototype.check = function() {
|
||||
var self = this;
|
||||
async.waterfall([
|
||||
function connectWeb3(callback) {
|
||||
self.logger.trace('connectWeb3');
|
||||
var web3 = new Web3();
|
||||
var web3Endpoint = 'http://' + self.config.blockchainConfig.rpcHost + ':' + self.config.blockchainConfig.rpcPort;
|
||||
web3.setProvider(new web3.providers.HttpProvider(web3Endpoint));
|
||||
callback(null, web3, []);
|
||||
},
|
||||
function addEmbarkVersion(web3, result, callback) {
|
||||
self.logger.trace('addEmbarkVersion');
|
||||
result.push(('Embark ' + self.version).green);
|
||||
callback(null, web3, result);
|
||||
},
|
||||
function checkEthereum(web3, result, callback) {
|
||||
self.logger.trace('checkEthereum');
|
||||
var service;
|
||||
if (web3.isConnected()) {
|
||||
service = (web3.version.node.split("/")[0] + " " + web3.version.node.split("/")[1].split("-")[0] + " (Ethereum)").green;
|
||||
} else {
|
||||
service = "No Blockchain node found".red;
|
||||
}
|
||||
result.push(service);
|
||||
callback(null, web3, result);
|
||||
},
|
||||
function checkWhisper(web3, result, callback) {
|
||||
self.logger.trace('checkWhisper');
|
||||
web3.version.getWhisper(function(err, res) {
|
||||
var service = 'Whisper';
|
||||
result.push(err ? service.red : service.green);
|
||||
callback(null, result);
|
||||
});
|
||||
},
|
||||
function checkIPFS(result, callback) {
|
||||
self.logger.trace('checkIPFS');
|
||||
|
||||
utils.checkIsAvailable('http://localhost:5001', function(available) {
|
||||
if (available) {
|
||||
//Ideally this method should be in an IPFS API JSONRPC wrapper
|
||||
//The URL should also be flexible to accept non-default IPFS url
|
||||
self.logger.trace("Checking IPFS version...");
|
||||
http.get('http://localhost:5001/api/v0/version', function(res) {
|
||||
var body = '';
|
||||
res.on('data', function(d) {
|
||||
body += d;
|
||||
});
|
||||
res.on('end', function() {
|
||||
var parsed = JSON.parse(body);
|
||||
if(parsed.Version){
|
||||
result.push(("IPFS " + parsed.Version).green);
|
||||
}
|
||||
else{
|
||||
result.push("IPFS".green);
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
res.on('error', function(err) {
|
||||
self.logger.trace("Check IPFS version error: " + err);
|
||||
result.push("IPFS".green);
|
||||
callback(null, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
result.push('IPFS'.red);
|
||||
return callback(null, result);
|
||||
}
|
||||
});
|
||||
},
|
||||
function checkDevServer(result, callback) {
|
||||
var host = self.serverHost || self.config.webServerConfig.host;
|
||||
var port = self.serverPort || self.config.webServerConfig.port;
|
||||
self.logger.trace('checkDevServer');
|
||||
var devServer = 'Webserver (http://' + host + ':' + port + ')';
|
||||
devServer = (self.runWebserver) ? devServer.green : devServer.red;
|
||||
result.push(devServer);
|
||||
callback(null, result);
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
self.logger.error(err.message);
|
||||
} else {
|
||||
self.logger.availableServices(result);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = ServicesMonitor;
|
|
@ -0,0 +1,102 @@
|
|||
var async = require('async');
|
||||
var Web3 = require('web3');
|
||||
|
||||
var Embark = require('../index.js');
|
||||
|
||||
var Engine = require('./engine.js');
|
||||
|
||||
var ABIGenerator = require('../contracts/abi.js');
|
||||
var ContractsManager = require('../contracts/contracts.js');
|
||||
var Deploy = require('../contracts/deploy.js');
|
||||
|
||||
var Config = require('./config.js');
|
||||
var RunCode = require('./runCode.js');
|
||||
var TestLogger = require('./test_logger.js');
|
||||
|
||||
var getSimulator = function() {
|
||||
try {
|
||||
var sim = require('ethereumjs-testrpc');
|
||||
return sim;
|
||||
} catch (e) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
console.log('Simulator not found; Please install it with "npm install ethereumjs-testrpc --save"');
|
||||
console.log('IMPORTANT: if you using a NodeJS version older than 6.9.1 then you need to install an older version of testrpc "npm install ethereumjs-testrpc@2.0 --save"');
|
||||
console.log('For more information see https://github.com/ethereumjs/testrpc');
|
||||
// TODO: should throw exception instead
|
||||
return process.exit();
|
||||
}
|
||||
console.log("==============");
|
||||
console.log("Tried to load testrpc but an error occurred. This is a problem with testrpc");
|
||||
console.log('IMPORTANT: if you using a NodeJS version older than 6.9.1 then you need to install an older version of testrpc "npm install ethereumjs-testrpc@2.0 --save". Alternatively install node 6.9.1 and the testrpc 3.0');
|
||||
console.log("==============");
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
var Test = function(options) {
|
||||
this.options = options || {};
|
||||
var simOptions = this.options.simulatorOptions || {};
|
||||
|
||||
this.engine = new Engine({
|
||||
env: this.options.env || 'test',
|
||||
// TODO: confi will need to detect if this is a obj
|
||||
embarkConfig: this.options.embarkConfig || 'embark.json',
|
||||
interceptLogs: false
|
||||
});
|
||||
|
||||
this.engine.init({
|
||||
logger: new TestLogger({logLevel: this.options.logLevel || 'debug'})
|
||||
});
|
||||
|
||||
this.sim = getSimulator();
|
||||
this.web3 = new Web3();
|
||||
this.web3.setProvider(this.sim.provider(simOptions));
|
||||
};
|
||||
|
||||
Test.prototype.deployAll = function(contractsConfig, cb) {
|
||||
var self = this;
|
||||
|
||||
async.waterfall([
|
||||
function getConfig(callback) {
|
||||
self.engine.config.contractsConfig = {contracts: contractsConfig};
|
||||
callback();
|
||||
},
|
||||
function startServices(callback) {
|
||||
//{abiType: 'contracts', embarkJS: false}
|
||||
self.engine.startService("abi");
|
||||
self.engine.startService("deployment", {
|
||||
web3: self.web3,
|
||||
trackContracts: false
|
||||
});
|
||||
callback();
|
||||
},
|
||||
function deploy(callback) {
|
||||
self.engine.events.on('abi-contracts-vanila', function(vanillaABI) {
|
||||
callback(null, vanillaABI);
|
||||
});
|
||||
self.engine.deployManager.deployContracts(function(err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
console.log("got error");
|
||||
process.exit();
|
||||
}
|
||||
// this should be part of the waterfall and not just something done at the
|
||||
// end
|
||||
self.web3.eth.getAccounts(function(err, accounts) {
|
||||
if (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
self.web3.eth.defaultAccount = accounts[0];
|
||||
RunCode.doEval(result, self.web3); // jshint ignore:line
|
||||
cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Test;
|
|
@ -0,0 +1,67 @@
|
|||
/*global exit */
|
||||
var path = require('path');
|
||||
var globule = require('globule');
|
||||
var merge = require('merge');
|
||||
var http = require('http');
|
||||
var shelljs = require('shelljs');
|
||||
|
||||
function joinPath() {
|
||||
return path.join.apply(path.join, arguments);
|
||||
}
|
||||
|
||||
function filesMatchingPattern(files) {
|
||||
return globule.find(files, {nonull: true});
|
||||
}
|
||||
|
||||
function fileMatchesPattern(patterns, intendedPath) {
|
||||
return globule.isMatch(patterns, intendedPath);
|
||||
}
|
||||
|
||||
function recursiveMerge(target, source) {
|
||||
return merge.recursive(target, source);
|
||||
}
|
||||
|
||||
function checkIsAvailable(url, callback) {
|
||||
http.get(url, function(res) {
|
||||
callback(true);
|
||||
}).on('error', function(res) {
|
||||
callback(false);
|
||||
});
|
||||
}
|
||||
|
||||
function runCmd(cmd, options) {
|
||||
var result = shelljs.exec(cmd, options || {silent: true});
|
||||
if (result.code !== 0) {
|
||||
console.log("error doing.. " + cmd);
|
||||
console.log(result.output);
|
||||
if (result.stderr !== undefined) {
|
||||
console.log(result.stderr);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function cd(folder) {
|
||||
shelljs.cd(folder);
|
||||
}
|
||||
|
||||
function sed(file, pattern, replace) {
|
||||
shelljs.sed('-i', pattern, replace, file);
|
||||
}
|
||||
|
||||
function exit(code) {
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
joinPath: joinPath,
|
||||
filesMatchingPattern: filesMatchingPattern,
|
||||
fileMatchesPattern: fileMatchesPattern,
|
||||
recursiveMerge: recursiveMerge,
|
||||
checkIsAvailable: checkIsAvailable,
|
||||
runCmd: runCmd,
|
||||
cd: cd,
|
||||
sed: sed,
|
||||
exit: exit
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
var CommandHistory = function() {
|
||||
this.history = [];
|
||||
this.pointer = -1;
|
||||
};
|
||||
|
||||
CommandHistory.prototype.addCommand = function(cmd) {
|
||||
this.history.push(cmd);
|
||||
this.pointer = this.history.length;
|
||||
};
|
||||
|
||||
CommandHistory.prototype.getPreviousCommand = function(cmd) {
|
||||
if (this.pointer >= 0) {
|
||||
this.pointer--;
|
||||
}
|
||||
return this.history[this.pointer];
|
||||
};
|
||||
|
||||
CommandHistory.prototype.getNextCommand = function(cmd) {
|
||||
if (this.pointer >= this.history.length) {
|
||||
this.pointer = this.history.length - 1;
|
||||
return '';
|
||||
}
|
||||
this.pointer++;
|
||||
return this.history[this.pointer];
|
||||
};
|
||||
|
||||
module.exports = CommandHistory;
|
|
@ -0,0 +1,60 @@
|
|||
var utils = require('../core/utils.js');
|
||||
var RunCode = require('../core/runCode.js');
|
||||
|
||||
var Console = function(options) {
|
||||
this.plugins = options.plugins;
|
||||
this.version = options.version;
|
||||
};
|
||||
|
||||
Console.prototype.runCode = function(code) {
|
||||
RunCode.doEval(code); // jshint ignore:line
|
||||
};
|
||||
|
||||
Console.prototype.processEmbarkCmd = function(cmd) {
|
||||
if (cmd === 'help') {
|
||||
var helpText = [
|
||||
'Welcome to Embark ' + this.version,
|
||||
'',
|
||||
'possible commands are:',
|
||||
// TODO: only if the blockchain is actually active!
|
||||
// will need to pass te current embark state here
|
||||
'web3 - instantiated web3.js object configured to the current environment',
|
||||
'quit - to immediatly exit',
|
||||
'',
|
||||
'The web3 object and the interfaces for the deployed contracts and their methods are also available'
|
||||
];
|
||||
return helpText.join('\n');
|
||||
} else if (cmd === 'quit') {
|
||||
utils.exit();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Console.prototype.executeCmd = function(cmd, callback) {
|
||||
var plugin, pluginOutput;
|
||||
var plugins = this.plugins.getPluginsFor('console');
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
plugin = plugins[i];
|
||||
pluginOutput = plugin.runCommands(cmd, {});
|
||||
if (pluginOutput !== false && pluginOutput !== 'false') return callback(pluginOutput);
|
||||
}
|
||||
|
||||
var output = this.processEmbarkCmd(cmd);
|
||||
if (output) {
|
||||
return callback(output);
|
||||
}
|
||||
|
||||
try {
|
||||
var result = RunCode.doEval(cmd);
|
||||
return callback(result);
|
||||
}
|
||||
catch(e) {
|
||||
if (e.message.indexOf('not defined') > 0) {
|
||||
return callback(("error: " + e.message).red + ("\nType " + "help".bold + " to see the list of available commands").cyan);
|
||||
} else {
|
||||
return callback(e.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Console;
|
|
@ -0,0 +1,43 @@
|
|||
var async = require('async');
|
||||
|
||||
var Monitor = require('./monitor.js');
|
||||
var Console = require('./console.js');
|
||||
|
||||
var Dashboard = function(options) {
|
||||
this.logger = options.logger;
|
||||
this.plugins = options.plugins;
|
||||
this.version = options.version;
|
||||
this.env = options.env;
|
||||
};
|
||||
|
||||
Dashboard.prototype.start = function(done) {
|
||||
var console, monitor;
|
||||
var self = this;
|
||||
|
||||
async.waterfall([
|
||||
function startConsole(callback) {
|
||||
console = new Console({plugins: self.plugins, version: self.version});
|
||||
callback();
|
||||
},
|
||||
function startMonitor(callback) {
|
||||
monitor = new Monitor({env: self.env, console: console});
|
||||
self.logger.logFunction = monitor.logEntry;
|
||||
self.logger.contractsState = monitor.setContracts;
|
||||
self.logger.availableServices = monitor.availableServices;
|
||||
self.logger.setStatus = monitor.setStatus.bind(monitor);
|
||||
|
||||
self.logger.info('========================'.bold.green);
|
||||
self.logger.info(('Welcome to Embark ' + self.version).yellow.bold);
|
||||
self.logger.info('========================'.bold.green);
|
||||
|
||||
// TODO: do this after monitor is rendered
|
||||
callback();
|
||||
}
|
||||
], function() {
|
||||
self.console = console;
|
||||
self.monitor = monitor;
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Dashboard;
|
|
@ -1,41 +1,16 @@
|
|||
/*jshint esversion: 6 */
|
||||
|
||||
var blessed = require("blessed");
|
||||
|
||||
var CommandHistory = function() {
|
||||
this.history = [];
|
||||
this.pointer = -1;
|
||||
};
|
||||
|
||||
CommandHistory.prototype.addCommand = function(cmd) {
|
||||
this.history.push(cmd);
|
||||
this.pointer = this.history.length;
|
||||
};
|
||||
|
||||
CommandHistory.prototype.getPreviousCommand = function(cmd) {
|
||||
if (this.pointer >= 0) {
|
||||
this.pointer--;
|
||||
}
|
||||
return this.history[this.pointer];
|
||||
};
|
||||
|
||||
CommandHistory.prototype.getNextCommand = function(cmd) {
|
||||
if (this.pointer >= this.history.length) {
|
||||
this.pointer = this.history.length - 1;
|
||||
return '';
|
||||
}
|
||||
this.pointer++;
|
||||
return this.history[this.pointer];
|
||||
};
|
||||
var CommandHistory = require('./command_history.js');
|
||||
|
||||
function Dashboard(options) {
|
||||
var title = options && options.title || "Embark 2.0";
|
||||
var title = (options && options.title) || "Embark 2.4.0";
|
||||
this.env = options.env;
|
||||
this.console = options.console;
|
||||
this.history = new CommandHistory();
|
||||
|
||||
this.color = options && options.color || "green";
|
||||
this.minimal = options && options.minimal || false;
|
||||
this.color = (options && options.color) || "green";
|
||||
this.minimal = (options && options.minimal) || false;
|
||||
|
||||
this.screen = blessed.screen({
|
||||
smartCSR: true,
|
||||
|
@ -45,10 +20,10 @@ function Dashboard(options) {
|
|||
autoPadding: true
|
||||
});
|
||||
|
||||
this.layoutLog.call(this);
|
||||
this.layoutStatus.call(this);
|
||||
this.layoutModules.call(this);
|
||||
this.layoutCmd.call(this);
|
||||
this.layoutLog();
|
||||
this.layoutStatus();
|
||||
this.layoutModules();
|
||||
this.layoutCmd();
|
||||
|
||||
this.screen.key(["C-c"], function() {
|
||||
process.exit(0);
|
||||
|
@ -272,13 +247,13 @@ Dashboard.prototype.layoutStatus = function() {
|
|||
label: "Available Services",
|
||||
tags: true,
|
||||
padding: this.minimal ? {
|
||||
left: 1,
|
||||
left: 1
|
||||
} : 1,
|
||||
width: "100%",
|
||||
height: "60%",
|
||||
valign: "top",
|
||||
border: {
|
||||
type: "line",
|
||||
type: "line"
|
||||
},
|
||||
style: {
|
||||
fg: -1,
|
||||
|
@ -358,7 +333,7 @@ Dashboard.prototype.layoutCmd = function() {
|
|||
this.input.on('submit', function(data) {
|
||||
if (data !== '') {
|
||||
self.history.addCommand(data);
|
||||
self.logText.log('console> ' + data);
|
||||
self.logText.log('console> '.bold.green + data);
|
||||
self.console.executeCmd(data, function(result) {
|
||||
self.logText.log(result);
|
||||
});
|
|
@ -1,138 +0,0 @@
|
|||
|
||||
var GethCommands = function(options) {
|
||||
this.config = options.config;
|
||||
this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
|
||||
};
|
||||
|
||||
GethCommands.prototype.initGenesisCommmand = function() {
|
||||
var config = this.config;
|
||||
var cmd = "geth ";
|
||||
|
||||
if (config.networkType === 'testnet') {
|
||||
cmd += "--testnet ";
|
||||
} else if (config.networkType === 'olympic') {
|
||||
cmd += "--olympic ";
|
||||
}
|
||||
|
||||
if (config.datadir) {
|
||||
cmd += "--datadir=\"" + config.datadir + "\" ";
|
||||
}
|
||||
|
||||
if (config.genesisBlock) {
|
||||
cmd += "init \"" + config.genesisBlock + "\" ";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
};
|
||||
|
||||
GethCommands.prototype.newAccountCommand = function() {
|
||||
var config = this.config;
|
||||
var cmd = "geth ";
|
||||
|
||||
if (config.networkType === 'testnet') {
|
||||
cmd += "--testnet ";
|
||||
} else if (config.networkType === 'olympic') {
|
||||
cmd += "--olympic ";
|
||||
}
|
||||
|
||||
if (config.datadir) {
|
||||
cmd += "--datadir=\"" + config.datadir + "\" ";
|
||||
}
|
||||
|
||||
if (config.account && config.account.password) {
|
||||
cmd += "--password " + config.account.password + " ";
|
||||
}
|
||||
|
||||
return cmd + "account new ";
|
||||
};
|
||||
|
||||
GethCommands.prototype.listAccountsCommand = function() {
|
||||
var config = this.config;
|
||||
var cmd = "geth ";
|
||||
|
||||
if (config.networkType === 'testnet') {
|
||||
cmd += "--testnet ";
|
||||
} else if (config.networkType === 'olympic') {
|
||||
cmd += "--olympic ";
|
||||
}
|
||||
|
||||
if (config.datadir) {
|
||||
cmd += "--datadir=\"" + config.datadir + "\" ";
|
||||
}
|
||||
|
||||
if (config.account && config.account.password) {
|
||||
cmd += "--password " + config.account.password + " ";
|
||||
}
|
||||
|
||||
return cmd + "account list ";
|
||||
};
|
||||
|
||||
GethCommands.prototype.mainCommand = function(address) {
|
||||
var config = this.config;
|
||||
var cmd = "geth ";
|
||||
var rpc_api = ['eth', 'web3'];
|
||||
|
||||
if (config.datadir) {
|
||||
cmd += "--datadir=\"" + config.datadir + "\" ";
|
||||
}
|
||||
|
||||
if (config.networkType === 'testnet') {
|
||||
cmd += "--testnet ";
|
||||
} else if (config.networkType === 'olympic') {
|
||||
cmd += "--olympic ";
|
||||
}
|
||||
|
||||
if (config.networkType === 'custom') {
|
||||
cmd += "--networkid " + config.networkId + " ";
|
||||
}
|
||||
|
||||
if (config.account && config.account.password) {
|
||||
cmd += "--password " + config.account.password + " ";
|
||||
}
|
||||
|
||||
cmd += "--port " + "30303" + " ";
|
||||
cmd += "--rpc ";
|
||||
cmd += "--rpcport " + config.rpcPort + " ";
|
||||
cmd += "--rpcaddr " + config.rpcHost + " ";
|
||||
if (config.rpcCorsDomain) {
|
||||
if (config.rpcCorsDomain === '*') {
|
||||
console.log('==================================');
|
||||
console.log('make sure you know what you are doing');
|
||||
console.log('==================================');
|
||||
}
|
||||
cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
|
||||
} else {
|
||||
console.log('==================================');
|
||||
console.log('warning: cors is not set');
|
||||
console.log('==================================');
|
||||
}
|
||||
|
||||
if (config.nodiscover) {
|
||||
cmd += "--nodiscover ";
|
||||
}
|
||||
|
||||
if (config.mineWhenNeeded || config.mine) {
|
||||
cmd += "--mine ";
|
||||
}
|
||||
|
||||
if (config.whisper) {
|
||||
cmd += "--shh ";
|
||||
rpc_api.push('shh');
|
||||
}
|
||||
|
||||
cmd += '--rpcapi "' + rpc_api.join(',') + '" ';
|
||||
|
||||
var accountAddress = config.account.address || address;
|
||||
if (accountAddress) {
|
||||
cmd += "--unlock=" + accountAddress + " ";
|
||||
}
|
||||
|
||||
if (config.mineWhenNeeded) {
|
||||
cmd += "js .embark/development/js/mine.js";
|
||||
}
|
||||
|
||||
return cmd;
|
||||
};
|
||||
|
||||
module.exports = GethCommands;
|
||||
|
357
lib/index.js
357
lib/index.js
|
@ -1,257 +1,172 @@
|
|||
/*jshint esversion: 6 */
|
||||
var async = require('async');
|
||||
//require("./core/debug_util.js")(__filename, async);
|
||||
|
||||
var Web3 = require('web3');
|
||||
var fs = require('fs');
|
||||
var grunt = require('grunt');
|
||||
var mkdirp = require('mkdirp');
|
||||
var colors = require('colors');
|
||||
var chokidar = require('chokidar');
|
||||
|
||||
var Engine = require('./core/engine.js');
|
||||
|
||||
var Blockchain = require('./cmds/blockchain/blockchain.js');
|
||||
var Simulator = require('./cmds/simulator.js');
|
||||
var TemplateGenerator = require('./cmds/template_generator.js');
|
||||
|
||||
var Test = require('./core/test.js');
|
||||
var Logger = require('./core/logger.js');
|
||||
var Config = require('./core/config.js');
|
||||
var Events = require('./core/events.js');
|
||||
|
||||
var Dashboard = require('./dashboard/dashboard.js');
|
||||
|
||||
var IPFS = require('./upload/ipfs.js');
|
||||
var Swarm = require('./upload/swarm.js');
|
||||
|
||||
var Cmd = require('./cmd.js');
|
||||
var Deploy = require('./deploy.js');
|
||||
var ContractsManager = require('./contracts.js');
|
||||
var ABIGenerator = require('./abi.js');
|
||||
var TemplateGenerator = require('./template_generator.js');
|
||||
var Blockchain = require('./blockchain.js');
|
||||
var Server = require('./server.js');
|
||||
var Watch = require('./watch.js');
|
||||
var Pipeline = require('./pipeline.js');
|
||||
var Test = require('./test.js');
|
||||
var Logger = require('./logger.js');
|
||||
var Config = require('./config.js');
|
||||
var Monitor = require('./monitor.js');
|
||||
var ServicesMonitor = require('./services.js');
|
||||
var Console = require('./console.js');
|
||||
var IPFS = require('./ipfs.js');
|
||||
|
||||
var Embark = {
|
||||
|
||||
version: '2.4.0',
|
||||
|
||||
process: function(args) {
|
||||
var cmd = new Cmd(Embark);
|
||||
cmd.process(args);
|
||||
},
|
||||
|
||||
initConfig: function(env, options) {
|
||||
this.events = new Events();
|
||||
this.logger = new Logger({logLevel: 'debug'});
|
||||
|
||||
this.config = new Config({env: env, logger: this.logger, events: this.events});
|
||||
this.config.loadConfigFiles(options);
|
||||
this.plugins = this.config.plugins;
|
||||
},
|
||||
|
||||
blockchain: function(env, client) {
|
||||
var blockchain = Blockchain(this.config.blockchainConfig, client, env);
|
||||
blockchain.run();
|
||||
},
|
||||
|
||||
simulator: function(options) {
|
||||
var simulator = new Simulator({blockchainConfig: this.config.blockchainConfig});
|
||||
simulator.run(options);
|
||||
},
|
||||
|
||||
generateTemplate: function(templateName, destinationFolder, name) {
|
||||
var templateGenerator = new TemplateGenerator(templateName);
|
||||
templateGenerator.generate(destinationFolder, name);
|
||||
},
|
||||
|
||||
initConfig: function(env, options) {
|
||||
this.config = new Config({env: env});
|
||||
this.config.loadConfigFiles(options);
|
||||
this.logger = new Logger({logLevel: 'debug'});
|
||||
|
||||
//this.contractsManager = new ContractsManager(configDir, files, env);
|
||||
//this.contractsManager.init();
|
||||
//return this.contractsManager;
|
||||
},
|
||||
|
||||
redeploy: function(env) {
|
||||
var self = this;
|
||||
async.waterfall([
|
||||
function reloadFiles(callback) {
|
||||
self.config.reloadConfig();
|
||||
callback();
|
||||
},
|
||||
self.buildDeployGenerate.bind(self)
|
||||
], function(err, result) {
|
||||
self.logger.trace("finished".underline);
|
||||
});
|
||||
},
|
||||
|
||||
run: function(options) {
|
||||
var self = this;
|
||||
var env = options.env;
|
||||
async.waterfall([
|
||||
function startConsole(callback) {
|
||||
Embark.console = new Console();
|
||||
callback();
|
||||
},
|
||||
function startMonitor(callback) {
|
||||
Embark.monitor = new Monitor({env: env, console: Embark.console});
|
||||
Embark.monitor.setStatus("Starting");
|
||||
self.logger.logFunction = Embark.monitor.logEntry;
|
||||
self.logger.contractsState = Embark.monitor.setContracts;
|
||||
self.logger.availableServices = Embark.monitor.availableServices;
|
||||
// TODO: do this after monitor is rendered
|
||||
callback();
|
||||
},
|
||||
function monitorServices(callback) {
|
||||
Embark.servicesMonitor = new ServicesMonitor({
|
||||
logger: Embark.logger,
|
||||
config: Embark.config,
|
||||
serverPort: options.serverPort
|
||||
});
|
||||
Embark.servicesMonitor.startMonitor();
|
||||
callback();
|
||||
},
|
||||
self.buildDeployGenerate.bind(self),
|
||||
function startAssetServer(callback) {
|
||||
Embark.monitor.setStatus("Starting Server");
|
||||
var server = new Server({logger: self.logger, port: options.serverPort});
|
||||
server.start(callback);
|
||||
},
|
||||
function watchFilesForChanges(callback) {
|
||||
Embark.monitor.setStatus("Watching for changes");
|
||||
var watch = new Watch({logger: self.logger});
|
||||
watch.start();
|
||||
watch.on('redeploy', function() {
|
||||
self.logger.info("received redeploy event");
|
||||
Embark.redeploy();
|
||||
});
|
||||
watch.on('rebuildAssets', function() {
|
||||
self.logger.info("received rebuildAssets event");
|
||||
// TODO: make this more efficient
|
||||
Embark.redeploy();
|
||||
});
|
||||
callback();
|
||||
}
|
||||
], function(err, result) {
|
||||
Embark.monitor.setStatus("Ready".green);
|
||||
self.logger.trace("finished".underline);
|
||||
|
||||
var engine = new Engine({
|
||||
env: options.env,
|
||||
embarkConfig: 'embark.json'
|
||||
});
|
||||
},
|
||||
engine.init();
|
||||
|
||||
build: function(env) {
|
||||
async.waterfall([
|
||||
function deployAndGenerateABI(callback) {
|
||||
Embark.deploy(function(abi) {
|
||||
callback(null, abi);
|
||||
});
|
||||
},
|
||||
function buildPipeline(abi, callback) {
|
||||
var pipeline = new Pipeline({});
|
||||
pipeline.build(abi);
|
||||
callback();
|
||||
}
|
||||
], function(err, result) {
|
||||
self.logger.trace("finished".underline);
|
||||
});
|
||||
},
|
||||
if (!options.useDashboard) {
|
||||
console.log('========================'.bold.green);
|
||||
console.log(('Welcome to Embark ' + Embark.version).yellow.bold);
|
||||
console.log('========================'.bold.green);
|
||||
}
|
||||
|
||||
blockchain: function(env, client) {
|
||||
var blockchain = Blockchain(this.config.blockchainConfig, client);
|
||||
blockchain.run({env: env});
|
||||
},
|
||||
|
||||
buildAndDeploy: function(done) {
|
||||
var self = this;
|
||||
async.waterfall([
|
||||
function buildContracts(callback) {
|
||||
var contractsManager = new ContractsManager({
|
||||
contractFiles: self.config.contractsFiles,
|
||||
contractsConfig: self.config.contractsConfig,
|
||||
logger: Embark.logger
|
||||
});
|
||||
try {
|
||||
contractsManager.build();
|
||||
callback(null, contractsManager);
|
||||
} catch(err) {
|
||||
callback(new Error(err.message));
|
||||
}
|
||||
},
|
||||
function deployContracts(contractsManager, callback) {
|
||||
|
||||
//TODO: figure out where to put this since the web3 can be passed along if needed
|
||||
// perhaps it should go into the deploy object itself
|
||||
// TODO: should come from the config object
|
||||
var web3 = new Web3();
|
||||
var web3Endpoint = 'http://' + self.config.blockchainConfig.rpcHost + ':' + self.config.blockchainConfig.rpcPort;
|
||||
web3.setProvider(new web3.providers.HttpProvider(web3Endpoint));
|
||||
|
||||
if (!web3.isConnected()) {
|
||||
console.log(("Couldn't connect to " + web3Endpoint.underline + " are you sure it's on?").red);
|
||||
console.log("make sure you have an ethereum node or simulator running. e.g 'embark blockchain'".magenta);
|
||||
exit();
|
||||
async.parallel([
|
||||
function startDashboard(callback) {
|
||||
if (!options.useDashboard) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
web3.eth.getAccounts(function(err, accounts) {
|
||||
web3.eth.defaultAccount = accounts[0];
|
||||
|
||||
var deploy = new Deploy({
|
||||
web3: web3,
|
||||
contractsManager: contractsManager,
|
||||
logger: Embark.logger,
|
||||
chainConfig: self.config.chainTracker,
|
||||
env: self.config.env
|
||||
});
|
||||
deploy.deployAll(function() {
|
||||
callback(null, contractsManager);
|
||||
});
|
||||
var dashboard = new Dashboard({
|
||||
logger: engine.logger,
|
||||
plugins: engine.plugins,
|
||||
version: engine.version,
|
||||
env: engine.env
|
||||
});
|
||||
dashboard.start(function() {
|
||||
engine.events.on('abi-vanila', function(abi) {
|
||||
dashboard.console.runCode(abi);
|
||||
});
|
||||
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
done(err, null);
|
||||
} else {
|
||||
done(null, result);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deploy: function(done) {
|
||||
var self = this;
|
||||
async.waterfall([
|
||||
function buildAndDeploy(callback) {
|
||||
Embark.buildAndDeploy(function(contractsManager) {
|
||||
callback(null, contractsManager);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function generateABI(contractsManager, callback) {
|
||||
var abiGenerator = new ABIGenerator(self.config.blockchainConfig, contractsManager);
|
||||
callback(null, abiGenerator.generateABI({useEmbarkJS: true}));
|
||||
}
|
||||
], function(err, result) {
|
||||
done(result);
|
||||
});
|
||||
},
|
||||
function (callback) {
|
||||
var pluginList = engine.plugins.listPlugins();
|
||||
if (pluginList.length > 0) {
|
||||
engine.logger.info("loaded plugins: " + pluginList.join(", "));
|
||||
}
|
||||
|
||||
if (options.useDashboard) {
|
||||
engine.startService("monitor", {
|
||||
serverHost: options.serverHost,
|
||||
serverPort: options.serverPort,
|
||||
runWebserver: options.runWebserver
|
||||
});
|
||||
}
|
||||
engine.startService("pipeline");
|
||||
engine.startService("abi");
|
||||
engine.startService("deployment");
|
||||
|
||||
buildDeployGenerate: function(done) {
|
||||
var self = this;
|
||||
|
||||
Embark.monitor.setStatus("Deploying...".magenta.underline);
|
||||
async.waterfall([
|
||||
function deployAndBuildContractsManager(callback) {
|
||||
Embark.buildAndDeploy(function(err, contractsManager) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, contractsManager);
|
||||
engine.deployManager.deployContracts(function() {
|
||||
engine.startService("fileWatcher");
|
||||
if (options.runWebserver) {
|
||||
engine.startService("webServer", {
|
||||
host: options.serverHost,
|
||||
port: options.serverPort
|
||||
});
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function generateConsoleABI(contractsManager, callback) {
|
||||
var abiGenerator = new ABIGenerator(self.config.blockchainConfig, contractsManager);
|
||||
var consoleABI = abiGenerator.generateABI({useEmbarkJS: false});
|
||||
Embark.console.runCode(consoleABI);
|
||||
callback(null, contractsManager);
|
||||
},
|
||||
function generateABI(contractsManager, callback) {
|
||||
var abiGenerator = new ABIGenerator(self.config.blockchainConfig, contractsManager);
|
||||
callback(null, abiGenerator.generateABI({useEmbarkJS: true}));
|
||||
},
|
||||
function buildPipeline(abi, callback) {
|
||||
Embark.monitor.setStatus("Building Assets");
|
||||
var pipeline = new Pipeline({
|
||||
buildDir: self.config.buildDir,
|
||||
contractsFiles: self.config.contractsFiles,
|
||||
assetFiles: self.config.assetFiles,
|
||||
logger: self.logger
|
||||
});
|
||||
pipeline.build(abi);
|
||||
callback();
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
self.logger.error("error deploying");
|
||||
self.logger.error(err.message);
|
||||
Embark.monitor.setStatus("Deployment Error".red);
|
||||
engine.logger.error(err.message);
|
||||
} else {
|
||||
Embark.monitor.setStatus("Ready".green);
|
||||
engine.logger.setStatus("Ready".green);
|
||||
engine.logger.info("Looking for documentation? you can find it at ".cyan + "http://embark.readthedocs.io/".green.underline);
|
||||
engine.logger.info("Ready".underline);
|
||||
engine.events.emit('firstDeploymentDone');
|
||||
}
|
||||
done(result);
|
||||
});
|
||||
},
|
||||
|
||||
build: function(options) {
|
||||
var self = this;
|
||||
|
||||
var engine = new Engine({
|
||||
env: options.env,
|
||||
embarkConfig: 'embark.json',
|
||||
interceptLogs: false
|
||||
});
|
||||
engine.init();
|
||||
|
||||
async.waterfall([
|
||||
function startServices(callback) {
|
||||
var pluginList = engine.plugins.listPlugins();
|
||||
if (pluginList.length > 0) {
|
||||
engine.logger.info("loaded plugins: " + pluginList.join(", "));
|
||||
}
|
||||
|
||||
engine.startService("pipeline");
|
||||
engine.startService("abi");
|
||||
engine.startService("deployment");
|
||||
callback();
|
||||
},
|
||||
function deploy(callback) {
|
||||
engine.deployManager.deployContracts(function() {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
], function(err, result) {
|
||||
if (err) {
|
||||
engine.logger.error(err.message);
|
||||
} else {
|
||||
engine.logger.info("finished building".underline);
|
||||
}
|
||||
// needed due to child processes
|
||||
process.exit();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -260,9 +175,17 @@ var Embark = {
|
|||
},
|
||||
|
||||
// TODO: should deploy if it hasn't already
|
||||
ipfs: function() {
|
||||
var ipfs = new IPFS({buildDir: 'dist/'});
|
||||
ipfs.deploy();
|
||||
upload: function(platform) {
|
||||
if (platform === 'ipfs') {
|
||||
var ipfs = new IPFS({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig});
|
||||
ipfs.deploy();
|
||||
} else if (platform === 'swarm') {
|
||||
var swarm = new Swarm({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig});
|
||||
swarm.deploy();
|
||||
} else {
|
||||
console.log(("unknown platform: " + platform).red);
|
||||
console.log('try "embark upload ipfs" or "embark upload swarm"'.green);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
29
lib/ipfs.js
29
lib/ipfs.js
|
@ -1,29 +0,0 @@
|
|||
var colors = require('colors');
|
||||
|
||||
var IPFS = function(options) {
|
||||
this.options = options;
|
||||
this.buildDir = options.buildDir || 'dist/';
|
||||
};
|
||||
|
||||
IPFS.prototype.deploy = function() {
|
||||
var ipfs_bin = exec('which ipfs').output.split("\n")[0];
|
||||
|
||||
if (ipfs_bin==='ipfs not found'){
|
||||
console.log('=== WARNING: IPFS not in an executable path. Guessing ~/go/bin/ipfs for path'.yellow);
|
||||
ipfs_bin = "~/go/bin/ipfs";
|
||||
}
|
||||
|
||||
var cmd = ipfs_bin + " add -r " + build_dir;
|
||||
console.log(("=== adding " + cmd + " to ipfs").green);
|
||||
|
||||
var result = exec(cmd);
|
||||
var rows = result.output.split("\n");
|
||||
var dir_row = rows[rows.length - 2];
|
||||
var dir_hash = dir_row.split(" ")[1];
|
||||
|
||||
console.log(("=== DApp available at http://localhost:8080/ipfs/" + dir_hash + "/").green);
|
||||
console.log(("=== DApp available at http://gateway.ipfs.io/ipfs/" + dir_hash + "/").green);
|
||||
};
|
||||
|
||||
module.exports = IPFS;
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*jshint esversion: 6, loopfunc: true */
|
||||
var fs = require('fs');
|
||||
var grunt = require('grunt');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
var Pipeline = function(options) {
|
||||
this.buildDir = options.buildDir;
|
||||
this.contractsFiles = options.contractsFiles;
|
||||
this.assetFiles = options.assetFiles;
|
||||
this.logger = options.logger;
|
||||
};
|
||||
|
||||
Pipeline.prototype.build = function(abi) {
|
||||
var self = this;
|
||||
for(var targetFile in this.assetFiles) {
|
||||
|
||||
var content = this.assetFiles[targetFile].map(file => {
|
||||
self.logger.info("reading " + file.filename);
|
||||
if (file.filename === 'embark.js') {
|
||||
return file.content + "\n" + abi;
|
||||
} else {
|
||||
return file.content;
|
||||
}
|
||||
}).join("\n");
|
||||
|
||||
var dir = targetFile.split('/').slice(0, -1).join('/');
|
||||
self.logger.info("creating dir " + this.buildDir + dir);
|
||||
mkdirp.sync(this.buildDir + dir);
|
||||
|
||||
self.logger.info("writing file " + this.buildDir + targetFile);
|
||||
fs.writeFileSync(this.buildDir + targetFile, content);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Pipeline;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*jshint esversion: 6, loopfunc: true */
|
||||
var fs = require('../core/fs.js');
|
||||
|
||||
var Pipeline = function(options) {
|
||||
this.buildDir = options.buildDir;
|
||||
this.contractsFiles = options.contractsFiles;
|
||||
this.assetFiles = options.assetFiles;
|
||||
this.logger = options.logger;
|
||||
this.plugins = options.plugins;
|
||||
};
|
||||
|
||||
Pipeline.prototype.build = function(abi, path) {
|
||||
var self = this;
|
||||
for(var targetFile in this.assetFiles) {
|
||||
|
||||
var contentFiles = this.assetFiles[targetFile].map(file => {
|
||||
self.logger.trace("reading " + file.filename);
|
||||
|
||||
var pipelinePlugins = this.plugins.getPluginsFor('pipeline');
|
||||
|
||||
if (file.filename === 'embark.js') {
|
||||
return {content: file.content + "\n" + abi, filename: file.filename, path: file.path, modified: true};
|
||||
} else if (file.filename === 'abi.js') {
|
||||
return {content: abi, filename: file.filename, path: file.path, modified: true};
|
||||
} else if (['web3.js', 'ipfs.js', 'ipfs-api.js', 'orbit.js'].indexOf(file.filename) >= 0) {
|
||||
file.modified = true;
|
||||
return file;
|
||||
} else {
|
||||
|
||||
if (pipelinePlugins.length > 0) {
|
||||
pipelinePlugins.forEach(function(plugin) {
|
||||
try {
|
||||
if (file.options && file.options.skipPipeline) {
|
||||
return;
|
||||
}
|
||||
file.content = plugin.runPipeline({targetFile: file.filename, source: file.content});
|
||||
file.modified = true;
|
||||
}
|
||||
catch(err) {
|
||||
self.logger.error(err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
});
|
||||
|
||||
var dir = targetFile.split('/').slice(0, -1).join('/');
|
||||
self.logger.trace("creating dir " + this.buildDir + dir);
|
||||
fs.mkdirpSync(this.buildDir + dir);
|
||||
|
||||
// if it's a directory
|
||||
if (targetFile.slice(-1) === '/' || targetFile.indexOf('.') === -1) {
|
||||
var targetDir = targetFile;
|
||||
|
||||
if (targetDir.slice(-1) !== '/') {
|
||||
targetDir = targetDir + '/';
|
||||
}
|
||||
|
||||
contentFiles.map(function(file) {
|
||||
var filename = file.filename.replace('app/', '');
|
||||
filename = filename.replace(targetDir, '');
|
||||
self.logger.info("writing file " + (self.buildDir + targetDir + filename).bold.dim);
|
||||
|
||||
fs.copySync(self.buildDir + targetDir + filename, file.path, {overwrite: true});
|
||||
});
|
||||
} else {
|
||||
var content = contentFiles.map(function(file) {
|
||||
return file.content;
|
||||
}).join("\n");
|
||||
|
||||
self.logger.info("writing file " + (this.buildDir + targetFile).bold.dim);
|
||||
fs.writeFileSync(this.buildDir + targetFile, content);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Pipeline;
|
||||
|
|
@ -5,6 +5,7 @@ var serveStatic = require('serve-static');
|
|||
var Server = function(options) {
|
||||
this.dist = options.dist || 'dist/';
|
||||
this.port = options.port || 8000;
|
||||
this.hostname = options.host || 'localhost';
|
||||
this.logger = options.logger;
|
||||
};
|
||||
|
||||
|
@ -15,8 +16,8 @@ Server.prototype.start = function(callback) {
|
|||
serve(req, res, finalhandler(req, res));
|
||||
});
|
||||
|
||||
this.logger.info(("listening on port " + this.port).underline.green);
|
||||
server.listen(this.port) ;
|
||||
this.logger.info("webserver available at " + ("http://" + this.hostname + ":" + this.port).bold.underline.green);
|
||||
server.listen(this.port, this.hostname) ;
|
||||
callback();
|
||||
};
|
||||
|
|
@ -1,17 +1,20 @@
|
|||
/*jshint esversion: 6 */
|
||||
var fs = require('fs');
|
||||
var chokidar = require('chokidar');
|
||||
|
||||
var fs = require('../core/fs.js');
|
||||
|
||||
// TODO: this should be receiving the config object not re-reading the
|
||||
// embark.json file
|
||||
var Watch = function(options) {
|
||||
this.logger = options.logger;
|
||||
this.events = {};
|
||||
this.events = options.events;
|
||||
};
|
||||
|
||||
Watch.prototype.start = function() {
|
||||
var self = this;
|
||||
// TODO: should come from the config object instead of reading the file
|
||||
// directly
|
||||
var embarkConfig = JSON.parse(fs.readFileSync("embark.json"));
|
||||
var embarkConfig = fs.readJSONSync("embark.json");
|
||||
|
||||
this.watchAssets(embarkConfig, function() {
|
||||
self.logger.trace('ready to watch asset changes');
|
||||
|
@ -25,7 +28,7 @@ Watch.prototype.start = function() {
|
|||
self.logger.trace('ready to watch config changes');
|
||||
});
|
||||
|
||||
this.logger.info("ready to watch changes");
|
||||
this.logger.info("ready to watch file changes");
|
||||
};
|
||||
|
||||
Watch.prototype.watchAssets = function(embarkConfig, callback) {
|
||||
|
@ -41,7 +44,8 @@ Watch.prototype.watchAssets = function(embarkConfig, callback) {
|
|||
filesToWatch,
|
||||
function(eventName, path) {
|
||||
self.logger.info(`${eventName}: ${path}`);
|
||||
self.trigger('rebuildAssets', path);
|
||||
self.events.emit('file-' + eventName, 'asset', path);
|
||||
self.events.emit('file-event', 'asset', path);
|
||||
},
|
||||
function() {
|
||||
callback();
|
||||
|
@ -55,7 +59,8 @@ Watch.prototype.watchContracts = function(embarkConfig, callback) {
|
|||
[embarkConfig.contracts],
|
||||
function(eventName, path) {
|
||||
self.logger.info(`${eventName}: ${path}`);
|
||||
self.trigger('redeploy', path);
|
||||
self.events.emit('file-' + eventName, 'contract', path);
|
||||
self.events.emit('file-event', 'contract', path);
|
||||
},
|
||||
function() {
|
||||
callback();
|
||||
|
@ -69,7 +74,8 @@ Watch.prototype.watchConfigs = function(callback) {
|
|||
"config/**/contracts.json",
|
||||
function(eventName, path) {
|
||||
self.logger.info(`${eventName}: ${path}`);
|
||||
self.trigger('redeploy', path);
|
||||
self.events.emit('file-' + eventName, 'config', path);
|
||||
self.events.emit('file-event', 'config', path);
|
||||
},
|
||||
function() {
|
||||
callback();
|
||||
|
@ -87,17 +93,9 @@ Watch.prototype.watchFiles = function(files, changeCallback, doneCallback) {
|
|||
|
||||
configWatcher
|
||||
.on('add', path => changeCallback('add', path))
|
||||
.on('change', path => changeCallback('add', path))
|
||||
.on('unlink', path => changeCallback('add', path))
|
||||
.on('change', path => changeCallback('change', path))
|
||||
.on('unlink', path => changeCallback('remove', path))
|
||||
.on('ready', doneCallback);
|
||||
};
|
||||
|
||||
Watch.prototype.on = function(eventName, callback) {
|
||||
this.events[eventName] = callback;
|
||||
};
|
||||
|
||||
Watch.prototype.trigger = function(eventName, values) {
|
||||
this.events[eventName](values);
|
||||
};
|
||||
|
||||
module.exports = Watch;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue