Merge branch 'develop'

This commit is contained in:
Iuri Matias 2017-06-28 06:56:51 -04:00
commit 10106067a7
81 changed files with 6676 additions and 5740 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ test_app/.embark/development/
test_app/config/production/password test_app/config/production/password
test_app/node_modules/ test_app/node_modules/
test_app/chains.json test_app/chains.json
.idea

View File

@ -1,8 +1,7 @@
language: node_js language: node_js
node_js: node_js:
- "7"
- "6" - "6"
- "5"
- "4"
addons: addons:
code_climate: code_climate:
repo_token: 7454b1a666015e244c384d19f48c34e35d1ae58c3aa428ec542f10bbcb848358 repo_token: 7454b1a666015e244c384d19f48c34e35d1ae58c3aa428ec542f10bbcb848358

92
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,92 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change.
Please note we have a code of conduct, please follow it in all your interactions with the project.
## Pull Request Process
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

29
Class Hierarchy.mmd Normal file
View File

@ -0,0 +1,29 @@
Mind Map generated by NB MindMap plugin
> __version__=`1.1`,showJumps=`true`
---
# Embark
## Config
## CLI
## Engine
> leftSide=`true`
### Plugins
#### DefaultLogger
#### DefaultPipeline
### Services
## DefaultLogger
## Utils
> leftSide=`true`
## DeployManager

View File

@ -21,8 +21,16 @@ module.exports = (grunt) ->
mochaTest: mochaTest:
test: test:
src: ['test/**/*.js'] src: ['test/**/*.js']
jshint: jshint:
all: ['bin/embark', 'lib/**/*.js', 'js/mine.js', 'js/embark.js'] all: ['bin/embark', 'lib/**/*.js']
options: grunt.file.readJSON('package.json').jshintConfig
with_overrides:
options:
undef: false
esversion: 5
files:
src: ['js/mine.js', 'js/embark.js']
grunt.loadTasks "tasks" grunt.loadTasks "tasks"
require('matchdep').filterAll(['grunt-*','!grunt-cli']).forEach(grunt.loadNpmTasks) require('matchdep').filterAll(['grunt-*','!grunt-cli']).forEach(grunt.loadNpmTasks)

View File

@ -1,4 +1,5 @@
[![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) [![npm](https://img.shields.io/npm/dm/embark.svg)]()
[![Gitter](https://img.shields.io/gitter/room/iurimatias/embark-framework.svg)]()
[![Build [![Build
Status](https://travis-ci.org/iurimatias/embark-framework.svg?branch=develop)](https://travis-ci.org/iurimatias/embark-framework) Status](https://travis-ci.org/iurimatias/embark-framework.svg?branch=develop)](https://travis-ci.org/iurimatias/embark-framework)
[![Code Climate](https://codeclimate.com/github/iurimatias/embark-framework/badges/gpa.svg)](https://codeclimate.com/github/iurimatias/embark-framework) [![Code Climate](https://codeclimate.com/github/iurimatias/embark-framework/badges/gpa.svg)](https://codeclimate.com/github/iurimatias/embark-framework)
@ -8,9 +9,9 @@ What is Embark
Embark is a framework that allows you to easily develop and deploy Decentralized Applications (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. A Decentralized Application is a 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. Embark currently integrates with EVM blockchains (Ethereum), Decentralized Storages (IPFS), and Decentralized communication platforms (Whisper and Orbit). Swarm is supported for deployment.
With Embark you can: With Embark you can:
@ -18,12 +19,12 @@ With Embark you can:
* 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. * 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.
* Contracts are available in JS with Promises. * Contracts are available in JS with Promises.
* Do Test Driven Development with Contracts using Javascript. * Do Test Driven Development with Contracts using Javascript.
* Keep track of deployed contracts, deploy only when truly needed. * Keep track of deployed contracts; deploy only when truly needed.
* Manage different chains (e.g testnet, private net, livenet) * Manage different chains (e.g testnet, private net, livenet)
* Easily manage complex systems of interdependent contracts. * Easily manage complex systems of interdependent contracts.
**Decentralized Storage (IPFS)** **Decentralized Storage (IPFS)**
* Easily Store & Retrieve Data on the DApp through EmbarkJS. Includin uploading and retrieving files. * Easily Store & Retrieve Data on the DApp through EmbarkJS. Including uploading and retrieving files.
* Deploy the full application to IPFS or Swarm. * Deploy the full application to IPFS or Swarm.
@ -41,20 +42,20 @@ Table of Contents
* [Dashboard](#dashboard) * [Dashboard](#dashboard)
* [Creating a new DApp](#creating-a-new-dapp) * [Creating a new DApp](#creating-a-new-dapp)
* [Libraries and APIs available](#libraries-and-languages-available) * [Libraries and APIs available](#libraries-and-languages-available)
* [Using and Configuring Contracts](#dapp-structure) * [Using and Configuring Contracts](#using-contracts)
* [EmbarkJS](#embarkjs) * [EmbarkJS](#embarkjs)
* [EmbarkJS - Storage (IPFS)](#embarkjs---storage) * [EmbarkJS - Storage (IPFS)](#embarkjs---storage)
* [EmbarkJS - Communication (Whisper/Orbit)](#embarkjs---communication) * [EmbarkJS - Communication (Whisper/Orbit)](#embarkjs---communication)
* [Testing Contracts](#tests) * [Testing Contracts](#tests)
* [Working with different chains](#working-with-different-chains) * [Working with different chains](#working-with-different-chains)
* [Custom Application Structure](#structuring-application) * [Custom Application Structure](#structuring-application)
* [Deploying to IPFS](#deploying-to-ipfs) * [Deploying to IPFS](#deploying-to-ipfs-and-swarm)
* [Extending Functionality with Plugins](#plugins) * [Extending Functionality with Plugins](#plugins)
* [Donations](#donations) * [Donations](#donations)
Installation Installation
====== ======
Requirements: geth (1.5.8 or higher), node (6.9.1 or higher is recommended) and npm Requirements: geth (1.6.5 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. 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/) Further: depending on the dapp stack you choose: [IPFS](https://ipfs.io/)
@ -68,7 +69,7 @@ $ npm -g install ethereumjs-testrpc
See [Complete Installation Instructions](https://github.com/iurimatias/embark-framework/wiki/Installation). See [Complete Installation Instructions](https://github.com/iurimatias/embark-framework/wiki/Installation).
**updating from embark 1** **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``` 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```
@ -96,7 +97,7 @@ Alternatively, to use an ethereum rpc simulator simply run:
$ embark simulator $ 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. By default Embark blockchain will mine a minimum amount of ether and will only mine when new transactions come in. This is quite useful 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: Then, in another command line:
@ -105,7 +106,7 @@ $ embark run
``` ```
This will automatically deploy the contracts, update their JS bindings and deploy your DApp to a local server at http://localhost:8000 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. 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.
Dashboard Dashboard
===== =====
@ -114,20 +115,20 @@ Embark 2 comes with a terminal dashboard.
![Dashboard](http://i.imgur.com/s4OQZpu.jpg) ![Dashboard](http://i.imgur.com/s4OQZpu.jpg)
The dashboard will tell you the state of your contracts, the enviroment you are using, and what embark is doing at the moment. The dashboard will tell you the state of your contracts, the environment you are using, and what Embark is doing at the moment.
**available services** **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. Available Services will display the services available to your dapp in green. If a service is down, then it will be displayed in red.
**logs and console** **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. 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.
Creating a new DApp Creating a new DApp
====== ======
If you want to create a blank new app. If you want to create a blank new app:
```Bash ```Bash
$ embark new AppName $ embark new AppName
@ -144,13 +145,16 @@ DApp Structure
|___ css/ |___ css/
|___ js/ |___ js/
config/ config/
|___ blockchain.json #environments configuration |___ blockchain.json #rpc and blockchain configuration
|___ contracts.json #contracts configuration |___ contracts.json #ethereum contracts configuration
|___ storage.json #ipfs configuration
|___ communication.json #whisper/orbit configuration
|___ webserver.json #dev webserver configuration
test/ test/
|___ #contracts tests |___ #contracts tests
``` ```
Solidity/Serpent 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 Solidity/Serpent 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
Libraries and languages available Libraries and languages available
====== ======
@ -223,7 +227,7 @@ If you are using multiple contracts, you can pass a reference to another contrac
"SimpleStorage": { "SimpleStorage": {
"args": [ "args": [
100, 100,
$MyStorage "$MyStorage"
] ]
}, },
"MyStorage": { "MyStorage": {
@ -233,7 +237,7 @@ If you are using multiple contracts, you can pass a reference to another contrac
}, },
"MyMainContract": { "MyMainContract": {
"args": [ "args": [
$SimpleStorage "$SimpleStorage"
] ]
} }
} }
@ -274,7 +278,7 @@ You can now deploy many instances of the same contract. e.g
... ...
``` ```
Contracts addresses can be defined, If an address is defined the contract wouldn't be deployed but its defined address will be used instead. Contracts addresses can be defined. If an address is defined, Embark uses the defined address instead of deploying the contract.
```Json ```Json
@ -322,14 +326,20 @@ events:
Client side deployment will be automatically available in Embark for existing contracts: Client side deployment will be automatically available in Embark for existing contracts:
```Javascript ```Javascript
SimpleStorage.deploy().then(function(anotherSimpleStorage) {}); SimpleStorage.deploy([args], {options}).then(function(anotherSimpleStorage) {});
``` ```
or it can be manually definied as or it can be manually definied as
```Javascript ```Javascript
var myContract = new EmbarkJS.Contract({abi: abiObject, code: code}); var myContract = new EmbarkJS.Contract({abi: abiObject, code: code});
myContract.deploy().then(function(anotherMyContractObject) {}); myContract.deploy([args], {options}).then(function(anotherMyContractObject) {});
```
so you can define your gas as
```Javascript
myContract.deploy([100, "seconde argument"], {gas: 800000}).then(function(anotherMyContractObject) {});
``` ```
EmbarkJS - Storage EmbarkJS - Storage
@ -337,7 +347,7 @@ EmbarkJS - Storage
**initialization** **initialization**
The current available storage is IPFS. it can be initialized as The current available storage is IPFS. It can be initialized as
```Javascript ```Javascript
EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'}) EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'})
@ -422,7 +432,7 @@ Tests
You can run specs with ```embark test```, it will run any test files under ```test/```. 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. Embark includes a testing lib to rapidly run & test your contracts in a EVM.
```Javascript ```Javascript
# test/simple_storage_spec.js # test/simple_storage_spec.js
@ -434,6 +444,7 @@ var web3 = EmbarkSpec.web3;
describe("SimpleStorage", function() { describe("SimpleStorage", function() {
before(function(done) { before(function(done) {
this.timeout(0);
var contractsConfig = { var contractsConfig = {
"SimpleStorage": { "SimpleStorage": {
args: [100] args: [100]
@ -459,6 +470,7 @@ describe("SimpleStorage", function() {
}); });
}); });
``` ```
Embark uses [Mocha](http://mochajs.org/) by default, but you can use any testing framework you want. Embark uses [Mocha](http://mochajs.org/) by default, but you can use any testing framework you want.
@ -521,20 +533,20 @@ To deploy a dapp to SWARM, all you need to do is run a local SWARM node and then
Plugins Plugins
====== ======
It's possible to extend Embarks functionality with plugins. For example the following is possible: It's possible to extend Embark's functionality with plugins. For example, the following is possible:
* plugin to add support for es6, jsx, coffescript, etc (``embark.registerPipeline``) * 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 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 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 add a libraries such as react or bootstrap (``embark.addFileToPipeline``)
* plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``) * plugin to specify a particular web3 initialization for special provider uses (``embark.registerClientWeb3Provider``)
* plugin to create a different contract wrapper (``embark.registerContractsGeneration``) * plugin to create a different contract wrapper (``embark.registerContractsGeneration``)
* plugin to add new console commands (``embark.registerConsoleCommand``) * plugin to add new console commands (``embark.registerConsoleCommand``)
* plugin to add support for another contract language such as viper, LLL, etc (``embark.registerCompiler``) * 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) For more information on how to develop your own plugin, please see the [plugin documentation](http://embark.readthedocs.io/en/latest/plugins.html)
Donations Donations
====== ======
If you like Embark please consider donating to 0x8811FdF0F988f0CD1B7E9DE252ABfA5b18c1cDb1 If you like Embark, please consider donating to 0x8811FdF0F988f0CD1B7E9DE252ABfA5b18c1cDb1

View File

@ -1,4 +1,4 @@
#!/usr/bin/env node #!/usr/bin/env node
var Cmd = require('../lib/cmd');
var Embark = require('..'); var cli = new Cmd();
Embark.process(process.argv); cli.process(process.argv);

View File

@ -6,6 +6,6 @@
</head> </head>
<body> <body>
<h3>Welcome to Embark!</h3> <h3>Welcome to Embark!</h3>
<p>See the <a href="https://github.com/iurimatias/embark-framework/wiki">Wiki</a> to see what you can do with Embark!</p> <p>See the <a href="http://embark.readthedocs.io/en/latest/index.html" target="_blank">Embark's documentation</a> to see what you can do with Embark!</p>
</body> </body>
</html> </html>

View File

@ -1,4 +1,5 @@
{ {
"config": {},
"nonce": "0x0000000000000042", "nonce": "0x0000000000000042",
"difficulty": "0x0", "difficulty": "0x0",
"alloc": { "alloc": {

View File

@ -9,7 +9,7 @@
"license": "ISC", "license": "ISC",
"homepage": "", "homepage": "",
"devDependencies": { "devDependencies": {
"embark": "^2.4.2", "embark": "^2.5.0",
"mocha": "^2.2.5" "mocha": "^2.2.5"
} }
} }

View File

@ -3,8 +3,9 @@ var Embark = require('embark');
var EmbarkSpec = Embark.initTests(); var EmbarkSpec = Embark.initTests();
var web3 = EmbarkSpec.web3; var web3 = EmbarkSpec.web3;
//describe("SimpleStorage", function() { // describe("SimpleStorage", function() {
// before(function(done) { // before(function(done) {
// this.timeout(0);
// var contractsConfig = { // var contractsConfig = {
// "SimpleStorage": { // "SimpleStorage": {
// args: [100, '0x123'] // args: [100, '0x123']
@ -29,4 +30,4 @@ var web3 = EmbarkSpec.web3;
// }); // });
// }); // });
// //
//}); // });

View File

@ -77,6 +77,7 @@
</div> </div>
<div role="tabpanel" class="tab-pane" id="communication"> <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 class="error alert alert-danger" role="alert">The node you are using does not support Whisper</div>
<div class="errorVersion alert alert-danger" role="alert">The node uses an unsupported version of Whisper</div>
<div id="communication-controls"> <div id="communication-controls">
<h3>Listen To channel</h3> <h3>Listen To channel</h3>
<div class="form-group form-inline listen"> <div class="form-group form-inline listen">

View File

@ -32,35 +32,55 @@ $(document).ready(function() {
//EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'}); //EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'});
$("#storage .error").hide(); $("#storage .error").hide();
EmbarkJS.Storage.ipfsConnection.ping() EmbarkJS.Storage.setProvider('ipfs')
.then(function(){ .then(function(){
$("#status-storage").addClass('status-online'); console.log('Provider set to IPFS');
$("#storage-controls").show(); 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();
}
});
}) })
.catch(function(err) { .catch(function(err){
if(err){ console.log('Failed to set IPFS as Provider:', err.message);
console.log("IPFS Connection Error => " + err.message); $("#storage .error").show();
$("#storage .error").show(); $("#status-storage").addClass('status-offline');
$("#status-storage").addClass('status-offline'); $("#storage-controls").hide();
$("#storage-controls").hide(); });
}
});
$("#storage button.setIpfsText").click(function() { $("#storage button.setIpfsText").click(function() {
var value = $("#storage input.ipfsText").val(); var value = $("#storage input.ipfsText").val();
EmbarkJS.Storage.saveText(value).then(function(hash) { EmbarkJS.Storage.saveText(value).then(function(hash) {
$("span.textHash").html(hash); $("span.textHash").html(hash);
$("input.textHash").val(hash); $("input.textHash").val(hash);
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS saveText Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
}); });
$("#storage button.loadIpfsHash").click(function() { $("#storage button.loadIpfsHash").click(function() {
var value = $("#storage input.textHash").val(); var value = $("#storage input.textHash").val();
EmbarkJS.Storage.get(value).then(function(content) { EmbarkJS.Storage.get(value).then(function(content) {
$("span.ipfsText").html(content); $("span.ipfsText").html(content);
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS get Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
}); });
$("#storage button.uploadFile").click(function() { $("#storage button.uploadFile").click(function() {
@ -68,8 +88,13 @@ $(document).ready(function() {
EmbarkJS.Storage.uploadFile(input).then(function(hash) { EmbarkJS.Storage.uploadFile(input).then(function(hash) {
$("span.fileIpfsHash").html(hash); $("span.fileIpfsHash").html(hash);
$("input.fileIpfsHash").val(hash); $("input.fileIpfsHash").val(hash);
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS uploadFile Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
}); });
$("#storage button.loadIpfsFile").click(function() { $("#storage button.loadIpfsFile").click(function() {
@ -89,11 +114,15 @@ $(document).ready(function() {
$(document).ready(function() { $(document).ready(function() {
$("#communication .error").hide(); $("#communication .error").hide();
web3.version.getWhisper(function(err, res) { web3.version.getWhisper(function(err, version) {
if (err) { if (err) {
$("#communication .error").show(); $("#communication .error").show();
$("#communication-controls").hide(); $("#communication-controls").hide();
+ $("#status-communication").addClass('status-offline'); $("#status-communication").addClass('status-offline');
} else if (version >= 5) {
$("#communication .errorVersion").show();
$("#communication-controls").hide();
$("#status-communication").addClass('status-offline');
} else { } else {
EmbarkJS.Messages.setProvider('whisper'); EmbarkJS.Messages.setProvider('whisper');
$("#status-communication").addClass('status-online'); $("#status-communication").addClass('status-online');

View File

@ -1,4 +1,5 @@
{ {
"config": {},
"nonce": "0x0000000000000042", "nonce": "0x0000000000000042",
"difficulty": "0x0", "difficulty": "0x0",
"alloc": { "alloc": {

View File

@ -10,7 +10,7 @@
"license": "ISC", "license": "ISC",
"homepage": "", "homepage": "",
"devDependencies": { "devDependencies": {
"embark": "^2.4.2", "embark": "^2.5.0",
"mocha": "^2.2.5" "mocha": "^2.2.5"
} }
} }

View File

@ -5,6 +5,7 @@ var web3 = EmbarkSpec.web3;
describe("SimpleStorage", function() { describe("SimpleStorage", function() {
before(function(done) { before(function(done) {
this.timeout(0);
var contractsConfig = { var contractsConfig = {
"SimpleStorage": { "SimpleStorage": {
args: [100] args: [100]

View File

@ -58,9 +58,9 @@ author = u'Iuri Matias'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = u'2.4' version = u'2.5'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = u'2.4.2' release = u'2.5.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -13,13 +13,25 @@ The current available storage is IPFS. it can be initialized as
.. code:: javascript .. code:: javascript
EmbarkJS.Storage.saveText("hello world").then(function(hash) {}); EmbarkJS.Storage.saveText("hello world")
.then(function(hash) {})
.catch(function(err) {
if(err){
console.log("IPFS saveText Error => " + err.message);
}
});
**Retrieving Data/Text** **Retrieving Data/Text**
.. code:: javascript .. code:: javascript
EmbarkJS.Storage.get(hash).then(function(content) {}); EmbarkJS.Storage.get(hash)
.then(function(content) {})
.catch(function(err) {
if(err){
console.log("IPFS get Error => " + err.message);
}
});
**Uploading a file** **Uploading a file**
@ -30,7 +42,13 @@ The current available storage is IPFS. it can be initialized as
.. code:: javascript .. code:: javascript
var input = $("input[type=file"]); var input = $("input[type=file"]);
EmbarkJS.Storage.uploadFile(input).then(function(hash) {}); EmbarkJS.Storage.uploadFile(input)
.then(function(hash) {})
.catch(function(err) {
if(err){
console.log("IPFS uploadFile Error => " + err.message);
}
});
**Generate URL to file** **Generate URL to file**

View File

@ -20,11 +20,17 @@ existing contracts:
.. code:: javascript .. code:: javascript
SimpleStorage.deploy().then(function(anotherSimpleStorage) {}); SimpleStorage.deploy([args], {options}).then(function(anotherSimpleStorage) {});
or it can be manually definied as or it can be manually definied as
.. code:: javascript .. code:: javascript
var myContract = new EmbarkJS.Contract({abi: abiObject, code: code}); var myContract = new EmbarkJS.Contract({abi: abiObject, code: code});
myContract.deploy().then(function(anotherMyContractObject) {}); myContract.deploy([args], {options}).then(function(anotherMyContractObject) {});
so you can define your gas as
.. code:: javascript
myContract.deploy([100, "seconde argument"], {gas: 800000}).then(function(anotherMyContractObject) {});

View File

@ -64,7 +64,7 @@ with the correct address for the contract.
"SimpleStorage": { "SimpleStorage": {
"args": [ "args": [
100, 100,
$MyStorage "$MyStorage"
] ]
}, },
"MyStorage": { "MyStorage": {
@ -74,7 +74,7 @@ with the correct address for the contract.
}, },
"MyMainContract": { "MyMainContract": {
"args": [ "args": [
$SimpleStorage "$SimpleStorage"
] ]
} }
} }

View File

@ -48,446 +48,530 @@ var EmbarkJS =
/*jshint esversion: 6 */ /*jshint esversion: 6 */
//var Ipfs = require('./ipfs.js'); //var Ipfs = require('./ipfs.js');
var EmbarkJS = { //=========================================================
}; // Embark Smart Contracts
//=========================================================
var EmbarkJS = {};
EmbarkJS.Contract = function(options) { EmbarkJS.Contract = function(options) {
var self = this; var self = this;
var i, abiElement; var i, abiElement;
this.abi = options.abi; this.abi = options.abi;
this.address = options.address; this.address = options.address;
this.code = '0x' + options.code; this.code = '0x' + options.code;
this.web3 = options.web3 || web3; this.web3 = options.web3 || web3;
var ContractClass = this.web3.eth.contract(this.abi); var ContractClass = this.web3.eth.contract(this.abi);
this.eventList = []; this.eventList = [];
if (this.abi) { if (this.abi) {
for (i = 0; i < this.abi.length; i++) { for (i = 0; i < this.abi.length; i++) {
abiElement = this.abi[i]; abiElement = this.abi[i];
if (abiElement.type === 'event') { if (abiElement.type === 'event') {
this.eventList.push(abiElement.name); this.eventList.push(abiElement.name);
}
}
}
var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
return err;
};
this._originalContractObject = ContractClass.at(this.address);
this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function (p) {
// TODO: check for forbidden properties
if (self.eventList.indexOf(p) >= 0) {
self[p] = function() {
var promise = new messageEvents();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, result) {
if (err) {
promise.error(err);
} else {
promise.cb(result);
}
});
self._originalContractObject[p].apply(self._originalContractObject[p], args);
return promise;
};
return true;
} else if (typeof self._originalContractObject[p] === 'function') {
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() { var messageEvents = function() {
self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) { this.cb = function() {};
if (err) { };
return reject(err);
}
if (receipt !== null) { messageEvents.prototype.then = function(cb) {
return resolve(receipt); this.cb = cb;
} };
setTimeout(getConfirmation, 1000); messageEvents.prototype.error = function(err) {
}); return err;
};
this._originalContractObject = ContractClass.at(this.address);
this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function(p) {
// TODO: check for forbidden properties
if (self.eventList.indexOf(p) >= 0) {
self[p] = function() {
var promise = new messageEvents();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, result) {
if (err) {
promise.error(err);
} else {
promise.cb(result);
}
});
self._originalContractObject[p].apply(self._originalContractObject[p], args);
return promise;
}; };
return true;
} else if (typeof self._originalContractObject[p] === 'function') {
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);
if (typeof(transaction) !== "string" || props.constant) { var promise = new Promise(function(resolve, reject) {
resolve(transaction); args.push(function(err, transaction) {
} else { promise.tx = transaction;
getConfirmation(); if (err) {
} return reject(err);
}); }
fn.apply(fn, args); var getConfirmation = function() {
}); self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) {
if (err) {
return reject(err);
}
return promise; if (receipt !== null) {
}; return resolve(receipt);
return true; }
}
return false; 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, _options) { EmbarkJS.Contract.prototype.deploy = function(args, _options) {
var self = this; var self = this;
var contractParams; var contractParams;
var options = _options || {}; var options = _options || {};
contractParams = args || []; contractParams = args || [];
contractParams.push({ contractParams.push({
from: this.web3.eth.accounts[0], from: this.web3.eth.accounts[0],
data: this.code, data: this.code,
gas: options.gas || 800000 gas: options.gas || 800000
});
var contractObject = this.web3.eth.contract(this.abi);
var promise = new Promise(function(resolve, reject) {
contractParams.push(function(err, transaction) {
if (err) {
reject(err);
} else if (transaction.address !== undefined) {
resolve(new EmbarkJS.Contract({abi: self.abi, code: self.code, address: transaction.address}));
}
}); });
// returns promise var contractObject = this.web3.eth.contract(this.abi);
// deploys contract
// wraps it around EmbarkJS.Contract
contractObject["new"].apply(contractObject, contractParams);
});
var promise = new Promise(function(resolve, reject) {
return promise; contractParams.push(function(err, transaction) {
if (err) {
reject(err);
} else if (transaction.address !== undefined) {
resolve(new EmbarkJS.Contract({
abi: self.abi,
code: self.code,
address: transaction.address
}));
}
});
// returns promise
// deploys contract
// wraps it around EmbarkJS.Contract
contractObject["new"].apply(contractObject, contractParams);
});
return promise;
}; };
EmbarkJS.IPFS = 'ipfs'; EmbarkJS.Contract.prototype.new = EmbarkJS.Contract.prototype.deploy;
EmbarkJS.Storage = { EmbarkJS.Contract.prototype.at = function(address) {
return new EmbarkJS.Contract({ abi: this.abi, code: this.code, address: address });
}; };
EmbarkJS.Storage.setProvider = function(provider, options) { EmbarkJS.Contract.prototype.send = function(value, unit, _options) {
if (provider === 'ipfs') { var options, wei;
this.currentStorage = EmbarkJS.Storage.IPFS; if (typeof unit === 'object') {
if (options === undefined) { options = unit;
this.ipfsConnection = IpfsApi('localhost', '5001'); wei = value;
} else {
this.ipfsConnection = IpfsApi(options.server, options.port);
}
} else { } else {
throw Error('unknown provider'); options = _options || {};
wei = this.web3.toWei(value, unit);
} }
options.to = this.address;
options.value = wei;
console.log(options);
this.web3.eth.sendTransaction(options);
}; };
//=========================================================
// Embark Storage
//=========================================================
EmbarkJS.Storage = {};
EmbarkJS.Storage.Providers = {
IPFS: 'ipfs',
SWARM: 'swarm'
};
EmbarkJS.Storage.IPFS = {};
EmbarkJS.Storage.saveText = function(text) { EmbarkJS.Storage.saveText = function(text) {
var self = this; return this.currentStorage.saveText(text);
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) {
reject(err);
} else {
resolve(result[0].path);
}
});
});
return promise;
};
EmbarkJS.Storage.uploadFile = function(inputSelector) {
var self = this;
var file = inputSelector[0].files[0];
if (file === undefined) {
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() {
var fileContent = reader.result;
var buffer = self.ipfsConnection.Buffer.from(fileContent);
self.ipfsConnection.add(buffer, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
};
reader.readAsArrayBuffer(file);
});
return promise;
}; };
EmbarkJS.Storage.get = function(hash) { EmbarkJS.Storage.get = function(hash) {
var self = this; return this.currentStorage.get(hash);
// 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) { EmbarkJS.Storage.uploadFile = function(inputSelector) {
self.ipfsConnection.object.get([hash]).then(function(node) { return this.currentStorage.uploadFile(inputSelector);
resolve(node.data);
});
});
return promise;
}; };
EmbarkJS.Storage.getUrl = function(hash) { EmbarkJS.Storage.getUrl = function(hash) {
//var ipfsHash = web3.toAscii(hash); return this.currentStorage.getUrl(hash);
return 'http://localhost:8080/ipfs/' + hash;
}; };
EmbarkJS.Messages = { EmbarkJS.Storage.setProvider = function(provider, options) {
var self = this;
var promise = new Promise(function(resolve, reject) {
if (provider.toLowerCase() === EmbarkJS.Storage.Providers.IPFS) {
//I don't think currentStorage is used anywhere, this might not be needed
//for now until additional storage providers are supported. But keeping it
//anyways
self.currentStorage = EmbarkJS.Storage.IPFS;
try {
if (options === undefined) {
self.ipfsConnection = IpfsApi('localhost', '5001');
} else {
self.ipfsConnection = IpfsApi(options.server, options.port);
}
resolve(self);
} catch (err) {
self.ipfsConnection = null;
reject(new Error('Failed to connect to IPFS'));
}
} else if (provider.toLowerCase() === EmbarkJS.Storage.SWARM) {
reject('Swarm not implemented');
// TODO Implement Swarm
// this.currentStorage = EmbarkJS.Storage.SWARM;
// if (options === undefined) {
// //Connect to default Swarm node
// } else {
// //Connect using options
// }
} else {
reject('Unknown storage provider');
}
});
return promise;
}; };
EmbarkJS.Storage.IPFS.saveText = function(text) {
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
EmbarkJS.Storage.ipfsConnection.add((new EmbarkJS.Storage.ipfsConnection.Buffer(text)), function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
});
return promise;
};
EmbarkJS.Storage.IPFS.get = function(hash) {
// TODO: detect type, then convert if needed
//var ipfsHash = web3.toAscii(hash);
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
EmbarkJS.Storage.ipfsConnection.object.get([hash]).then(function(node) {
resolve(node.data);
}).catch(function(err) {
reject(err);
});
});
return promise;
};
EmbarkJS.Storage.IPFS.uploadFile = function(inputSelector) {
var file = inputSelector[0].files[0];
if (file === undefined) {
throw new Error('no file found');
}
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
var reader = new FileReader();
reader.onloadend = function() {
var fileContent = reader.result;
var buffer = EmbarkJS.Storage.ipfsConnection.Buffer.from(fileContent);
EmbarkJS.Storage.ipfsConnection.add(buffer, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
};
reader.readAsArrayBuffer(file);
});
return promise;
};
EmbarkJS.Storage.IPFS.getUrl = function(hash) {
//var ipfsHash = web3.toAscii(hash);
return 'http://localhost:8080/ipfs/' + hash;
};
//=========================================================
// Embark Messaging
//=========================================================
EmbarkJS.Messages = {};
EmbarkJS.Messages.setProvider = function(provider, options) { EmbarkJS.Messages.setProvider = function(provider, options) {
var self = this; var self = this;
var ipfs; var ipfs;
if (provider === 'whisper') { if (provider === 'whisper') {
this.currentMessages = EmbarkJS.Messages.Whisper; this.currentMessages = EmbarkJS.Messages.Whisper;
if (typeof variable === 'undefined' && typeof(web3) === 'undefined') { if (typeof variable === 'undefined' && typeof(web3) === 'undefined') {
if (options === undefined) { if (options === undefined) {
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
} else { } else {
web3 = new Web3(new Web3.providers.HttpProvider("http://" + options.server + ':' + options.port)); web3 = new Web3(new Web3.providers.HttpProvider("http://" + options.server + ':' + options.port));
} }
} }
web3.version.getWhisper(function(err, res) { web3.version.getWhisper(function(err, res) {
if (err) { if (err) {
console.log("whisper not available"); console.log("whisper not available");
} else { } else if (web3.version.whisper >= 5) {
self.currentMessages.identity = web3.shh.newIdentity(); console.log("this version of whisper is not supported yet; try a version of geth bellow 1.6.1");
} } else {
}); self.currentMessages.identity = web3.shh.newIdentity();
} else if (provider === 'orbit') { }
this.currentMessages = EmbarkJS.Messages.Orbit; });
if (options === undefined) { } else if (provider === 'orbit') {
ipfs = HaadIpfsApi('localhost', '5001'); this.currentMessages = EmbarkJS.Messages.Orbit;
if (options === undefined) {
ipfs = HaadIpfsApi('localhost', '5001');
} else {
ipfs = HaadIpfsApi(options.host, options.port);
}
this.currentMessages.orbit = new Orbit(ipfs);
if (typeof(web3) === "undefined") {
this.currentMessages.orbit.connect(Math.random().toString(36).substring(2));
} else {
this.currentMessages.orbit.connect(web3.eth.accounts[0]);
}
} else { } else {
ipfs = HaadIpfsApi(options.server, options.port); throw Error('Unknown message provider');
} }
this.currentMessages.orbit = new Orbit(ipfs);
this.currentMessages.orbit.connect(web3.eth.accounts[0]);
} else {
throw Error('unknown provider');
}
}; };
EmbarkJS.Messages.sendMessage = function(options) { EmbarkJS.Messages.sendMessage = function(options) {
return this.currentMessages.sendMessage(options); return this.currentMessages.sendMessage(options);
}; };
EmbarkJS.Messages.listenTo = function(options) { EmbarkJS.Messages.listenTo = function(options) {
return this.currentMessages.listenTo(options); return this.currentMessages.listenTo(options);
}; };
EmbarkJS.Messages.Whisper = { EmbarkJS.Messages.Whisper = {};
};
EmbarkJS.Messages.Whisper.sendMessage = function(options) { EmbarkJS.Messages.Whisper.sendMessage = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var data = options.data || options.payload; var data = options.data || options.payload;
var identity = options.identity || this.identity || web3.shh.newIdentity(); var identity = options.identity || this.identity || web3.shh.newIdentity();
var ttl = options.ttl || 100; var ttl = options.ttl || 100;
var priority = options.priority || 1000; var priority = options.priority || 1000;
var _topics; var _topics;
if (topics === undefined) { if (topics === undefined) {
throw new Error("missing option: topic"); throw new Error("missing option: topic");
}
if (data === undefined) {
throw new Error("missing option: data");
}
// do fromAscii to each topics unless it's already a string
if (typeof topics === 'string') {
_topics = [web3.fromAscii(topics)];
} else {
// TODO: replace with es6 + babel;
for (var i = 0; i < topics.length; i++) {
_topics.push(web3.fromAscii(topics[i]));
} }
}
topics = _topics;
var payload = JSON.stringify(data); if (data === undefined) {
throw new Error("missing option: data");
}
var message = { // do fromAscii to each topics unless it's already a string
from: identity, if (typeof topics === 'string') {
topics: topics, _topics = [web3.fromAscii(topics)];
payload: web3.fromAscii(payload), } else {
ttl: ttl, // TODO: replace with es6 + babel;
priority: priority for (var i = 0; i < topics.length; i++) {
}; _topics.push(web3.fromAscii(topics[i]));
}
}
topics = _topics;
return web3.shh.post(message, function() {}); var payload = JSON.stringify(data);
var message = {
from: identity,
topics: topics,
payload: web3.fromAscii(payload),
ttl: ttl,
priority: priority
};
return web3.shh.post(message, function() {});
}; };
EmbarkJS.Messages.Whisper.listenTo = function(options) { EmbarkJS.Messages.Whisper.listenTo = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var _topics = []; var _topics = [];
if (typeof topics === 'string') { if (typeof topics === 'string') {
_topics = [topics]; _topics = [topics];
} else {
// TODO: replace with es6 + babel;
for (var i = 0; i < topics.length; i++) {
_topics.push(topics[i]);
}
}
topics = _topics;
var filterOptions = {
topics: topics
};
var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
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 { } else {
data = { // TODO: replace with es6 + babel;
topic: topics, for (var i = 0; i < topics.length; i++) {
data: payload, _topics.push(topics[i]);
from: result.from, }
time: (new Date(result.sent * 1000))
};
promise.cb(payload, data, result);
} }
}); topics = _topics;
promise.filter = filter; var filterOptions = {
topics: topics
};
return promise; var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
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 {
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 = {};
};
EmbarkJS.Messages.Orbit.sendMessage = function(options) { EmbarkJS.Messages.Orbit.sendMessage = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var data = options.data || options.payload; var data = options.data || options.payload;
if (topics === undefined) { if (topics === undefined) {
throw new Error("missing option: topic"); throw new Error("missing option: topic");
} }
if (data === undefined) { if (data === undefined) {
throw new Error("missing option: data"); throw new Error("missing option: data");
} }
if (typeof topics === 'string') { if (typeof topics === 'string') {
topics = topics; topics = topics;
} else { } else {
// TODO: better to just send to different channels instead // TODO: better to just send to different channels instead
topics = topics.join(','); topics = topics.join(',');
} }
this.orbit.join(topics); this.orbit.join(topics);
var payload = JSON.stringify(data); var payload = JSON.stringify(data);
this.orbit.send(topics, data); this.orbit.send(topics, data);
}; };
EmbarkJS.Messages.Orbit.listenTo = function(options) { EmbarkJS.Messages.Orbit.listenTo = function(options) {
var self = this; var self = this;
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
if (typeof topics === 'string') { if (typeof topics === 'string') {
topics = topics; topics = topics;
} else { } else {
topics = topics.join(','); topics = topics.join(',');
} }
this.orbit.join(topics); this.orbit.join(topics);
var messageEvents = function() { var messageEvents = function() {
this.cb = function() {}; this.cb = function() {};
}; };
messageEvents.prototype.then = function(cb) { messageEvents.prototype.then = function(cb) {
this.cb = cb; this.cb = cb;
}; };
messageEvents.prototype.error = function(err) { messageEvents.prototype.error = function(err) {
return err; return err;
}; };
var promise = new messageEvents(); var promise = new messageEvents();
this.orbit.events.on('message', (channel, message) => { this.orbit.events.on('message', (channel, message) => {
// TODO: looks like sometimes it's receving messages from all topics // TODO: looks like sometimes it's receving messages from all topics
if (topics !== channel) return; if (topics !== channel) return;
self.orbit.getPost(message.payload.value, true).then((post) => { self.orbit.getPost(message.payload.value, true).then((post) => {
var data = { var data = {
topic: channel, topic: channel,
data: post.content, data: post.content,
from: post.meta.from.name, from: post.meta.from.name,
time: (new Date(post.meta.ts)) time: (new Date(post.meta.ts))
}; };
promise.cb(post.content, data, post); promise.cb(post.content, data, post);
});
}); });
});
return promise; return promise;
}; };
module.exports = EmbarkJS; module.exports = EmbarkJS;

View File

@ -1,446 +1,530 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
//var Ipfs = require('./ipfs.js'); //var Ipfs = require('./ipfs.js');
var EmbarkJS = { //=========================================================
}; // Embark Smart Contracts
//=========================================================
var EmbarkJS = {};
EmbarkJS.Contract = function(options) { EmbarkJS.Contract = function(options) {
var self = this; var self = this;
var i, abiElement; var i, abiElement;
this.abi = options.abi; this.abi = options.abi;
this.address = options.address; this.address = options.address;
this.code = '0x' + options.code; this.code = '0x' + options.code;
this.web3 = options.web3 || web3; this.web3 = options.web3 || web3;
var ContractClass = this.web3.eth.contract(this.abi); var ContractClass = this.web3.eth.contract(this.abi);
this.eventList = []; this.eventList = [];
if (this.abi) { if (this.abi) {
for (i = 0; i < this.abi.length; i++) { for (i = 0; i < this.abi.length; i++) {
abiElement = this.abi[i]; abiElement = this.abi[i];
if (abiElement.type === 'event') { if (abiElement.type === 'event') {
this.eventList.push(abiElement.name); this.eventList.push(abiElement.name);
}
}
}
var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
return err;
};
this._originalContractObject = ContractClass.at(this.address);
this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function (p) {
// TODO: check for forbidden properties
if (self.eventList.indexOf(p) >= 0) {
self[p] = function() {
var promise = new messageEvents();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, result) {
if (err) {
promise.error(err);
} else {
promise.cb(result);
}
});
self._originalContractObject[p].apply(self._originalContractObject[p], args);
return promise;
};
return true;
} else if (typeof self._originalContractObject[p] === 'function') {
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() { var messageEvents = function() {
self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) { this.cb = function() {};
if (err) { };
return reject(err);
}
if (receipt !== null) { messageEvents.prototype.then = function(cb) {
return resolve(receipt); this.cb = cb;
} };
setTimeout(getConfirmation, 1000); messageEvents.prototype.error = function(err) {
}); return err;
};
this._originalContractObject = ContractClass.at(this.address);
this._methods = Object.getOwnPropertyNames(this._originalContractObject).filter(function(p) {
// TODO: check for forbidden properties
if (self.eventList.indexOf(p) >= 0) {
self[p] = function() {
var promise = new messageEvents();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, result) {
if (err) {
promise.error(err);
} else {
promise.cb(result);
}
});
self._originalContractObject[p].apply(self._originalContractObject[p], args);
return promise;
}; };
return true;
} else if (typeof self._originalContractObject[p] === 'function') {
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);
if (typeof(transaction) !== "string" || props.constant) { var promise = new Promise(function(resolve, reject) {
resolve(transaction); args.push(function(err, transaction) {
} else { promise.tx = transaction;
getConfirmation(); if (err) {
} return reject(err);
}); }
fn.apply(fn, args); var getConfirmation = function() {
}); self.web3.eth.getTransactionReceipt(transaction, function(err, receipt) {
if (err) {
return reject(err);
}
return promise; if (receipt !== null) {
}; return resolve(receipt);
return true; }
}
return false; 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, _options) { EmbarkJS.Contract.prototype.deploy = function(args, _options) {
var self = this; var self = this;
var contractParams; var contractParams;
var options = _options || {}; var options = _options || {};
contractParams = args || []; contractParams = args || [];
contractParams.push({ contractParams.push({
from: this.web3.eth.accounts[0], from: this.web3.eth.accounts[0],
data: this.code, data: this.code,
gas: options.gas || 800000 gas: options.gas || 800000
});
var contractObject = this.web3.eth.contract(this.abi);
var promise = new Promise(function(resolve, reject) {
contractParams.push(function(err, transaction) {
if (err) {
reject(err);
} else if (transaction.address !== undefined) {
resolve(new EmbarkJS.Contract({abi: self.abi, code: self.code, address: transaction.address}));
}
}); });
// returns promise var contractObject = this.web3.eth.contract(this.abi);
// deploys contract
// wraps it around EmbarkJS.Contract
contractObject["new"].apply(contractObject, contractParams);
});
var promise = new Promise(function(resolve, reject) {
return promise; contractParams.push(function(err, transaction) {
if (err) {
reject(err);
} else if (transaction.address !== undefined) {
resolve(new EmbarkJS.Contract({
abi: self.abi,
code: self.code,
address: transaction.address
}));
}
});
// returns promise
// deploys contract
// wraps it around EmbarkJS.Contract
contractObject["new"].apply(contractObject, contractParams);
});
return promise;
}; };
EmbarkJS.IPFS = 'ipfs'; EmbarkJS.Contract.prototype.new = EmbarkJS.Contract.prototype.deploy;
EmbarkJS.Storage = { EmbarkJS.Contract.prototype.at = function(address) {
return new EmbarkJS.Contract({ abi: this.abi, code: this.code, address: address });
}; };
EmbarkJS.Storage.setProvider = function(provider, options) { EmbarkJS.Contract.prototype.send = function(value, unit, _options) {
if (provider === 'ipfs') { var options, wei;
this.currentStorage = EmbarkJS.Storage.IPFS; if (typeof unit === 'object') {
if (options === undefined) { options = unit;
this.ipfsConnection = IpfsApi('localhost', '5001'); wei = value;
} else {
this.ipfsConnection = IpfsApi(options.server, options.port);
}
} else { } else {
throw Error('unknown provider'); options = _options || {};
wei = this.web3.toWei(value, unit);
} }
options.to = this.address;
options.value = wei;
console.log(options);
this.web3.eth.sendTransaction(options);
}; };
//=========================================================
// Embark Storage
//=========================================================
EmbarkJS.Storage = {};
EmbarkJS.Storage.Providers = {
IPFS: 'ipfs',
SWARM: 'swarm'
};
EmbarkJS.Storage.IPFS = {};
EmbarkJS.Storage.saveText = function(text) { EmbarkJS.Storage.saveText = function(text) {
var self = this; return this.currentStorage.saveText(text);
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) {
reject(err);
} else {
resolve(result[0].path);
}
});
});
return promise;
};
EmbarkJS.Storage.uploadFile = function(inputSelector) {
var self = this;
var file = inputSelector[0].files[0];
if (file === undefined) {
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() {
var fileContent = reader.result;
var buffer = self.ipfsConnection.Buffer.from(fileContent);
self.ipfsConnection.add(buffer, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
};
reader.readAsArrayBuffer(file);
});
return promise;
}; };
EmbarkJS.Storage.get = function(hash) { EmbarkJS.Storage.get = function(hash) {
var self = this; return this.currentStorage.get(hash);
// 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) { EmbarkJS.Storage.uploadFile = function(inputSelector) {
self.ipfsConnection.object.get([hash]).then(function(node) { return this.currentStorage.uploadFile(inputSelector);
resolve(node.data);
});
});
return promise;
}; };
EmbarkJS.Storage.getUrl = function(hash) { EmbarkJS.Storage.getUrl = function(hash) {
//var ipfsHash = web3.toAscii(hash); return this.currentStorage.getUrl(hash);
return 'http://localhost:8080/ipfs/' + hash;
}; };
EmbarkJS.Messages = { EmbarkJS.Storage.setProvider = function(provider, options) {
var self = this;
var promise = new Promise(function(resolve, reject) {
if (provider.toLowerCase() === EmbarkJS.Storage.Providers.IPFS) {
//I don't think currentStorage is used anywhere, this might not be needed
//for now until additional storage providers are supported. But keeping it
//anyways
self.currentStorage = EmbarkJS.Storage.IPFS;
try {
if (options === undefined) {
self.ipfsConnection = IpfsApi('localhost', '5001');
} else {
self.ipfsConnection = IpfsApi(options.server, options.port);
}
resolve(self);
} catch (err) {
self.ipfsConnection = null;
reject(new Error('Failed to connect to IPFS'));
}
} else if (provider.toLowerCase() === EmbarkJS.Storage.SWARM) {
reject('Swarm not implemented');
// TODO Implement Swarm
// this.currentStorage = EmbarkJS.Storage.SWARM;
// if (options === undefined) {
// //Connect to default Swarm node
// } else {
// //Connect using options
// }
} else {
reject('Unknown storage provider');
}
});
return promise;
}; };
EmbarkJS.Storage.IPFS.saveText = function(text) {
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
EmbarkJS.Storage.ipfsConnection.add((new EmbarkJS.Storage.ipfsConnection.Buffer(text)), function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
});
return promise;
};
EmbarkJS.Storage.IPFS.get = function(hash) {
// TODO: detect type, then convert if needed
//var ipfsHash = web3.toAscii(hash);
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
EmbarkJS.Storage.ipfsConnection.object.get([hash]).then(function(node) {
resolve(node.data);
}).catch(function(err) {
reject(err);
});
});
return promise;
};
EmbarkJS.Storage.IPFS.uploadFile = function(inputSelector) {
var file = inputSelector[0].files[0];
if (file === undefined) {
throw new Error('no file found');
}
var promise = new Promise(function(resolve, reject) {
if (!EmbarkJS.Storage.ipfsConnection) {
var connectionError = new Error('No IPFS connection. Please ensure to call Embark.Storage.setProvider()');
reject(connectionError);
}
var reader = new FileReader();
reader.onloadend = function() {
var fileContent = reader.result;
var buffer = EmbarkJS.Storage.ipfsConnection.Buffer.from(fileContent);
EmbarkJS.Storage.ipfsConnection.add(buffer, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result[0].path);
}
});
};
reader.readAsArrayBuffer(file);
});
return promise;
};
EmbarkJS.Storage.IPFS.getUrl = function(hash) {
//var ipfsHash = web3.toAscii(hash);
return 'http://localhost:8080/ipfs/' + hash;
};
//=========================================================
// Embark Messaging
//=========================================================
EmbarkJS.Messages = {};
EmbarkJS.Messages.setProvider = function(provider, options) { EmbarkJS.Messages.setProvider = function(provider, options) {
var self = this; var self = this;
var ipfs; var ipfs;
if (provider === 'whisper') { if (provider === 'whisper') {
this.currentMessages = EmbarkJS.Messages.Whisper; this.currentMessages = EmbarkJS.Messages.Whisper;
if (typeof variable === 'undefined' && typeof(web3) === 'undefined') { if (typeof variable === 'undefined' && typeof(web3) === 'undefined') {
if (options === undefined) { if (options === undefined) {
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
} else { } else {
web3 = new Web3(new Web3.providers.HttpProvider("http://" + options.server + ':' + options.port)); web3 = new Web3(new Web3.providers.HttpProvider("http://" + options.server + ':' + options.port));
} }
} }
web3.version.getWhisper(function(err, res) { web3.version.getWhisper(function(err, res) {
if (err) { if (err) {
console.log("whisper not available"); console.log("whisper not available");
} else { } else if (web3.version.whisper >= 5) {
self.currentMessages.identity = web3.shh.newIdentity(); console.log("this version of whisper is not supported yet; try a version of geth bellow 1.6.1");
} } else {
}); self.currentMessages.identity = web3.shh.newIdentity();
} else if (provider === 'orbit') { }
this.currentMessages = EmbarkJS.Messages.Orbit; });
if (options === undefined) { } else if (provider === 'orbit') {
ipfs = HaadIpfsApi('localhost', '5001'); this.currentMessages = EmbarkJS.Messages.Orbit;
if (options === undefined) {
ipfs = HaadIpfsApi('localhost', '5001');
} else {
ipfs = HaadIpfsApi(options.host, options.port);
}
this.currentMessages.orbit = new Orbit(ipfs);
if (typeof(web3) === "undefined") {
this.currentMessages.orbit.connect(Math.random().toString(36).substring(2));
} else {
this.currentMessages.orbit.connect(web3.eth.accounts[0]);
}
} else { } else {
ipfs = HaadIpfsApi(options.server, options.port); throw Error('Unknown message provider');
} }
this.currentMessages.orbit = new Orbit(ipfs);
this.currentMessages.orbit.connect(web3.eth.accounts[0]);
} else {
throw Error('unknown provider');
}
}; };
EmbarkJS.Messages.sendMessage = function(options) { EmbarkJS.Messages.sendMessage = function(options) {
return this.currentMessages.sendMessage(options); return this.currentMessages.sendMessage(options);
}; };
EmbarkJS.Messages.listenTo = function(options) { EmbarkJS.Messages.listenTo = function(options) {
return this.currentMessages.listenTo(options); return this.currentMessages.listenTo(options);
}; };
EmbarkJS.Messages.Whisper = { EmbarkJS.Messages.Whisper = {};
};
EmbarkJS.Messages.Whisper.sendMessage = function(options) { EmbarkJS.Messages.Whisper.sendMessage = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var data = options.data || options.payload; var data = options.data || options.payload;
var identity = options.identity || this.identity || web3.shh.newIdentity(); var identity = options.identity || this.identity || web3.shh.newIdentity();
var ttl = options.ttl || 100; var ttl = options.ttl || 100;
var priority = options.priority || 1000; var priority = options.priority || 1000;
var _topics; var _topics;
if (topics === undefined) { if (topics === undefined) {
throw new Error("missing option: topic"); throw new Error("missing option: topic");
}
if (data === undefined) {
throw new Error("missing option: data");
}
// do fromAscii to each topics unless it's already a string
if (typeof topics === 'string') {
_topics = [web3.fromAscii(topics)];
} else {
// TODO: replace with es6 + babel;
for (var i = 0; i < topics.length; i++) {
_topics.push(web3.fromAscii(topics[i]));
} }
}
topics = _topics;
var payload = JSON.stringify(data); if (data === undefined) {
throw new Error("missing option: data");
}
var message = { // do fromAscii to each topics unless it's already a string
from: identity, if (typeof topics === 'string') {
topics: topics, _topics = [web3.fromAscii(topics)];
payload: web3.fromAscii(payload), } else {
ttl: ttl, // TODO: replace with es6 + babel;
priority: priority for (var i = 0; i < topics.length; i++) {
}; _topics.push(web3.fromAscii(topics[i]));
}
}
topics = _topics;
return web3.shh.post(message, function() {}); var payload = JSON.stringify(data);
var message = {
from: identity,
topics: topics,
payload: web3.fromAscii(payload),
ttl: ttl,
priority: priority
};
return web3.shh.post(message, function() {});
}; };
EmbarkJS.Messages.Whisper.listenTo = function(options) { EmbarkJS.Messages.Whisper.listenTo = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var _topics = []; var _topics = [];
if (typeof topics === 'string') { if (typeof topics === 'string') {
_topics = [topics]; _topics = [topics];
} else {
// TODO: replace with es6 + babel;
for (var i = 0; i < topics.length; i++) {
_topics.push(topics[i]);
}
}
topics = _topics;
var filterOptions = {
topics: topics
};
var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
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 { } else {
data = { // TODO: replace with es6 + babel;
topic: topics, for (var i = 0; i < topics.length; i++) {
data: payload, _topics.push(topics[i]);
from: result.from, }
time: (new Date(result.sent * 1000))
};
promise.cb(payload, data, result);
} }
}); topics = _topics;
promise.filter = filter; var filterOptions = {
topics: topics
};
return promise; var messageEvents = function() {
this.cb = function() {};
};
messageEvents.prototype.then = function(cb) {
this.cb = cb;
};
messageEvents.prototype.error = function(err) {
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 {
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 = {};
};
EmbarkJS.Messages.Orbit.sendMessage = function(options) { EmbarkJS.Messages.Orbit.sendMessage = function(options) {
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
var data = options.data || options.payload; var data = options.data || options.payload;
if (topics === undefined) { if (topics === undefined) {
throw new Error("missing option: topic"); throw new Error("missing option: topic");
} }
if (data === undefined) { if (data === undefined) {
throw new Error("missing option: data"); throw new Error("missing option: data");
} }
if (typeof topics === 'string') { if (typeof topics === 'string') {
topics = topics; topics = topics;
} else { } else {
// TODO: better to just send to different channels instead // TODO: better to just send to different channels instead
topics = topics.join(','); topics = topics.join(',');
} }
this.orbit.join(topics); this.orbit.join(topics);
var payload = JSON.stringify(data); var payload = JSON.stringify(data);
this.orbit.send(topics, data); this.orbit.send(topics, data);
}; };
EmbarkJS.Messages.Orbit.listenTo = function(options) { EmbarkJS.Messages.Orbit.listenTo = function(options) {
var self = this; var self = this;
var topics = options.topic || options.topics; var topics = options.topic || options.topics;
if (typeof topics === 'string') { if (typeof topics === 'string') {
topics = topics; topics = topics;
} else { } else {
topics = topics.join(','); topics = topics.join(',');
} }
this.orbit.join(topics); this.orbit.join(topics);
var messageEvents = function() { var messageEvents = function() {
this.cb = function() {}; this.cb = function() {};
}; };
messageEvents.prototype.then = function(cb) { messageEvents.prototype.then = function(cb) {
this.cb = cb; this.cb = cb;
}; };
messageEvents.prototype.error = function(err) { messageEvents.prototype.error = function(err) {
return err; return err;
}; };
var promise = new messageEvents(); var promise = new messageEvents();
this.orbit.events.on('message', (channel, message) => { this.orbit.events.on('message', (channel, message) => {
// TODO: looks like sometimes it's receving messages from all topics // TODO: looks like sometimes it's receving messages from all topics
if (topics !== channel) return; if (topics !== channel) return;
self.orbit.getPost(message.payload.value, true).then((post) => { self.orbit.getPost(message.payload.value, true).then((post) => {
var data = { var data = {
topic: channel, topic: channel,
data: post.content, data: post.content,
from: post.meta.from.name, from: post.meta.from.name,
time: (new Date(post.meta.ts)) time: (new Date(post.meta.ts))
}; };
promise.cb(post.content, data, post); promise.cb(post.content, data, post);
});
}); });
});
return promise; return promise;
}; };
module.exports = EmbarkJS; module.exports = EmbarkJS;

5636
js/web3.js

File diff suppressed because it is too large Load Diff

View File

@ -1,150 +1,170 @@
var program = require('commander'); let program = require('commander');
var colors = require('colors'); let colors = require('colors');
var shelljs = require('shelljs'); let shelljs = require('shelljs');
let promptly = require('promptly');
let path = require('path');
const Embark = require('../lib/index');
let embark = new Embark;
var Cmd = function(Embark) { class Cmd {
this.Embark = Embark; constructor() {
program.version(Embark.version); program.version(embark.version);
};
Cmd.prototype.process = function(args) {
this.newApp();
this.demo();
this.build();
this.run();
this.blockchain();
this.simulator();
this.test();
this.upload();
this.otherCommands();
//If no arguments are passed display help by default
if (!process.argv.slice(2).length) {
program.help();
} }
program.parse(args);
};
Cmd.prototype.newApp = function() { process(args) {
var self = this; this.newApp();
program this.demo();
.command('new [name]') this.build();
.description('new application') this.run();
.action(function(name, options) { this.blockchain();
if (name === undefined) { this.simulator();
console.log("please specify your app Name".red); this.test();
console.log("e.g embark new MyApp".green); this.upload();
console.log("e.g embark new --help for more information".green); this.otherCommands();
process.exit(code);
//If no arguments are passed display help by default
if (!process.argv.slice(2).length) {
program.help();
} }
self.Embark.generateTemplate('boilerplate', './', name);
});
};
Cmd.prototype.demo = function() { program.parse(args);
var self = this; }
program
.command('demo')
.description('create a working dapp with a SimpleStorage contract')
.action(function() {
self.Embark.generateTemplate('demo', './', 'embark_demo');
});
};
Cmd.prototype.build = function() { newApp(name) {
var self = this;
program
.command('build [environment]')
.description('deploy and build dapp at dist/ (default: development)')
.action(function(env, options) {
self.Embark.build({env: env || 'development'});
});
};
Cmd.prototype.run = function() { let validateName = function (value) {
var self = this; try {
program if (value.match(/^[a-zA-Z\s\-]+$/)) return value;
.command('run [environment]') } catch (e) {
.option('-p, --port [port]', 'port to run the dev webserver (default: 8000)') throw new Error('Name must be only letters, spaces, or dashes');
.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.run({
env: env || 'development',
serverPort: options.port,
serverHost: options.host,
runWebserver: !options.noserver,
useDashboard: !options.nodashboard
});
});
};
Cmd.prototype.blockchain = function() { program
var self = this; .command('new [name]')
program .description('new application')
.command('blockchain [environment]') .action(function (name) {
.option('-c, --client [client]', 'Use a specific ethereum client or simulator (supported: geth, parity, ethersim, testrpc') if (name === undefined) {
.description('run blockchain server (default: development)') return promptly.prompt("Name your app (default is embarkDApp):", {
.action(function(env ,options) { default: "embarkDApp",
self.Embark.initConfig(env || 'development', { validator: validateName
embarkConfig: 'embark.json', }, function (err, inputvalue) {
interceptLogs: false if (err) {
}); console.error('Invalid name:', err.message);
self.Embark.blockchain(env || 'development', options.client || 'geth'); // Manually call retry
}); // The passed error has a retry method to easily prompt again.
}; err.retry();
} else {
//slightly different assignment of name since it comes from child prompt
embark.generateTemplate('boilerplate', './', inputvalue);
}
});
} else {
embark.generateTemplate('boilerplate', './', name);
}
Cmd.prototype.simulator = function() { });
var self = this; }
program
.command('simulator [environment]')
.description('run a fast ethereum rpc simulator')
.option('--testrpc', 'use testrpc as the rpc simulator [default]')
.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});
});
};
Cmd.prototype.test = function() { demo() {
program program
.command('test') .command('demo')
.description('run tests') .description('create a working dapp with a SimpleStorage contract')
.action(function() { .action(function () {
shelljs.exec('mocha test/ --no-timeouts'); embark.generateTemplate('demo', './', 'embark_demo');
}); });
}; }
Cmd.prototype.upload = function() { build() {
var self = this; program
program .command('build [environment]')
.command('upload [platform] [environment]') .description('deploy and build dapp at dist/ (default: development)')
.description('upload your dapp to a decentralized storage. possible options: ipfs, swarm (e.g embark upload swarm)') .action(function (env, options) {
.action(function(platform, env, options) { embark.build({env: env || 'development'});
// TODO: get env in cmd line as well });
self.Embark.initConfig(env || 'development', { }
embarkConfig: 'embark.json', interceptLogs: false
});
self.Embark.upload(platform);
});
};
Cmd.prototype.otherCommands = function() { run() {
program program
.action(function(env){ .command('run [environment]')
console.log('unknown command "%s"'.red, env); .option('-p, --port [port]', 'port to run the dev webserver (default: 8000)')
console.log("type embark --help to see the available commands"); .option('-b, --host [host]', 'host to run the dev webserver (default: localhost)')
process.exit(0); .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) {
embark.run({
env: env || 'development',
serverPort: options.port,
serverHost: options.host,
runWebserver: !options.noserver,
useDashboard: !options.nodashboard
});
});
}
blockchain() {
program
.command('blockchain [environment]')
.option('-c, --client [client]', 'Use a specific ethereum client or simulator (supported: geth, parity, ethersim, testrpc')
.description('run blockchain server (default: development)')
.action(function (env, options) {
embark.initConfig(env || 'development', {
embarkConfig: 'embark.json',
interceptLogs: false
});
embark.blockchain(env || 'development', options.client || 'geth');
});
}
simulator() {
program
.command('simulator [environment]')
.description('run a fast ethereum rpc simulator')
.option('--testrpc', 'use testrpc as the rpc simulator [default]')
.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) {
embark.initConfig(env || 'development', {
embarkConfig: 'embark.json',
interceptLogs: false
});
embark.simulator({port: options.port, host: options.host});
});
}
test() {
program
.command('test')
.description('run tests')
.action(function () {
shelljs.exec('mocha test');
});
}
upload() {
program
.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
embark.initConfig(env || 'development', {
embarkConfig: 'embark.json', interceptLogs: false
});
embark.upload(platform);
});
}
otherCommands() {
program
.action(function (env) {
console.log('unknown command "%s"'.red, env);
console.log("type embark --help to see the available commands");
process.exit(0);
});
}
}
module.exports = Cmd; module.exports = Cmd;

View File

@ -35,9 +35,9 @@ var Blockchain = function(options) {
this.client = new options.client({config: this.config, env: this.env}); this.client = new options.client({config: this.config, env: this.env});
}; };
Blockchain.prototype.runCommand = function(cmd) { Blockchain.prototype.runCommand = function(cmd, options) {
console.log(("running: " + cmd.underline).green); console.log(("running: " + cmd.underline).green);
return shelljs.exec(cmd); return shelljs.exec(cmd, options);
}; };
Blockchain.prototype.run = function() { Blockchain.prototype.run = function() {
@ -49,7 +49,7 @@ Blockchain.prototype.run = function() {
console.log("===============================================================================".magenta); console.log("===============================================================================".magenta);
var address = this.initChainAndGetAddress(); var address = this.initChainAndGetAddress();
this.client.mainCommand(address, function(cmd) { this.client.mainCommand(address, function(cmd) {
self.runCommand(cmd); self.runCommand(cmd, {async: true});
}); });
}; };
@ -65,7 +65,7 @@ Blockchain.prototype.initChainAndGetAddress = function() {
// check if an account already exists, create one if not, return address // check if an account already exists, create one if not, return address
result = this.runCommand(this.client.listAccountsCommand()); result = this.runCommand(this.client.listAccountsCommand());
if (result.output === undefined || result.output === '' || result.output.indexOf("Fatal") >= 0) { if (result.output === undefined || result.output.match(/{(\w+)}/) === null || result.output.indexOf("Fatal") >= 0) {
console.log("no accounts found".green); console.log("no accounts found".green);
if (this.config.genesisBlock) { if (this.config.genesisBlock) {
console.log("initializing genesis block".green); console.log("initializing genesis block".green);

View File

@ -1,164 +1,171 @@
var async = require('async'); let async = require('async');
// TODO: make all of this async // TODO: make all of this async
var GethCommands = function(options) { class GethCommands {
this.config = options.config; constructor(options) {
this.env = options.env || 'development'; this.config = options && options.hasOwnProperty('config') ? options.config : {};
this.name = "Go-Ethereum (https://github.com/ethereum/go-ethereum)"; this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
this.geth_bin = this.config.geth_bin || "geth"; 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) { commonOptions() {
cmd += "--light "; let config = this.config;
let 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;
} }
if (config.fast) { determineNetworkType(config) {
cmd += "--fast "; let 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;
} }
if (config.account && config.account.password) { initGenesisCommmand() {
cmd += "--password " + config.account.password + " "; let config = this.config;
let cmd = this.geth_bin + " " + this.commonOptions();
if (config.genesisBlock) {
cmd += "init \"" + config.genesisBlock + "\" ";
}
return cmd;
} }
return cmd; newAccountCommand() {
}; return this.geth_bin + " " + this.commonOptions() + "account new ";
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; listAccountsCommand() {
}; return this.geth_bin + " " + this.commonOptions() + "account list ";
}
GethCommands.prototype.newAccountCommand = function() { determineRpcOptions(config) {
return this.geth_bin + " " + this.commonOptions() + "account new "; let cmd = "";
};
GethCommands.prototype.listAccountsCommand = function() { cmd += "--port " + config.port + " ";
return this.geth_bin + " " + this.commonOptions() + "account list "; cmd += "--rpc ";
}; cmd += "--rpcport " + config.rpcPort + " ";
cmd += "--rpcaddr " + config.rpcHost + " ";
GethCommands.prototype.determineRpcOptions = function(config) { if (config.rpcCorsDomain) {
var cmd = ""; if (config.rpcCorsDomain === '*') {
console.log('==================================');
cmd += "--port " + config.port + " "; console.log('make sure you know what you are doing');
cmd += "--rpc "; console.log('==================================');
cmd += "--rpcport " + config.rpcPort + " "; }
cmd += "--rpcaddr " + config.rpcHost + " "; cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
if (config.rpcCorsDomain) { } else {
if (config.rpcCorsDomain === '*') {
console.log('=================================='); console.log('==================================');
console.log('make sure you know what you are doing'); console.log('warning: cors is not set');
console.log('=================================='); console.log('==================================');
} }
cmd += "--rpccorsdomain=\"" + config.rpcCorsDomain + "\" ";
} else { return cmd;
console.log('==================================');
console.log('warning: cors is not set');
console.log('==================================');
} }
return cmd; mainCommand(address, done) {
}; let self = this;
let config = this.config;
let rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net']);
GethCommands.prototype.mainCommand = function(address, done) { async.series([
var self = this; function commonOptions(callback) {
var config = this.config; let cmd = self.commonOptions();
var rpc_api = (this.config.rpcApi || ['eth', 'web3', 'net']); callback(null, cmd);
},
async.series([ function rpcOptions(callback) {
function commonOptions(callback) { let cmd = self.determineRpcOptions(self.config);
var cmd = self.commonOptions(); callback(null, cmd);
callback(null, cmd); },
}, function dontGetPeers(callback) {
function rpcOptions(callback) { if (config.nodiscover) {
var cmd = self.determineRpcOptions(self.config); return callback(null, "--nodiscover");
callback(null, cmd); }
}, callback(null, "");
function dontGetPeers(callback) { },
if (config.nodiscover) { function vmDebug(callback) {
return callback(null, "--nodiscover"); if (config.vmdebug) {
return callback(null, "--vmdebug");
}
callback(null, "");
},
function maxPeers(callback) {
let 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) {
let accountAddress = "";
if(config.hasOwnProperty('address') && config.account.hasOwnProperty('address')) {
accountAddress = config.account.address;
} else {
accountAddress = 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, "");
} }
callback(null, ""); ], function (err, results) {
}, if (err) {
function vmDebug(callback) { throw new Error(err.message);
if (config.vmdebug) {
return callback(null, "--vmdebug");
} }
callback(null, ""); done(self.geth_bin + " " + results.join(" "));
}, });
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; module.exports = GethCommands;

View File

@ -1,18 +1,20 @@
var shelljs = require('shelljs'); let shelljs = require('shelljs');
var Simulator = function(options) { class Simulator {
this.blockchainConfig = options.blockchainConfig; constructor(options) {
}; this.blockchainConfig = options.blockchainConfig;
}
Simulator.prototype.run = function(options) { run(options) {
var cmds = []; let cmds = [];
cmds.push("-p " + (this.blockchainConfig.rpcPort || options.port || 8545)); cmds.push("-p " + (this.blockchainConfig.rpcPort || options.port || 8545));
cmds.push("-h " + (this.blockchainConfig.rpcHost || options.host || 'localhost')); cmds.push("-h " + (this.blockchainConfig.rpcHost || options.host || 'localhost'));
cmds.push("-a " + (options.num || 10)); cmds.push("-a " + (options.num || 10));
shelljs.exec('testrpc ' + cmds.join(' ')); shelljs.exec('testrpc ' + cmds.join(' '), {async : true});
}; }
}
module.exports = Simulator; module.exports = Simulator;

View File

@ -1,32 +1,35 @@
var fs = require('../core/fs.js'); let fs = require('../core/fs.js');
var utils = require('../core/utils.js'); let utils = require('../utils/utils.js');
var TemplateGenerator = function(templateName) { class TemplateGenerator {
this.templateName = templateName; constructor(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);
} }
};
generate(destinationFolder, name) {
let templatePath = fs.embarkPath(this.templateName);
console.log('Initializing Embark Template....'.green);
let fspath = utils.joinPath(destinationFolder, name);
fs.copySync(templatePath, fspath);
utils.cd(fspath);
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 + fspath);
if (name === 'embark_demo') {
console.log('-------------------'.yellow);
console.log('Next steps:'.green);
console.log(('-> ' + ('cd ' + fspath).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; module.exports = TemplateGenerator;

View File

@ -1,138 +1,170 @@
class ABIGenerator {
var ABIGenerator = function(options) { constructor(options) {
this.blockchainConfig = options.blockchainConfig || {}; this.blockchainConfig = options.blockchainConfig || {};
this.storageConfig = options.storageConfig || {}; this.storageConfig = options.storageConfig || {};
this.communicationConfig = options.communicationConfig || {}; this.communicationConfig = options.communicationConfig || {};
this.contractsManager = options.contractsManager; this.contractsManager = options.contractsManager;
this.rpcHost = options.blockchainConfig && options.blockchainConfig.rpcHost; this.rpcHost = options.blockchainConfig && options.blockchainConfig.rpcHost;
this.rpcPort = options.blockchainConfig && options.blockchainConfig.rpcPort; this.rpcPort = options.blockchainConfig && options.blockchainConfig.rpcPort;
this.plugins = options.plugins; this.plugins = options.plugins;
};
ABIGenerator.prototype.generateProvider = function() {
var self = this;
var result = "";
var providerPlugins;
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
return "";
} }
result += "\nvar whenEnvIsLoaded = function(cb) {"; generateProvider() {
result += "\n if (typeof window !== 'undefined' && window !== null) {"; let self = this;
result += "\n window.addEventListener('load', cb);"; let result = "";
result += "\n } else {"; let providerPlugins;
result += "\n cb();";
result += "\n }";
result += "\n}";
if (this.plugins) { if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
providerPlugins = this.plugins.getPluginsFor('clientWeb3Provider'); return "";
}
if (this.plugins && providerPlugins.length > 0) {
providerPlugins.forEach(function(plugin) {
result += plugin.generateProvider(self) + "\n";
});
} else {
result += "\nwhenEnvIsLoaded(function() {";
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];";
result += '\n})';
}
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);
// TODO: refactor this
result += "\nvar whenEnvIsLoaded = function(cb) {";
result += "\n if (typeof window !== 'undefined' && window !== null) {";
result += "\n window.addEventListener('load', cb);";
result += "\n } else {";
result += "\n cb();";
result += "\n }";
result += "\n}";
result += "\nwhenEnvIsLoaded(function() {";
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 + "');";
}
result += '\n});';
} }
result += "\nvar whenEnvIsLoaded = function(cb) {";
result += "\n if (typeof document !== 'undefined' && document !== null) {";
result += "\n document.addEventListener('DOMContentLoaded', cb);";
result += "\n } else {";
result += "\n cb();";
result += "\n }";
result += "\n}";
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 += "\nwhenEnvIsLoaded(function() {";
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];";
result += '\n})';
}
return result;
} }
return result; generateContracts(useEmbarkJS) {
}; let self = this;
let result = "\n";
let contractsPlugins;
ABIGenerator.prototype.generateStorageInitialization = function(useEmbarkJS) { if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
var self = this; return "";
var result = "\n"; }
if (!useEmbarkJS || self.storageConfig === {}) return ""; if (this.plugins) {
contractsPlugins = this.plugins.getPluginsFor('contractGeneration');
}
if (self.storageConfig.provider === 'ipfs' && self.storageConfig.enabled === true) { if (this.plugins && contractsPlugins.length > 0) {
result += "\nEmbarkJS.Storage.setProvider('" + self.storageConfig.provider + "', {server: '" + self.storageConfig.host + "', port: '" + self.storageConfig.port + "'});"; contractsPlugins.forEach(function (plugin) {
result += plugin.generateContracts({contracts: self.contractsManager.contracts});
});
} else {
for (let className in this.contractsManager.contracts) {
let contract = this.contractsManager.contracts[className];
let abi = JSON.stringify(contract.abiDefinition);
let gasEstimates = JSON.stringify(contract.gasEstimates);
// TODO: refactor this
result += "\nif (whenEnvIsLoaded === undefined) {";
result += "\n var whenEnvIsLoaded = function(cb) {";
result += "\n if (typeof document !== 'undefined' && document !== null) {";
result += "\n document.addEventListener('DOMContentLoaded', cb);";
result += "\n } else {";
result += "\n cb();";
result += "\n }";
result += "\n }";
result += "\n}";
result += "\nwhenEnvIsLoaded(function() {";
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 + "');";
}
result += '\n});';
}
}
return result;
} }
return result; generateStorageInitialization(useEmbarkJS) {
}; let self = this;
let result = "\n";
ABIGenerator.prototype.generateCommunicationInitialization = function(useEmbarkJS) { if (!useEmbarkJS || self.storageConfig === {}) return "";
var self = this;
var result = "\n";
if (!useEmbarkJS || self.communicationConfig === {}) 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 + "'});";
}
if (self.communicationConfig.provider === 'whisper' && self.communicationConfig.enabled === true) { return result;
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; generateCommunicationInitialization(useEmbarkJS) {
}; let self = this;
let result = "\n";
ABIGenerator.prototype.generateABI = function(options) { if (!useEmbarkJS || self.communicationConfig === {}) return "";
var result = "";
result += this.generateProvider(); if (self.communicationConfig.provider === 'whisper' && self.communicationConfig.enabled === true) {
result += this.generateContracts(options.useEmbarkJS); result += "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "');";
result += this.generateStorageInitialization(options.useEmbarkJS); } else if (self.communicationConfig.provider === 'orbit' && self.communicationConfig.enabled === true) {
result += this.generateCommunicationInitialization(options.useEmbarkJS); if (self.communicationConfig.host === undefined && self.communicationConfig.port === undefined) {
result += "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "');";
} else {
result += "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "', {server: '" + self.communicationConfig.host + "', port: '" + self.communicationConfig.port + "'});";
}
}
return result; return result;
}; }
generateABI(options) {
let result = "";
result += this.generateProvider();
result += this.generateContracts(options.useEmbarkJS);
result += this.generateStorageInitialization(options.useEmbarkJS);
result += this.generateCommunicationInitialization(options.useEmbarkJS);
return result;
}
generateContractsJSON() {
let contracts = {};
for (let className in this.contractsManager.contracts) {
let contract = this.contractsManager.contracts[className];
let contractJSON = {};
let abi = JSON.stringify(contract.abiDefinition);
let gasEstimates = JSON.stringify(contract.gasEstimates);
contractJSON.contract_name = className;
contractJSON.code = contract.code;
contractJSON.runtime_bytecode = contract.runtimeBytecode;
contractJSON.real_runtime_bytecode = contract.realRuntimeBytecode;
contractJSON.swarm_hash = contract.swarmHash;
contractJSON.gas_estimates = contract.gasEstimates;
contractJSON.function_hashes = contract.functionHashes;
contractJSON.abi = contract.abiDefinition;
contracts[className] = contractJSON;
}
return contracts;
}
}
module.exports = ABIGenerator; module.exports = ABIGenerator;

View File

@ -1,118 +1,115 @@
/*jshint esversion: 6, loopfunc: true */ /*jshint esversion: 6, loopfunc: true */
var async = require('async'); let async = require('../utils/async_extend.js');
var SolcW = require('./solcW.js'); let SolcW = require('./solcW.js');
function asyncEachObject(object, iterator, callback) { class Compiler {
async.each( constructor(options) {
Object.keys(object || {}), this.plugins = options.plugins;
function(key, next){ this.logger = options.logger;
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 = {}; compile_contracts(contractFiles, cb) {
async.eachObject(available_compilers, let available_compilers = {
function(extension, compiler, callback) { //".se": this.compile_serpent
// TODO: warn about files it doesn't know how to compile ".sol": this.compile_solidity.bind(this)
var matchingFiles = contractFiles.filter(function(file) { };
return (file.filename.match(/\.[0-9a-z]+$/)[0] === extension);
});
compiler.call(compiler, matchingFiles || [], function(err, compileResult) { if (this.plugins) {
Object.assign(compiledObject, compileResult); let compilerPlugins = this.plugins.getPluginsFor('compilers');
callback(err, compileResult); if (compilerPlugins.length > 0) {
}); compilerPlugins.forEach(function (plugin) {
}, plugin.compilers.forEach(function (compilerObject) {
function (err) { available_compilers[compilerObject.extension] = compilerObject.cb;
cb(err, compiledObject); });
});
}
} }
);
};
Compiler.prototype.compile_solidity = function(contractFiles, cb) { let compiledObject = {};
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.."); async.eachObject(available_compilers,
solcW.load_compiler(function(){ function (extension, compiler, callback) {
callback(); // TODO: warn about files it doesn't know how to compile
}); let matchingFiles = contractFiles.filter(function (file) {
}, return (file.filename.match(/\.[0-9a-z]+$/)[0] === extension);
function compileContracts(callback) { });
self.logger.info("compiling contracts...");
solcW.compile({sources: input}, 1, function(output) { compiler.call(compiler, matchingFiles || [], function (err, compileResult) {
if (output.errors) { Object.assign(compiledObject, compileResult);
return callback(new Error ("Solidity errors: " + output.errors).message); callback(err, compileResult);
});
},
function (err) {
cb(err, compiledObject);
}
);
}
compile_solidity(contractFiles, cb) {
let self = this;
let input = {};
let solcW;
async.waterfall([
function prepareInput(callback) {
for (let i = 0; i < contractFiles.length; i++) {
// TODO: this depends on the config
let 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();
} }
callback(null, output);
});
},
function createCompiledObject(output, callback) {
var json = output.contracts;
compiled_object = {}; 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) {
let json = output.contracts;
for (var className in json) { let compiled_object = {};
var contract = json[className];
compiled_object[className] = {}; for (let contractName in json) {
compiled_object[className].code = contract.bytecode; let contract = json[contractName];
compiled_object[className].runtimeBytecode = contract.runtimeBytecode;
compiled_object[className].realRuntimeBytecode = contract.runtimeBytecode.slice(0, -68); // Pull out filename:classname
compiled_object[className].swarmHash = contract.runtimeBytecode.slice(-68).slice(0,64); // [0] filename:classname
compiled_object[className].gasEstimates = contract.gasEstimates; // [1] filename
compiled_object[className].functionHashes = contract.functionHashes; // [2] classname
compiled_object[className].abiDefinition = JSON.parse(contract.interface); const regex = /(.*):(.*)/;
const className = contractName.match(regex)[2];
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);
} }
callback(null, compiled_object); ], function (err, result) {
} cb(err, result);
], function(err, result) { });
cb(err, result); }
}); }
};
module.exports = Compiler; module.exports = Compiler;

View File

@ -1,247 +1,251 @@
var toposort = require('toposort'); let toposort = require('toposort');
var async = require('async'); let async = require('async');
var Compiler = require('./compiler.js'); let Compiler = require('./compiler.js');
// TODO: create a contract object // TODO: create a contract object
var adjustGas = function(contract) { class ContractsManager {
var maxGas, adjustedGas; constructor(options) {
if (contract.gas === 'auto') { this.contractFiles = options.contractFiles;
if (contract.deploy || contract.deploy === undefined) { this.contractsConfig = options.contractsConfig;
if (contract.gasEstimates.creation !== undefined) { this.contracts = {};
// TODO: should sum it instead this.logger = options.logger;
maxGas = Math.max(contract.gasEstimates.creation[0], contract.gasEstimates.creation[1], 500000); this.plugins = options.plugins;
} else {
maxGas = 500000; this.contractDependencies = {};
}
} 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) { build(done) {
this.contractFiles = options.contractFiles; let self = this;
this.contractsConfig = options.contractsConfig; async.waterfall([
this.contracts = {}; function compileContracts(callback) {
this.logger = options.logger; let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
this.plugins = options.plugins; compiler.compile_contracts(self.contractFiles, function (err, compiledObject) {
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; self.compiledContracts = compiledObject;
callback(err); callback(err);
}); });
}, },
function prepareContractsFromConfig(callback) { function prepareContractsFromConfig(callback) {
var className, contract; let className, contract;
for(className in self.contractsConfig.contracts) { for (className in self.contractsConfig.contracts) {
contract = self.contractsConfig.contracts[className]; contract = self.contractsConfig.contracts[className];
contract.className = className; contract.className = className;
contract.args = contract.args || []; contract.args = contract.args || [];
self.contracts[className] = contract; 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;
} }
callback();
if (parentContract === undefined) { },
self.logger.error(className + ": couldn't find instanceOf contract " + parentContractName); function setDeployIntention(callback) {
continue; let className, contract;
for (className in self.contracts) {
contract = self.contracts[className];
contract.deploy = (contract.deploy === undefined) || contract.deploy;
} }
callback();
},
function prepareContractsFromCompilation(callback) {
let className, compiledContract, contractConfig, contract;
for (className in self.compiledContracts) {
compiledContract = self.compiledContracts[className];
contractConfig = self.contractsConfig.contracts[className];
if (parentContract.args && parentContract.args.length > 0 && ((contract.args && contract.args.length === 0) || contract.args === undefined)) { contract = self.contracts[className] || {className: className, args: []};
contract.args = parentContract.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';
self.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) {
let 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';
if (contract.code !== undefined) {
self.logger.error(className + " has code associated to it but it's configured as an instanceOf " + parentContractName);
} }
callback();
},
function removeContractsWithNoCode(callback) {
let className, contract;
for (className in self.contracts) {
contract = self.contracts[className];
contract.code = parentContract.code; if (contract.code === undefined) {
contract.runtimeBytecode = parentContract.runtimeBytecode; self.logger.error(className + " has no code associated");
contract.gasEstimates = parentContract.gasEstimates; delete self.contracts[className];
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));
} }
} }
self.logger.trace(self.contracts);
callback();
},
function determineDependencies(callback) {
let className, contract;
for (className in self.contracts) {
contract = self.contracts[className];
if (contract.args === []) continue;
let ref = contract.args;
for (let j = 0; j < ref.length; j++) {
let arg = ref[j];
if (arg[0] === "$") {
self.contractDependencies[className] = self.contractDependencies[className] || [];
self.contractDependencies[className].push(arg.substr(1));
}
}
}
callback();
} }
callback(); ], function (err, result) {
} if (err) {
], function(err, result) { self.logger.error("Error Compiling/Building contracts: " + err);
if (err) { }
self.logger.error("Error Compiling/Building contracts: " + err); self.logger.trace("finished".underline);
} done(err, self);
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(); getContract(className) {
return this.contracts[className];
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() { sortContracts(contractList) {
var data = []; let converted_dependencies = [], i;
for(var className in this.contracts) { for (let contract in this.contractDependencies) {
var contract = this.contracts[className]; let dependencies = this.contractDependencies[contract];
for (i = 0; i < dependencies.length; i++) {
var contractData; converted_dependencies.push([contract, dependencies[i]]);
}
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); let orderedDependencies = toposort(converted_dependencies).reverse();
let newList = contractList.sort(function (a, b) {
let order_a = orderedDependencies.indexOf(a.className);
let order_b = orderedDependencies.indexOf(b.className);
return order_a - order_b;
});
return newList;
} }
return data; // TODO: should be built contracts
}; listContracts() {
let contracts = [];
for (let className in this.contracts) {
let contract = this.contracts[className];
contracts.push(contract);
}
return this.sortContracts(contracts);
}
contractsState() {
let data = [];
for (let className in this.contracts) {
let contract = this.contracts[className];
let 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;
}
adjustGas(contract) {
let 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;
}
}
}
module.exports = ContractsManager; module.exports = ContractsManager;

View File

@ -1,166 +1,168 @@
var async = require('async'); let async = require('async');
var RunCode = require('../core/runCode.js'); let RunCode = require('../core/runCode.js');
var DeployTracker = require('./deploy_tracker.js'); let DeployTracker = require('./deploy_tracker.js');
var ABIGenerator = require('./abi.js'); let ABIGenerator = require('./abi.js');
var Deploy = function(options) { class Deploy {
this.web3 = options.web3; constructor(options) {
this.contractsManager = options.contractsManager; this.web3 = options.web3;
this.logger = options.logger; this.contractsManager = options.contractsManager;
this.env = options.env; this.logger = options.logger;
this.env = options.env;
this.deployTracker = new DeployTracker({ this.deployTracker = new DeployTracker({
logger: options.logger, chainConfig: options.chainConfig, web3: options.web3, env: this.env logger: options.logger, chainConfig: options.chainConfig, web3: options.web3, env: this.env
}); });
};
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; determineArguments(suppliedArgs) {
}; let realArgs = [], l, arg, contractName, referedContract;
Deploy.prototype.checkAndDeployContract = function(contract, params, callback) { for (l = 0; l < suppliedArgs.length; l++) {
var self = this; arg = suppliedArgs[l];
var suppliedArgs; if (arg[0] === "$") {
var realArgs; contractName = arg.substr(1);
var arg; referedContract = this.contractsManager.getContract(contractName);
var l; realArgs.push(referedContract.deployedAddress);
var contractName; } else {
var referedContract; realArgs.push(arg);
contract.error = false;
if (contract.deploy === false) {
self.logger.contractsState(self.contractsManager.contractsState());
return callback();
}
if (contract.address !== undefined) {
realArgs = self.determineArguments(params || contract.args);
contract.deployedAddress = 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.realRuntimeBytecode, contract.args);
if (trackedContract && this.web3.eth.getCode(trackedContract.address) !== "0x") {
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());
return callback();
} else {
realArgs = self.determineArguments(params || contract.args);
this.deployContract(contract, realArgs, function(err, address) {
if (err) {
return callback(new Error(err));
} }
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, address); }
return realArgs;
}
checkAndDeployContract(contract, params, callback) {
let self = this;
let suppliedArgs;
let realArgs;
let arg;
let l;
let contractName;
let referedContract;
contract.error = false;
if (contract.deploy === false) {
self.logger.contractsState(self.contractsManager.contractsState());
return callback();
}
if (contract.address !== undefined) {
realArgs = self.determineArguments(params || contract.args);
contract.deployedAddress = contract.address;
self.deployTracker.trackContract(contract.className, contract.realRuntimeBytecode, realArgs, contract.address);
self.deployTracker.save(); self.deployTracker.save();
self.logger.contractsState(self.contractsManager.contractsState()); self.logger.contractsState(self.contractsManager.contractsState());
return callback();
}
if (contract.onDeploy !== undefined) { let trackedContract = self.deployTracker.getContract(contract.className, contract.realRuntimeBytecode, contract.args);
self.logger.info('executing onDeploy commands');
var abiGenerator = new ABIGenerator({contractsManager: self.contractsManager});
var abi = abiGenerator.generateContracts(false);
var cmds = contract.onDeploy.join(';\n');
RunCode.doEval(abi + "\n" + cmds, self.web3); if (trackedContract && this.web3.eth.getCode(trackedContract.address) !== "0x") {
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());
return callback();
} else {
realArgs = self.determineArguments(params || contract.args);
this.deployContract(contract, realArgs, function (err, 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());
if (contract.onDeploy !== undefined) {
self.logger.info('executing onDeploy commands');
let abiGenerator = new ABIGenerator({contractsManager: self.contractsManager});
let abi = abiGenerator.generateContracts(false);
let cmds = contract.onDeploy.join(';\n');
RunCode.doEval(abi + "\n" + cmds, self.web3);
}
callback();
});
}
}
deployContract(contract, params, callback) {
let self = this;
let contractObject = this.web3.eth.contract(contract.abiDefinition);
let contractParams = (params || contract.args).slice();
this.web3.eth.getAccounts(function (err, accounts) {
if (err) {
return callback(new Error(err));
} }
callback(); // TODO: probably needs to be defaultAccount
// TODO: it wouldn't necessary be the first address
// use defined blockchain address or first address
contractParams.push({
//from: this.web3.eth.coinbase,
from: accounts[0],
data: "0x" + contract.code,
gas: contract.gas,
gasPrice: contract.gasPrice
});
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.cyan);
let 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;
return callback(new Error(err));
} else if (transaction.address !== undefined) {
self.logger.info(contract.className.bold.cyan + " deployed at ".green + transaction.address.bold.cyan);
contract.deployedAddress = transaction.address;
contract.transactionHash = transaction.transactionHash;
return callback(null, transaction.address);
}
});
contractObject["new"].apply(contractObject, contractParams);
}); });
} }
}; deployAll(done) {
let self = this;
this.logger.info("deploying contracts");
Deploy.prototype.deployContract = function(contract, params, callback) { async.eachOfSeries(this.contractsManager.listContracts(),
var self = this; function (contract, key, callback) {
var contractObject = this.web3.eth.contract(contract.abiDefinition); self.logger.trace(arguments);
self.checkAndDeployContract(contract, null, callback);
var contractParams = (params || contract.args).slice(); },
function (err, results) {
this.web3.eth.getAccounts(function(err, accounts) { if (err) {
if (err) { self.logger.error("error deploying contracts");
return callback(new Error(err)); self.logger.error(err.message);
} self.logger.debug(err.stack);
// TODO: probably needs to be defaultAccount
// TODO: it wouldn't necessary be the first address
// use defined blockchain address or first address
contractParams.push({
//from: this.web3.eth.coinbase,
from: accounts[0],
data: "0x" + contract.code,
gas: contract.gas,
gasPrice: contract.gasPrice
});
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.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); self.logger.info("finished deploying contracts");
contract.error = errMsg; self.logger.trace(arguments);
return callback(new Error(err)); done();
} else if (transaction.address !== undefined) {
self.logger.info(contract.className.bold.cyan + " deployed at ".green + transaction.address.bold.cyan);
contract.deployedAddress = transaction.address;
contract.transactionHash = transaction.transactionHash;
return callback(null, transaction.address);
} }
}); );
contractObject["new"].apply(contractObject, contractParams); }
}); }
};
Deploy.prototype.deployAll = function(done) {
var self = this;
this.logger.info("deploying contracts");
async.eachOfSeries(this.contractsManager.listContracts(),
function(contract, key, callback) {
self.logger.trace(arguments);
self.checkAndDeployContract(contract, null, callback);
},
function(err, results) {
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();
}
);
};
module.exports = Deploy; module.exports = Deploy;

View File

@ -1,85 +1,90 @@
var async = require('async'); let async = require('async');
var Web3 = require('web3'); let Deploy = require('./deploy.js');
let ContractsManager = require('./contracts.js');
var Deploy = require('./deploy.js'); class DeployManager {
var ContractsManager = require('./contracts.js'); constructor(options) {
this.config = options.config;
var DeployManager = function(options) { this.logger = options.logger;
this.config = options.config; this.blockchainConfig = this.config.blockchainConfig;
this.logger = options.logger; this.events = options.events;
this.blockchainConfig = this.config.blockchainConfig; this.plugins = options.plugins;
this.plugins = options.plugins; this.web3 = options.web3;
this.events = options.events; this.chainConfig = (options.trackContracts !== false) ? this.config.chainTracker : false;
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([ deployContracts(done) {
function buildContracts(callback) { let self = this;
var contractsManager = new ContractsManager({
contractFiles: self.config.contractsFiles, if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
contractsConfig: self.config.contractsConfig, self.logger.info("Blockchain component is disabled in the config".underline);
logger: self.logger, this.events.emit('blockchainDisabled', {});
plugins: self.plugins return done();
});
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);
}, async.waterfall([
function setDefaultAccount(contractsManager, web3, callback) { function buildContracts(callback) {
web3.eth.getAccounts(function(err, accounts) { let contractsManager = new ContractsManager({
contractFiles: self.config.contractsFiles,
contractsConfig: self.config.contractsConfig,
logger: self.logger,
plugins: self.plugins
});
contractsManager.build(callback);
},
function checkWeb3IsConnected(contractsManager, callback) {
if (!self.web3) {
return callback(Error("no web3 instance found"));
}
if (self.web3.currentProvider.isConnected !== undefined && !self.web3.isConnected()) {
self.logger.error(("Couldn't connect to an Ethereum node 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"));
}
if (self.web3.currentProvider.isConnected === undefined) {
self.web3.version.getNode(function (err, version) {
if (err) {
return callback(Error("error connecting to blockchain node"));
}
return callback(null, contractsManager, self.web3);
});
} else {
return callback(null, contractsManager, self.web3);
}
},
function setDefaultAccount(contractsManager, web3, callback) {
web3.eth.getAccounts(function (err, accounts) {
if (err) {
return callback(new Error(err));
}
let accountConfig = self.config.blockchainConfig.account;
let selectedAccount = accountConfig && accountConfig.address;
web3.eth.defaultAccount = (selectedAccount || accounts[0]);
callback(null, contractsManager, web3);
});
},
function deployAllContracts(contractsManager, web3, callback) {
let 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) { if (err) {
return callback(new Error(err)); done(err, null);
} else {
done(null, result);
} }
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; module.exports = DeployManager;

View File

@ -1,56 +1,62 @@
var fs = require('../core/fs.js'); let fs = require('../core/fs.js');
var DeployTracker = function(options) { class DeployTracker {
this.logger = options.logger; constructor(options) {
this.env = options.env; this.logger = options.logger;
this.chainConfig = options.chainConfig; this.env = options.env;
this.web3 = options.web3; this.chainConfig = options.chainConfig;
this.web3 = options.web3;
if (this.chainConfig === false) { if (this.chainConfig === false) {
this.currentChain = {contracts: []}; this.currentChain = {contracts: []};
return; return;
}
// TODO: need to make this async
let block = this.web3.eth.getBlock(0);
let chainId = block.hash;
if (this.chainConfig[chainId] === undefined) {
this.chainConfig[chainId] = {contracts: {}};
}
this.currentChain = this.chainConfig[chainId];
this.currentChain.name = this.env;
// TODO: add other params
//this.currentChain.networkId = "";
//this.currentChain.networkType = "custom"
} }
// TODO: need to make this async loadConfig(config) {
var block = this.web3.eth.getBlock(0); this.chainConfig = config;
var chainId = block.hash; return this;
if (this.chainConfig[chainId] === undefined) {
this.chainConfig[chainId] = {contracts: {}};
} }
this.currentChain = this.chainConfig[chainId]; trackContract(contractName, code, args, address) {
this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))] = {
name: contractName,
address: address
};
}
this.currentChain.name = this.env; getContract(contractName, code, args) {
// TODO: add other params let contract = this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))];
//this.currentChain.networkId = ""; if (contract && contract.address === undefined) {
//this.currentChain.networkType = "custom" return false;
}; }
return contract;
}
DeployTracker.prototype.loadConfig = function(config) { // TODO: abstract this
this.chainConfig = config; // chainConfig can be an abstract PersistentObject
return this; save() {
}; if (this.chainConfig === false) {
return;
DeployTracker.prototype.trackContract = function(contractName, code, args, address) { }
this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))] = { fs.writeJSONSync("./chains.json", this.chainConfig, {spaces: 2});
name: contractName, }
address: address }
};
};
DeployTracker.prototype.getContract = function(contractName, code, args) {
var contract = this.currentChain.contracts[this.web3.sha3(code + contractName + args.join(','))];
if (contract && contract.address === undefined) { return false; }
return contract;
};
// TODO: abstract this
// chainConfig can be an abstract PersistentObject
DeployTracker.prototype.save = function() {
if (this.chainConfig === false) { return; }
fs.writeJSONSync("./chains.json", this.chainConfig);
};
module.exports = DeployTracker; module.exports = DeployTracker;

View File

@ -1,18 +1,18 @@
var solc; let solc;
process.on('message', function(msg) { process.on('message', function (msg) {
if (msg.action === 'loadCompiler') { if (msg.action === 'loadCompiler') {
solc = require('solc'); solc = require('solc');
process.send({result: "loadedCompiler"}); process.send({result: "loadedCompiler"});
} }
if (msg.action === 'compile') { if (msg.action === 'compile') {
var output = solc.compile(msg.obj, msg.optimize); let output = solc.compile(msg.obj, msg.optimize);
process.send({result: "compilation", output: output}); process.send({result: "compilation", output: output});
} }
}); });
process.on('exit', function() { process.on('exit', function () {
process.exit(0); process.exit(0);
}); });

View File

@ -1,36 +1,38 @@
var utils = require('../core/utils.js'); let utils = require('../utils/utils.js');
var solcProcess; let solcProcess;
var compilerLoaded = false; let compilerLoaded = false;
var SolcW = function() { class SolcW {
};
SolcW.prototype.load_compiler = function(done) { load_compiler(done) {
if (compilerLoaded) { done(); } if (compilerLoaded) {
solcProcess = require('child_process').fork(utils.joinPath(__dirname, '/solcP.js')); done();
solcProcess.once('message', function(msg) {
if (msg.result !== 'loadedCompiler') {
return;
} }
compilerLoaded = true; solcProcess = require('child_process').fork(utils.joinPath(__dirname, '/solcP.js'));
done(); solcProcess.once('message', function (msg) {
}); if (msg.result !== 'loadedCompiler') {
solcProcess.send({action: 'loadCompiler'}); return;
}; }
compilerLoaded = true;
done();
});
solcProcess.send({action: 'loadCompiler'});
}
SolcW.prototype.isCompilerLoaded = function() { isCompilerLoaded() {
return (compilerLoaded === true); return (compilerLoaded === true);
}; }
SolcW.prototype.compile = function(obj, optimize, done) { compile(obj, optimize, done) {
solcProcess.once('message', function(msg) { solcProcess.once('message', function (msg) {
if (msg.result !== 'compilation') { if (msg.result !== 'compilation') {
return; return;
} }
done(msg.output); done(msg.output);
}); });
solcProcess.send({action: 'compile', obj: obj, optimize: optimize}); solcProcess.send({action: 'compile', obj: obj, optimize: optimize});
}; }
}
module.exports = SolcW; module.exports = SolcW;

View File

@ -1,6 +1,6 @@
var fs = require('./fs.js'); var fs = require('./fs.js');
var Plugins = require('./plugins.js'); var Plugins = require('./plugins.js');
var utils = require('./utils.js'); var utils = require('../utils/utils.js');
// TODO: add wrapper for fs so it can also work in the browser // TODO: add wrapper for fs so it can also work in the browser
// can work with both read and save // can work with both read and save

View File

@ -1,5 +1,5 @@
class Core {
var Core = function() {}; }
module.exports = Core; module.exports = Core;

View File

@ -1,151 +1,251 @@
var Events = require('./events.js'); let Web3 = require('web3');
var Logger = require('./logger.js'); let utils = require('../utils/utils.js');
var Config = require('./config.js'); let Events = require('./events.js');
let Logger = require('./logger.js');
let Config = require('./config.js');
let DeployManager = require('../contracts/deploy_manager.js');
let ABIGenerator = require('../contracts/abi.js');
let ServicesMonitor = require('./services_monitor.js');
let Pipeline = require('../pipeline/pipeline.js');
let Server = require('../pipeline/server.js');
let Watch = require('../pipeline/watch.js');
var DeployManager = require('../contracts/deploy_manager.js'); class Engine {
var ABIGenerator = require('../contracts/abi.js'); constructor(options) {
var Dashboard = require('../dashboard/dashboard.js'); this.env = options.env;
var ServicesMonitor = require('./services.js'); this.embarkConfig = options.embarkConfig;
var Pipeline = require('../pipeline/pipeline.js'); this.interceptLogs = options.interceptLogs;
var Server = require('../pipeline/server.js'); this.version = options.version;
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.2";
};
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 init(_options) {
//this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")"); let self = this;
return service.apply(this, [options]); let options = _options || {};
}; this.events = new Events();
this.logger = options.logger || new Logger({logLevel: options.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.monitorService = function(options) { this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger});
var servicesMonitor = new ServicesMonitor({ this.servicesMonitor.addCheck('embarkVersion', function (cb) {
logger: this.logger, return cb({name: 'Embark ' + self.version, status: 'on'});
config: this.config, }, 0);
serverHost: options.serverHost, }
serverPort: options.serverPort,
runWebserver: options.runWebserver,
version: this.version
});
servicesMonitor.startMonitor();
};
Engine.prototype.pipelineService = function(options) { startMonitor() {
var self = this; let self = this;
this.logger.setStatus("Building Assets"); if (this.plugins) {
var pipeline = new Pipeline({ let servicePlugins = this.plugins.getPluginsFor('serviceChecks');
buildDir: this.config.buildDir, servicePlugins.forEach(function (plugin) {
contractsFiles: this.config.contractsFiles, plugin.serviceChecks.forEach(function (pluginCheck) {
assetFiles: this.config.assetFiles, self.servicesMonitor.addCheck(pluginCheck.checkName, pluginCheck.checkFn, pluginCheck.time);
logger: this.logger, });
plugins: this.plugins });
}); }
this.events.on('abi', function(abi) { this.servicesMonitor.startMonitor();
self.currentAbi = abi; }
pipeline.build(abi);
self.events.emit('outputDone');
});
// TODO: still need to redeploy contracts because the original contracts
// config is being corrupted
//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) { startService(serviceName, _options) {
var self = this; let options = _options || {};
var generateABICode = function(contractsManager) {
var abiGenerator = new ABIGenerator({ let services = {
blockchainConfig: self.config.blockchainConfig, "pipeline": this.pipelineService,
contractsManager: contractsManager, "abi": this.abiService,
plugins: self.plugins, "deployment": this.deploymentService,
storageConfig: self.config.storageConfig, "fileWatcher": this.fileWatchService,
communicationConfig: self.config.communicationConfig "webServer": this.webServerService,
"ipfs": this.ipfsService,
"web3": this.web3Service
};
let 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]);
}
pipelineService(options) {
let self = this;
this.logger.setStatus("Building Assets");
let pipeline = new Pipeline({
buildDir: this.config.buildDir,
contractsFiles: this.config.contractsFiles,
assetFiles: this.config.assetFiles,
logger: this.logger,
plugins: this.plugins
}); });
var embarkJSABI = abiGenerator.generateABI({useEmbarkJS: true}); this.events.on('abi', function (abi, contractsJSON) {
var vanillaABI = abiGenerator.generateABI({useEmbarkJS: false}); self.currentAbi = abi;
var vanillaContractsABI = abiGenerator.generateContracts(false); self.contractsJSON = contractsJSON;
pipeline.build(abi, contractsJSON);
self.events.emit('outputDone');
});
// TODO: still need to redeploy contracts because the original contracts
// config is being corrupted
//this.events.on('file-event', function(fileType, path) {
// if (fileType === 'asset') {
// self.config.reloadConfig();
// pipeline.build(self.abi, self.contractsJSON, path);
// self.events.emit('outputDone');
// }
//});
}
self.events.emit('abi-contracts-vanila', vanillaContractsABI); abiService(options) {
self.events.emit('abi-vanila', vanillaABI); let self = this;
self.events.emit('abi', embarkJSABI); let generateABICode = function (contractsManager) {
}; let abiGenerator = new ABIGenerator({
this.events.on('contractsDeployed', generateABICode); blockchainConfig: self.config.blockchainConfig,
this.events.on('blockchainDisabled', generateABICode); contractsManager: contractsManager,
}; plugins: self.plugins,
storageConfig: self.config.storageConfig,
communicationConfig: self.config.communicationConfig
});
let embarkJSABI = abiGenerator.generateABI({useEmbarkJS: true});
let vanillaABI = abiGenerator.generateABI({useEmbarkJS: false});
let vanillaContractsABI = abiGenerator.generateContracts(false);
let contractsJSON = abiGenerator.generateContractsJSON();
Engine.prototype.deploymentService = function(options) { self.events.emit('abi-contracts-vanila', vanillaContractsABI, contractsJSON);
var self = this; self.events.emit('abi-vanila', vanillaABI, contractsJSON);
this.deployManager = new DeployManager({ self.events.emit('abi', embarkJSABI, contractsJSON);
web3: options.web3, };
trackContracts: options.trackContracts, this.events.on('contractsDeployed', generateABICode);
config: this.config, this.events.on('blockchainDisabled', generateABICode);
logger: this.logger, }
plugins: this.plugins,
events: this.events
});
this.events.on('file-event', function(fileType, path) { deploymentService(options) {
// TODO: for now need to deploy on asset chanes as well let self = this;
// because the contractsManager config is corrupted after a deploy this.deployManager = new DeployManager({
//if (fileType === 'contract' || fileType === 'config') { web3: options.web3 || self.web3,
trackContracts: options.trackContracts,
config: this.config,
logger: this.logger,
plugins: this.plugins,
events: this.events
});
this.events.on('file-event', function (fileType, path) {
// TODO: for now need to deploy on asset chanes as well
// because the contractsManager config is corrupted after a deploy
//if (fileType === 'contract' || fileType === 'config') {
self.config.reloadConfig(); self.config.reloadConfig();
self.deployManager.deployContracts(function() {}); self.deployManager.deployContracts(function () {
//} });
}); //}
}; });
}
Engine.prototype.fileWatchService = function(options) { fileWatchService(options) {
this.logger.setStatus("Watching for changes"); this.logger.setStatus("Watching for changes");
var watch = new Watch({logger: this.logger, events: this.events}); let watch = new Watch({logger: this.logger, events: this.events});
watch.start(); watch.start();
}; }
Engine.prototype.webServerService = function(options) { webServerService(options) {
var webServerConfig = this.config.webServerConfig; let self = this;
if (!webServerConfig.enabled) { return; } let webServerConfig = this.config.webServerConfig;
this.logger.setStatus("Starting Server"); if (!webServerConfig.enabled) {
var server = new Server({ return;
logger: this.logger, }
host: options.host || webServerConfig.host,
port: options.port || webServerConfig.port let host = options.host || webServerConfig.host;
}); let port = options.port || webServerConfig.port;
server.start(function(){});
}; this.logger.setStatus("Starting Server");
let server = new Server({
logger: this.logger,
host: host,
port: port
});
self.servicesMonitor.addCheck('Webserver', function (cb) {
let devServer = 'Webserver (http://' + host + ':' + port + ')';
return cb({name: devServer, status: 'on'});
});
server.start(function () {
});
}
ipfsService(options) {
let self = this;
self.servicesMonitor.addCheck('IPFS', function (cb) {
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...");
utils.httpGet('http://localhost:5001/api/v0/version', function (res) {
let body = '';
res.on('data', function (d) {
body += d;
});
res.on('end', function () {
try {
let parsed = JSON.parse(body);
if (parsed.Version) {
return cb({name: ("IPFS " + parsed.Version), status: 'on'});
}
else {
return cb({name: "IPFS ", status: 'on'});
}
}
catch (e) {
return cb({name: "IPFS ", status: 'off'});
}
});
res.on('error', function (err) {
self.logger.trace("Check IPFS version error: " + err);
return cb({name: "IPFS ", status: 'off'});
});
});
}
else {
return cb({name: "IPFS ", status: 'off'});
}
});
});
}
web3Service(options) {
let self = this;
this.web3 = options.web3;
if (this.web3 === undefined) {
this.web3 = new Web3();
let web3Endpoint = 'http://' + this.config.blockchainConfig.rpcHost + ':' + this.config.blockchainConfig.rpcPort;
this.web3.setProvider(new this.web3.providers.HttpProvider(web3Endpoint));
}
self.servicesMonitor.addCheck('Ethereum', function (cb) {
if (self.web3.isConnected()) {
return cb({
name: (self.web3.version.node.split("/")[0] + " " + self.web3.version.node.split("/")[1].split("-")[0] + " (Ethereum)"),
status: 'on'
});
} else {
return cb({name: "No Blockchain node found", status: 'off'});
}
});
self.servicesMonitor.addCheck('Whisper', function (cb) {
self.web3.version.getWhisper(function (err, version) {
if (err) {
return cb({name: 'Whisper', status: 'off'});
} else if (version >= 5) {
return cb({name: 'Whisper (version ' + version + ') - unsupported', status: 'warn'});
} else {
return cb({name: 'Whisper (version ' + version + ')', status: 'on'});
}
});
});
}
}
module.exports = Engine; module.exports = Engine;

View File

@ -1,5 +1,5 @@
var fs = require('fs-extra'); let fs = require('fs-extra');
var utils = require('./utils.js'); let utils = require('../utils/utils.js');
function mkdirpSync() { function mkdirpSync() {
return fs.mkdirpSync.apply(fs.mkdirpSync, arguments); return fs.mkdirpSync.apply(fs.mkdirpSync, arguments);
@ -25,7 +25,7 @@ function writeJSONSync() {
return fs.writeJSONSync.apply(fs.writeJSONSync, arguments); return fs.writeJSONSync.apply(fs.writeJSONSync, arguments);
} }
function existsSync(){ function existsSync() {
return fs.existsSync.apply(fs.existsSync, arguments); return fs.existsSync.apply(fs.existsSync, arguments);
} }

View File

@ -1,40 +1,52 @@
var colors = require('colors'); let colors = require('colors');
var Logger = function(options) { class Logger {
this.logLevels = ['error', 'warn', 'info', 'debug', 'trace']; constructor(options) {
this.logLevel = options.logLevel || 'info'; this.logLevels = ['error', 'warn', 'info', 'debug', 'trace'];
this.logFunction = options.logFunction || console.log; this.logLevel = options.logLevel || 'info';
this.contractsState = options.contractsState || function() {}; this.logFunction = options.logFunction || console.log;
this.availableServices = options.availableServices || function() {}; this.contractsState = options.contractsState || function () {
this.setStatus = options.setStatus || console.log; };
}; this.setStatus = options.setStatus || console.log;
}
}
Logger.prototype.error = function(txt) { Logger.prototype.error = function (txt) {
if (!(this.shouldLog('error'))) { return; } if (!txt || !(this.shouldLog('error'))) {
return;
}
this.logFunction(txt.red); this.logFunction(txt.red);
}; };
Logger.prototype.warn = function(txt) { Logger.prototype.warn = function (txt) {
if (!(this.shouldLog('warn'))) { return; } if (!txt || !(this.shouldLog('warn'))) {
return;
}
this.logFunction(txt.yellow); this.logFunction(txt.yellow);
}; };
Logger.prototype.info = function(txt) { Logger.prototype.info = function (txt) {
if (!(this.shouldLog('info'))) { return; } if (!txt || !(this.shouldLog('info'))) {
return;
}
this.logFunction(txt.green); this.logFunction(txt.green);
}; };
Logger.prototype.debug = function(txt) { Logger.prototype.debug = function (txt) {
if (!(this.shouldLog('debug'))) { return; } if (!txt || !(this.shouldLog('debug'))) {
return;
}
this.logFunction(txt); this.logFunction(txt);
}; };
Logger.prototype.trace = function(txt) { Logger.prototype.trace = function (txt) {
if (!(this.shouldLog('trace'))) { return; } if (!txt || !(this.shouldLog('trace'))) {
return;
}
this.logFunction(txt); this.logFunction(txt);
}; };
Logger.prototype.shouldLog = function(level) { Logger.prototype.shouldLog = function (level) {
return (this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel)); return (this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel));
}; };

View File

@ -1,6 +1,6 @@
/*jshint esversion: 6, loopfunc: true */ /*jshint esversion: 6, loopfunc: true */
var fs = require('./fs.js'); var fs = require('./fs.js');
var utils = require('./utils.js'); var utils = require('../utils/utils.js');
// TODO: pass other params like blockchainConfig, contract files, etc.. // TODO: pass other params like blockchainConfig, contract files, etc..
var Plugin = function(options) { var Plugin = function(options) {
@ -17,6 +17,7 @@ var Plugin = function(options) {
this.contractsConfigs = []; this.contractsConfigs = [];
this.contractsFiles = []; this.contractsFiles = [];
this.compilers = []; this.compilers = [];
this.serviceChecks = [];
this.pluginTypes = []; this.pluginTypes = [];
this.logger = options.logger; this.logger = options.logger;
this.events = options.events; this.events = options.events;
@ -98,6 +99,11 @@ Plugin.prototype.registerConsoleCommand = function(cb) {
this.pluginTypes.push('console'); this.pluginTypes.push('console');
}; };
Plugin.prototype.registerServiceCheck = function(checkName, checkFn, time) {
this.serviceChecks.push({checkName: checkName, checkFn: checkFn, time: time});
this.pluginTypes.push('serviceChecks');
};
Plugin.prototype.has = function(pluginType) { Plugin.prototype.has = function(pluginType) {
return this.pluginTypes.indexOf(pluginType) >= 0; return this.pluginTypes.indexOf(pluginType) >= 0;
}; };

View File

@ -1,5 +1,5 @@
var Plugin = require('./plugin.js'); var Plugin = require('./plugin.js');
var utils = require('./utils.js'); var utils = require('../utils/utils.js');
var Plugins = function(options) { var Plugins = function(options) {
this.pluginList = options.plugins || []; this.pluginList = options.plugins || [];

View File

@ -1,5 +1,5 @@
var Web3 = require('web3'); let Web3 = require('web3');
var web3; let web3;
// ====================== // ======================
// the eval is used for evaluating some of the contact calls for different purposes // the eval is used for evaluating some of the contact calls for different purposes

View File

@ -1,113 +0,0 @@
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;

View File

@ -0,0 +1,80 @@
let async = require('../utils/async_extend.js');
class ServicesMonitor {
constructor(options) {
this.events = options.events;
this.logger = options.logger;
this.checkList = {};
this.checkTimers = {};
this.checkState = {};
this.working = false;
}
}
ServicesMonitor.prototype.initCheck = function (checkName) {
let self = this;
let check = this.checkList[checkName];
if (!check) {
return false;
}
self.events.on('check:' + checkName, function (obj) {
if (check && check.status === 'off' && obj.status === 'on') {
self.events.emit('check:backOnline:' + checkName);
}
if (check && check.status === 'on' && obj.status === 'off') {
self.events.emit('check:wentOffline:' + checkName);
}
self.checkState[checkName] = {name: obj.name, status: obj.status};
check.status = obj.status;
self.events.emit("servicesState", self.checkState);
});
if (check.interval !== 0) {
self.checkTimers[checkName] = setInterval(function () {
check.fn.call(check.fn, function (obj) {
self.events.emit('check:' + checkName, obj);
});
}, check.interval);
}
check.fn.call(check.fn, function (obj) {
self.events.emit('check:' + checkName, obj);
});
};
ServicesMonitor.prototype.addCheck = function (checkName, checkFn, time) {
let self = this;
this.logger.trace('add check: ' + checkName);
this.checkList[checkName] = {fn: checkFn, interval: time || 5000};
if (this.working) {
this.initCheck(checkName);
}
};
ServicesMonitor.prototype.stopCheck = function (name) {
clearInterval(this.checkTimers[name]);
delete this.checkTimers[name];
delete this.checkList[name];
delete this.checkState[name];
};
ServicesMonitor.prototype.startMonitor = function () {
let self = this;
this.working = true;
this.logger.trace('startMonitor');
async.eachObject(this.checkList, function (checkName, check, callback) {
self.initCheck(checkName);
callback();
}, function (err) {
if (err) {
self.logger.error("error running service check");
self.logger.error(err.message);
}
});
};
module.exports = ServicesMonitor;

View File

@ -12,6 +12,7 @@ var Deploy = require('../contracts/deploy.js');
var Config = require('./config.js'); var Config = require('./config.js');
var RunCode = require('./runCode.js'); var RunCode = require('./runCode.js');
var TestLogger = require('./test_logger.js'); var TestLogger = require('./test_logger.js');
var web3;
var getSimulator = function() { var getSimulator = function() {
try { try {
@ -45,7 +46,7 @@ var Test = function(options) {
}); });
this.engine.init({ this.engine.init({
logger: new TestLogger({logLevel: this.options.logLevel || 'debug'}) logger: new TestLogger({logLevel: 'debug'})
}); });
this.sim = getSimulator(); this.sim = getSimulator();

View File

@ -1,52 +1,65 @@
var colors = require('colors'); let colors = require('colors');
// TODO: just logFunction changes, probably doesn't need a whole new module just // TODO: just logFunction changes, probably doesn't need a whole new module just
// for this // for this
var TestLogger = function(options) { class TestLogger {
this.logLevels = ['error', 'warn', 'info', 'debug', 'trace']; constructor(options) {
this.logs = []; this.logLevels = ['error', 'warn', 'info', 'debug', 'trace'];
this.logLevel = options.logLevel || 'info'; this.logs = [];
}; this.logLevel = options.logLevel || 'info';
}
TestLogger.prototype.logFunction = function() { logFunction() {
this.logs.push(arguments); this.logs.push(arguments);
}; }
TestLogger.prototype.contractsState = function() { contractsState() {
this.logs.push(arguments); this.logs.push(arguments);
}; }
TestLogger.prototype.availableServices = function() { availableServices() {
this.logs.push(arguments); this.logs.push(arguments);
}; }
TestLogger.prototype.error = function(txt) { error(txt) {
if (!(this.shouldLog('error'))) { return; } if (!(this.shouldLog('error'))) {
this.logFunction(txt.red); return;
}; }
this.logFunction(txt.red);
}
TestLogger.prototype.warn = function(txt) { warn(txt) {
if (!(this.shouldLog('warn'))) { return; } if (!(this.shouldLog('warn'))) {
this.logFunction(txt.yellow); return;
}; }
this.logFunction(txt.yellow);
}
TestLogger.prototype.info = function(txt) { info(txt) {
if (!(this.shouldLog('info'))) { return; } if (!(this.shouldLog('info'))) {
this.logFunction(txt.green); return;
}; }
this.logFunction(txt.green);
}
TestLogger.prototype.debug = function(txt) { debug(txt) {
if (!(this.shouldLog('debug'))) { return; } if (!(this.shouldLog('debug'))) {
this.logFunction(txt); return;
}; }
this.logFunction(txt);
}
TestLogger.prototype.trace = function(txt) { trace(txt) {
if (!(this.shouldLog('trace'))) { return; } if (!(this.shouldLog('trace'))) {
this.logFunction(txt); return;
}; }
this.logFunction(txt);
}
TestLogger.prototype.shouldLog = function(level) { shouldLog(level) {
return (this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel)); return (this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel));
}; }
}
module.exports = TestLogger; module.exports = TestLogger;

View File

@ -1,28 +1,29 @@
class CommandHistory {
var CommandHistory = function() { constructor() {
this.history = []; this.history = [];
this.pointer = -1; 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) { addCommand(cmd) {
if (this.pointer >= this.history.length) { this.history.push(cmd);
this.pointer = this.history.length - 1; this.pointer = this.history.length;
return '';
} }
this.pointer++;
return this.history[this.pointer]; getPreviousCommand(cmd) {
}; if (this.pointer >= 0) {
this.pointer--;
}
return this.history[this.pointer];
}
getNextCommand(cmd) {
if (this.pointer >= this.history.length) {
this.pointer = this.history.length - 1;
return '';
}
this.pointer++;
return this.history[this.pointer];
}
}
module.exports = CommandHistory; module.exports = CommandHistory;

View File

@ -1,60 +1,62 @@
var utils = require('../core/utils.js'); let utils = require('../utils/utils.js');
var RunCode = require('../core/runCode.js'); let RunCode = require('../core/runCode.js');
var Console = function(options) { class Console {
this.plugins = options.plugins; constructor(options) {
this.version = options.version; 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); runCode(code) {
if (output) { RunCode.doEval(code); // jshint ignore:line
return callback(output);
} }
try { processEmbarkCmd (cmd) {
var result = RunCode.doEval(cmd); if (cmd === 'help') {
return callback(result); let 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;
} }
catch(e) {
if (e.message.indexOf('not defined') > 0) { executeCmd(cmd, callback) {
return callback(("error: " + e.message).red + ("\nType " + "help".bold + " to see the list of available commands").cyan); var plugin, pluginOutput;
} else { var plugins = this.plugins.getPluginsFor('console');
return callback(e.message); for (var i = 0; i < plugins.length; i++) {
plugin = plugins[i];
pluginOutput = plugin.runCommands(cmd, {});
if (pluginOutput !== false && pluginOutput !== 'false') return callback(pluginOutput);
}
let output = this.processEmbarkCmd(cmd);
if (output) {
return callback(output);
}
try {
let 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; module.exports = Console;

View File

@ -1,43 +1,45 @@
var async = require('async'); let async = require('async');
var Monitor = require('./monitor.js'); let Monitor = require('./monitor.js');
var Console = require('./console.js'); let Console = require('./console.js');
var Dashboard = function(options) { class Dashboard {
this.logger = options.logger; constructor(options) {
this.plugins = options.plugins; this.logger = options.logger;
this.version = options.version; this.plugins = options.plugins;
this.env = options.env; this.version = options.version;
}; this.env = options.env;
}
Dashboard.prototype.start = function(done) { start(done) {
var console, monitor; let console, monitor;
var self = this; let self = this;
async.waterfall([ async.waterfall([
function startConsole(callback) { function startConsole(callback) {
console = new Console({plugins: self.plugins, version: self.version}); console = new Console({plugins: self.plugins, version: self.version});
callback(); callback();
}, },
function startMonitor(callback) { function startMonitor(callback) {
monitor = new Monitor({env: self.env, console: console}); monitor = new Monitor({env: self.env, console: console});
self.logger.logFunction = monitor.logEntry; self.logger.logFunction = monitor.logEntry;
self.logger.contractsState = monitor.setContracts; self.logger.contractsState = monitor.setContracts;
self.logger.availableServices = monitor.availableServices; self.logger.setStatus = monitor.setStatus.bind(monitor);
self.logger.setStatus = monitor.setStatus.bind(monitor);
self.logger.info('========================'.bold.green); self.logger.info('========================'.bold.green);
self.logger.info(('Welcome to Embark ' + self.version).yellow.bold); self.logger.info(('Welcome to Embark ' + self.version).yellow.bold);
self.logger.info('========================'.bold.green); self.logger.info('========================'.bold.green);
// TODO: do this after monitor is rendered // TODO: do this after monitor is rendered
callback(); callback();
} }
], function() { ], function () {
self.console = console; self.console = console;
self.monitor = monitor; self.monitor = monitor;
done(); done();
}); });
}; }
}
module.exports = Dashboard; module.exports = Dashboard;

View File

@ -1,348 +1,365 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
var blessed = require("blessed"); let blessed = require("blessed");
var CommandHistory = require('./command_history.js'); let CommandHistory = require('./command_history.js');
function Dashboard(options) { class Dashboard {
var title = (options && options.title) || "Embark 2.4.2"; constructor(options) {
this.env = options.env; let title = (options && options.title) || "Embark " + options.version;
this.console = options.console; this.env = options.env;
this.history = new CommandHistory(); this.console = options.console;
this.history = new CommandHistory();
this.color = (options && options.color) || "green"; this.color = (options && options.color) || "green";
this.minimal = (options && options.minimal) || false; this.minimal = (options && options.minimal) || false;
this.screen = blessed.screen({ this.screen = blessed.screen({
smartCSR: true, smartCSR: true,
title: title, title: title,
dockBorders: false, dockBorders: false,
fullUnicode: true, fullUnicode: true,
autoPadding: true autoPadding: true
}); });
this.layoutLog(); this.layoutLog();
this.layoutStatus(); this.layoutStatus();
this.layoutModules(); this.layoutModules();
this.layoutCmd(); this.layoutCmd();
this.screen.key(["C-c"], function() { this.screen.key(["C-c"], function () {
process.exit(0); process.exit(0);
}); });
this.logEntry = this.logEntry.bind(this); this.logEntry = this.logEntry.bind(this);
this.setContracts = this.setContracts.bind(this); this.setContracts = this.setContracts.bind(this);
this.availableServices = this.availableServices.bind(this); this.availableServices = this.availableServices.bind(this);
this.status.setContent(this.env.green); this.status.setContent(this.env.green);
this.screen.render();
this.input.focus();
}
availableServices(_services) {
let services = [];
let check;
for (check in _services) {
let checkObj = _services[check];
if (checkObj.status === 'on') {
services.push(checkObj.name.green);
} else if (checkObj.status === 'off') {
services.push(checkObj.name.red);
} else if (checkObj.status === 'warn') {
services.push(checkObj.name.grey);
} else {
services.push(checkObj.name);
}
}
this.progress.setContent(services.join('\n'));
this.screen.render();
}
setStatus(status) {
this.operations.setContent(status);
this.screen.render();
}
setContracts(contracts) {
let data = [];
data.push(["Contract Name", "Address", "Status"]);
contracts.forEach(function (row) {
data.push(row);
});
this.moduleTable.setData(data);
this.screen.render();
}
logEntry(text) {
this.logText.log(text);
this.screen.render();
}
layoutLog() {
this.log = blessed.box({
label: "Logs",
padding: 1,
width: "100%",
height: "55%",
left: "0%",
top: "42%",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.logText = blessed.log({
parent: this.log,
tags: true,
width: "100%-5",
//height: '90%',
scrollable: true,
input: false,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true
});
this.screen.append(this.log);
}
layoutModules() {
this.modules = blessed.box({
label: "Contracts",
tags: true,
padding: 1,
width: "75%",
height: "42%",
left: "0%",
top: "0",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.moduleTable = blessed.table({
parent: this.modules,
height: "100%",
width: "100%-5",
align: "left",
pad: 1,
margin: "auto",
shrink: true,
scrollable: true,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true,
data: [["ContractName", "Address", "Status"]]
});
this.screen.append(this.modules);
}
layoutAssets() {
this.assets = blessed.box({
label: "Asset Pipeline",
tags: true,
padding: 1,
width: "50%",
height: "55%",
left: "50%",
top: "42%",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.assetTable = blessed.table({
parent: this.assets,
height: "100%",
width: "100%-5",
align: "left",
pad: 1,
scrollable: true,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true,
data: [["Name", "Size"]]
});
this.screen.append(this.assets);
}
layoutStatus() {
this.wrapper = blessed.layout({
width: "25%",
height: "42%",
top: "0%",
left: "75%",
layout: "grid"
});
this.status = blessed.box({
parent: this.wrapper,
label: "Environment",
tags: true,
padding: {
left: 1
},
width: "100%",
height: "20%",
valign: "middle",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.operations = blessed.box({
parent: this.wrapper,
label: "Status",
tags: true,
padding: {
left: 1
},
width: "100%",
height: "20%",
valign: "middle",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.progress = blessed.box({
parent: this.wrapper,
label: "Available Services",
tags: true,
padding: this.minimal ? {
left: 1
} : 1,
width: "100%",
height: "60%",
valign: "top",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.screen.append(this.wrapper);
}
layoutCmd() {
this.consoleBox = blessed.box({
label: 'Console',
tags: true,
padding: 0,
width: '100%',
height: '6%',
left: '0%',
top: '95%',
border: {
type: 'line'
},
style: {
fg: 'black',
border: {
fg: this.color
}
}
});
this.input = blessed.textbox({
parent: this.consoleBox,
name: 'input',
input: true,
keys: false,
top: 0,
left: 1,
height: '50%',
width: '100%-2',
inputOnFocus: true,
style: {
fg: 'green',
bg: 'black',
focus: {
bg: 'black',
fg: 'green'
}
}
});
let self = this;
this.input.key(["C-c"], function () {
process.exit(0);
});
this.input.key(["C-w"], function () {
self.input.clearValue();
self.input.focus();
});
this.input.key(["up"], function () {
let cmd = self.history.getPreviousCommand();
self.input.setValue(cmd);
self.input.focus();
});
this.input.key(["down"], function () {
let cmd = self.history.getNextCommand();
self.input.setValue(cmd);
self.input.focus();
});
this.input.on('submit', function (data) {
if (data !== '') {
self.history.addCommand(data);
self.logText.log('console> '.bold.green + data);
self.console.executeCmd(data, function (result) {
self.logText.log(result);
});
}
self.input.clearValue();
self.input.focus();
});
this.screen.append(this.consoleBox);
}
this.screen.render();
this.input.focus();
} }
Dashboard.prototype.availableServices = function(services) {
this.progress.setContent(services.join('\n'));
this.screen.render();
};
Dashboard.prototype.setStatus = function(status) {
this.operations.setContent(status);
this.screen.render();
};
Dashboard.prototype.setContracts = function(contracts) {
var data = [];
data.push(["Contract Name", "Address", "Status"]);
contracts.forEach(function(row) {
data.push(row);
});
this.moduleTable.setData(data);
this.screen.render();
};
Dashboard.prototype.logEntry = function(text) {
this.logText.log(text);
this.screen.render();
};
Dashboard.prototype.layoutLog = function() {
this.log = blessed.box({
label: "Logs",
padding: 1,
width: "100%",
height: "55%",
left: "0%",
top: "42%",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.logText = blessed.log({
parent: this.log,
tags: true,
width: "100%-5",
//height: '90%',
scrollable: true,
input: false,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true
});
this.screen.append(this.log);
};
Dashboard.prototype.layoutModules = function() {
this.modules = blessed.box({
label: "Contracts",
tags: true,
padding: 1,
width: "75%",
height: "42%",
left: "0%",
top: "0",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.moduleTable = blessed.table({
parent: this.modules,
height: "100%",
width: "100%-5",
align: "left",
pad: 1,
margin: "auto",
shrink: true,
scrollable: true,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true,
data: [["ContractName", "Address", "Status"]]
});
this.screen.append(this.modules);
};
Dashboard.prototype.layoutAssets = function() {
this.assets = blessed.box({
label: "Asset Pipeline",
tags: true,
padding: 1,
width: "50%",
height: "55%",
left: "50%",
top: "42%",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.assetTable = blessed.table({
parent: this.assets,
height: "100%",
width: "100%-5",
align: "left",
pad: 1,
scrollable: true,
alwaysScroll: true,
scrollbar: {
ch: " ",
inverse: true
},
keys: false,
vi: false,
mouse: true,
data: [["Name", "Size"]]
});
this.screen.append(this.assets);
};
Dashboard.prototype.layoutStatus = function() {
this.wrapper = blessed.layout({
width: "25%",
height: "42%",
top: "0%",
left: "75%",
layout: "grid"
});
this.status = blessed.box({
parent: this.wrapper,
label: "Environment",
tags: true,
padding: {
left: 1
},
width: "100%",
height: "20%",
valign: "middle",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.operations = blessed.box({
parent: this.wrapper,
label: "Status",
tags: true,
padding: {
left: 1
},
width: "100%",
height: "20%",
valign: "middle",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.progress = blessed.box({
parent: this.wrapper,
label: "Available Services",
tags: true,
padding: this.minimal ? {
left: 1
} : 1,
width: "100%",
height: "60%",
valign: "top",
border: {
type: "line"
},
style: {
fg: -1,
border: {
fg: this.color
}
}
});
this.screen.append(this.wrapper);
};
Dashboard.prototype.layoutCmd = function() {
this.consoleBox = blessed.box({
label: 'Console',
tags: true,
padding: 0,
width: '100%',
height: '6%',
left: '0%',
top: '95%',
border: {
type: 'line'
},
style: {
fg: 'black',
border: {
fg: this.color
}
}
});
this.input = blessed.textbox({
parent: this.consoleBox,
name: 'input',
input: true,
keys: false,
top: 0,
left: 1,
height: '50%',
width: '100%-2',
inputOnFocus: true,
style: {
fg: 'green',
bg: 'black',
focus: {
bg: 'black',
fg: 'green'
}
}
});
var self = this;
this.input.key(["C-c"], function() {
process.exit(0);
});
this.input.key(["C-w"], function() {
self.input.clearValue();
self.input.focus();
});
this.input.key(["up"], function() {
var cmd = self.history.getPreviousCommand();
self.input.setValue(cmd);
self.input.focus();
});
this.input.key(["down"], function() {
var cmd = self.history.getNextCommand();
self.input.setValue(cmd);
self.input.focus();
});
this.input.on('submit', function(data) {
if (data !== '') {
self.history.addCommand(data);
self.logText.log('console> '.bold.green + data);
self.console.executeCmd(data, function(result) {
self.logText.log(result);
});
}
self.input.clearValue();
self.input.focus();
});
this.screen.append(this.consoleBox);
};
module.exports = Dashboard; module.exports = Dashboard;

View File

@ -1,74 +1,68 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
var async = require('async'); let async = require('async');
//require("./core/debug_util.js")(__filename, async); // require("./utils/debug_util.js")(__filename, async);
var Web3 = require('web3'); let colors = require('colors');
var colors = require('colors');
var Engine = require('./core/engine.js'); let Engine = require('./core/engine.js');
var Blockchain = require('./cmds/blockchain/blockchain.js'); let IPFS = require('./upload/ipfs.js');
var Simulator = require('./cmds/simulator.js'); let Swarm = require('./upload/swarm.js');
var TemplateGenerator = require('./cmds/template_generator.js');
var Test = require('./core/test.js'); let version = require('../package.json').version;
var Logger = require('./core/logger.js');
var Config = require('./core/config.js');
var Events = require('./core/events.js');
var Dashboard = require('./dashboard/dashboard.js'); class Embark {
var IPFS = require('./upload/ipfs.js'); constructor (options) {
var Swarm = require('./upload/swarm.js'); this.version = version;
this.options = options || {};
}
var Cmd = require('./cmd.js'); initConfig(env, options) {
let Events = require('./core/events.js');
let Logger = require('./core/logger.js');
let Config = require('./core/config.js');
var Embark = {
version: '2.4.2',
process: function(args) {
var cmd = new Cmd(Embark);
cmd.process(args);
},
initConfig: function(env, options) {
this.events = new Events(); this.events = new Events();
this.logger = new Logger({logLevel: 'debug'}); this.logger = new Logger({logLevel: 'debug'});
this.config = new Config({env: env, logger: this.logger, events: this.events}); this.config = new Config({env: env, logger: this.logger, events: this.events});
this.config.loadConfigFiles(options); this.config.loadConfigFiles(options);
this.plugins = this.config.plugins; this.plugins = this.config.plugins;
}, }
blockchain: function(env, client) { blockchain(env, client) {
var blockchain = Blockchain(this.config.blockchainConfig, client, env); return require('./cmds/blockchain/blockchain.js')(this.config.blockchainConfig, client, env).run();
blockchain.run(); }
},
simulator: function(options) { simulator(options) {
var simulator = new Simulator({blockchainConfig: this.config.blockchainConfig}); let Simulator = require('./cmds/simulator.js');
let simulator = new Simulator({blockchainConfig: this.config.blockchainConfig});
simulator.run(options); simulator.run(options);
}, }
generateTemplate: function(templateName, destinationFolder, name) { generateTemplate(templateName, destinationFolder, name) {
var templateGenerator = new TemplateGenerator(templateName); let TemplateGenerator = require('./cmds/template_generator.js');
let templateGenerator = new TemplateGenerator(templateName);
templateGenerator.generate(destinationFolder, name); templateGenerator.generate(destinationFolder, name);
}, }
run: function(options) { run(options) {
var self = this; let self = this;
var env = options.env; let Dashboard = require('./dashboard/dashboard.js');
var engine = new Engine({ let env = options.env;
let engine = new Engine({
env: options.env, env: options.env,
embarkConfig: 'embark.json' version: this.version,
embarkConfig: options.embarkConfig || 'embark.json'
}); });
engine.init(); engine.init();
if (!options.useDashboard) { if (!options.useDashboard) {
console.log('========================'.bold.green); console.log('========================'.bold.green);
console.log(('Welcome to Embark ' + Embark.version).yellow.bold); console.log(('Welcome to Embark ' + this.version).yellow.bold);
console.log('========================'.bold.green); console.log('========================'.bold.green);
} }
@ -78,38 +72,47 @@ var Embark = {
return callback(); return callback();
} }
var dashboard = new Dashboard({ let dashboard = new Dashboard({
logger: engine.logger, logger: engine.logger,
plugins: engine.plugins, plugins: engine.plugins,
version: engine.version, version: self.version,
env: engine.env env: engine.env
}); });
dashboard.start(function() { dashboard.start(function () {
engine.events.on('abi-vanila', function(abi) { engine.events.on('abi-vanila', function (abi) {
dashboard.console.runCode(abi); dashboard.console.runCode(abi);
}); });
engine.logger.info('dashboard start');
engine.events.on('servicesState', function (servicesState) {
dashboard.monitor.availableServices(servicesState);
});
callback(); callback();
}); });
}, },
function (callback) { function (callback) {
var pluginList = engine.plugins.listPlugins(); let pluginList = engine.plugins.listPlugins();
if (pluginList.length > 0) { if (pluginList.length > 0) {
engine.logger.info("loaded plugins: " + pluginList.join(", ")); engine.logger.info("loaded plugins: " + pluginList.join(", "));
} }
if (options.useDashboard) { engine.startMonitor();
engine.startService("monitor", { engine.startService("web3");
serverHost: options.serverHost,
serverPort: options.serverPort,
runWebserver: options.runWebserver
});
}
engine.startService("pipeline"); engine.startService("pipeline");
engine.startService("abi"); engine.startService("abi");
engine.startService("deployment"); engine.startService("deployment");
engine.startService("ipfs");
engine.deployManager.deployContracts(function() { engine.events.on('check:backOnline:Ethereum', function () {
engine.logger.info('Ethereum node detected..');
engine.config.reloadConfig();
engine.deployManager.deployContracts(function () {
engine.logger.info('Deployment Done');
});
});
engine.deployManager.deployContracts(function (err) {
engine.startService("fileWatcher"); engine.startService("fileWatcher");
if (options.runWebserver) { if (options.runWebserver) {
engine.startService("webServer", { engine.startService("webServer", {
@ -117,12 +120,13 @@ var Embark = {
port: options.serverPort port: options.serverPort
}); });
} }
callback(); callback(err);
}); });
} }
], function(err, result) { ], function (err, result) {
if (err) { if (err) {
engine.logger.error(err.message); engine.logger.error(err.message);
engine.logger.info(err.stack);
} else { } else {
engine.logger.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("Looking for documentation? you can find it at ".cyan + "http://embark.readthedocs.io/".green.underline);
@ -130,13 +134,13 @@ var Embark = {
engine.events.emit('firstDeploymentDone'); engine.events.emit('firstDeploymentDone');
} }
}); });
}, }
build: function(options) { build(options) {
var self = this;
var engine = new Engine({ let engine = new Engine({
env: options.env, env: options.env,
version: this.version,
embarkConfig: 'embark.json', embarkConfig: 'embark.json',
interceptLogs: false interceptLogs: false
}); });
@ -144,43 +148,46 @@ var Embark = {
async.waterfall([ async.waterfall([
function startServices(callback) { function startServices(callback) {
var pluginList = engine.plugins.listPlugins(); let pluginList = engine.plugins.listPlugins();
if (pluginList.length > 0) { if (pluginList.length > 0) {
engine.logger.info("loaded plugins: " + pluginList.join(", ")); engine.logger.info("loaded plugins: " + pluginList.join(", "));
} }
engine.startService("web3");
engine.startService("pipeline"); engine.startService("pipeline");
engine.startService("abi"); engine.startService("abi");
engine.startService("deployment"); engine.startService("deployment");
callback(); callback();
}, },
function deploy(callback) { function deploy(callback) {
engine.deployManager.deployContracts(function() { engine.deployManager.deployContracts(function (err) {
callback(); callback(err);
}); });
} }
], function(err, result) { ], function (err, result) {
if (err) { if (err) {
engine.logger.error(err.message); engine.logger.error(err.message);
engine.logger.debug(err.stack);
} else { } else {
engine.logger.info("finished building".underline); engine.logger.info("finished building".underline);
} }
// needed due to child processes // needed due to child processes
process.exit(); process.exit();
}); });
}, }
initTests: function(options) { initTests(options) {
let Test = require('./core/test.js');
return new Test(options); return new Test(options);
}, }
// TODO: should deploy if it hasn't already // TODO: should deploy if it hasn't already
upload: function(platform) { upload(platform) {
if (platform === 'ipfs') { if (platform === 'ipfs') {
var ipfs = new IPFS({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig}); let ipfs = new IPFS({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig});
ipfs.deploy(); ipfs.deploy();
} else if (platform === 'swarm') { } else if (platform === 'swarm') {
var swarm = new Swarm({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig}); let swarm = new Swarm({buildDir: 'dist/', plugins: this.plugins, storageConfig: this.config.storageConfig});
swarm.deploy(); swarm.deploy();
} else { } else {
console.log(("unknown platform: " + platform).red); console.log(("unknown platform: " + platform).red);
@ -188,7 +195,12 @@ var Embark = {
} }
} }
}
// temporary until next refactor
Embark.initTests = function(options) {
let Test = require('./core/test.js');
return new Test(options);
}; };
module.exports = Embark; module.exports = Embark;

View File

@ -1,80 +1,94 @@
/*jshint esversion: 6, loopfunc: true */ /*jshint esversion: 6, loopfunc: true */
var fs = require('../core/fs.js'); let fs = require('../core/fs.js');
var Pipeline = function(options) { class Pipeline {
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) { constructor(options) {
var self = this; this.buildDir = options.buildDir;
for(var targetFile in this.assetFiles) { this.contractsFiles = options.contractsFiles;
this.assetFiles = options.assetFiles;
this.logger = options.logger;
this.plugins = options.plugins;
}
var contentFiles = this.assetFiles[targetFile].map(file => { build(abi, contractsJSON, path) {
self.logger.trace("reading " + file.filename); let self = this;
for (let targetFile in this.assetFiles) {
var pipelinePlugins = this.plugins.getPluginsFor('pipeline'); let contentFiles = this.assetFiles[targetFile].map(file => {
self.logger.trace("reading " + file.filename);
if (file.filename === 'embark.js') { let pipelinePlugins = this.plugins.getPluginsFor('pipeline');
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) { if (file.filename === 'embark.js') {
pipelinePlugins.forEach(function(plugin) { return {content: file.content + "\n" + abi, filename: file.filename, path: file.path, modified: true};
try { } else if (file.filename === 'abi.js') {
if (file.options && file.options.skipPipeline) { return {content: abi, filename: file.filename, path: file.path, modified: true};
return; } 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;
} }
file.content = plugin.runPipeline({targetFile: file.filename, source: file.content}); catch (err) {
file.modified = true; self.logger.error(err.message);
} }
catch(err) { });
self.logger.error(err.message); }
}
}); return file;
}
});
let 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) {
let targetDir = targetFile;
if (targetDir.slice(-1) !== '/') {
targetDir = targetDir + '/';
} }
return file; contentFiles.map(function (file) {
let 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 {
let 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);
} }
}); }
var dir = targetFile.split('/').slice(0, -1).join('/'); this.buildContracts(contractsJSON);
self.logger.trace("creating dir " + this.buildDir + dir); }
fs.mkdirpSync(this.buildDir + dir);
// if it's a directory buildContracts(contractsJSON) {
if (targetFile.slice(-1) === '/' || targetFile.indexOf('.') === -1) { fs.mkdirpSync(this.buildDir + 'contracts');
var targetDir = targetFile;
if (targetDir.slice(-1) !== '/') { for (let className in contractsJSON) {
targetDir = targetDir + '/'; let contract = contractsJSON[className];
} fs.writeJSONSync(this.buildDir + 'contracts/' + className + ".json", contract, {spaces: 2});
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; module.exports = Pipeline;

View File

@ -1,24 +1,27 @@
var finalhandler = require('finalhandler'); let finalhandler = require('finalhandler');
var http = require('http'); let http = require('http');
var serveStatic = require('serve-static'); let serveStatic = require('serve-static');
var Server = function(options) { class Server {
this.dist = options.dist || 'dist/'; constructor(options) {
this.port = options.port || 8000; this.dist = options.dist || 'dist/';
this.hostname = options.host || 'localhost'; this.port = options.port || 8000;
this.logger = options.logger; this.hostname = options.host || 'localhost';
}; this.logger = options.logger;
}
Server.prototype.start = function(callback) { start(callback) {
var serve = serveStatic(this.dist, {'index': ['index.html', 'index.htm']}); let serve = serveStatic(this.dist, {'index': ['index.html', 'index.htm']});
var server = http.createServer(function onRequest (req, res) { let server = http.createServer(function onRequest(req, res) {
serve(req, res, finalhandler(req, res)); serve(req, res, finalhandler(req, res));
}); });
this.logger.info("webserver available at " + ("http://" + this.hostname + ":" + this.port).bold.underline.green); this.logger.info("webserver available at " + ("http://" + this.hostname + ":" + this.port).bold.underline.green);
server.listen(this.port, this.hostname) ; server.listen(this.port, this.hostname);
callback(); callback();
}; }
}
module.exports = Server; module.exports = Server;

View File

@ -1,101 +1,104 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
var chokidar = require('chokidar'); let chokidar = require('chokidar');
var fs = require('../core/fs.js'); let fs = require('../core/fs.js');
// TODO: this should be receiving the config object not re-reading the // TODO: this should be receiving the config object not re-reading the
// embark.json file // embark.json file
var Watch = function(options) { class Watch {
this.logger = options.logger; constructor(options) {
this.events = options.events; this.logger = options.logger;
}; 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 = fs.readJSONSync("embark.json");
this.watchAssets(embarkConfig, function() {
self.logger.trace('ready to watch asset changes');
});
this.watchContracts(embarkConfig, function() {
self.logger.trace('ready to watch contract changes');
});
this.watchConfigs(function() {
self.logger.trace('ready to watch config changes');
});
this.logger.info("ready to watch file changes");
};
Watch.prototype.watchAssets = function(embarkConfig, callback) {
var self = this;
var appConfig = embarkConfig.app;
var filesToWatch = [];
for(var targetFile in appConfig) {
filesToWatch.push(appConfig[targetFile]);
} }
this.watchFiles( start() {
filesToWatch, let self = this;
function(eventName, path) { // TODO: should come from the config object instead of reading the file
self.logger.info(`${eventName}: ${path}`); // directly
self.events.emit('file-' + eventName, 'asset', path); let embarkConfig = fs.readJSONSync("embark.json");
self.events.emit('file-event', 'asset', path);
}, this.watchAssets(embarkConfig, function () {
function() { self.logger.trace('ready to watch asset changes');
callback(); });
this.watchContracts(embarkConfig, function () {
self.logger.trace('ready to watch contract changes');
});
this.watchConfigs(function () {
self.logger.trace('ready to watch config changes');
});
this.logger.info("ready to watch file changes");
}
watchAssets(embarkConfig, callback) {
let self = this;
let appConfig = embarkConfig.app;
let filesToWatch = [];
for (let targetFile in appConfig) {
filesToWatch.push(appConfig[targetFile]);
} }
);
};
Watch.prototype.watchContracts = function(embarkConfig, callback) { this.watchFiles(
var self = this; filesToWatch,
this.watchFiles( function (eventName, path) {
[embarkConfig.contracts], self.logger.info(`${eventName}: ${path}`);
function(eventName, path) { self.events.emit('file-' + eventName, 'asset', path);
self.logger.info(`${eventName}: ${path}`); self.events.emit('file-event', 'asset', path);
self.events.emit('file-' + eventName, 'contract', path); },
self.events.emit('file-event', 'contract', path); function () {
}, callback();
function() { }
callback(); );
} }
);
};
Watch.prototype.watchConfigs = function(callback) { watchContracts(embarkConfig, callback) {
var self = this; let self = this;
this.watchFiles( this.watchFiles(
"config/**/contracts.json", [embarkConfig.contracts],
function(eventName, path) { function (eventName, path) {
self.logger.info(`${eventName}: ${path}`); self.logger.info(`${eventName}: ${path}`);
self.events.emit('file-' + eventName, 'config', path); self.events.emit('file-' + eventName, 'contract', path);
self.events.emit('file-event', 'config', path); self.events.emit('file-event', 'contract', path);
}, },
function() { function () {
callback(); callback();
} }
); );
}; }
Watch.prototype.watchFiles = function(files, changeCallback, doneCallback) { watchConfigs(callback) {
this.logger.trace('watchFiles'); let self = this;
this.logger.trace(files); this.watchFiles(
"config/**/contracts.json",
function (eventName, path) {
self.logger.info(`${eventName}: ${path}`);
self.events.emit('file-' + eventName, 'config', path);
self.events.emit('file-event', 'config', path);
},
function () {
callback();
}
);
}
var configWatcher = chokidar.watch(files, { watchFiles(files, changeCallback, doneCallback) {
ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true this.logger.trace('watchFiles');
}); this.logger.trace(files);
configWatcher let configWatcher = chokidar.watch(files, {
.on('add', path => changeCallback('add', path)) ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
.on('change', path => changeCallback('change', path)) });
.on('unlink', path => changeCallback('remove', path))
.on('ready', doneCallback); configWatcher
}; .on('add', path => changeCallback('add', path))
.on('change', path => changeCallback('change', path))
.on('unlink', path => changeCallback('remove', path))
.on('ready', doneCallback);
}
}
module.exports = Watch; module.exports = Watch;

View File

@ -1,56 +1,60 @@
var colors = require('colors'); let colors = require('colors');
var async = require('async'); let async = require('async');
var shelljs = require('shelljs'); let shelljs = require('shelljs');
var IPFS = function(options) { class IPFS {
this.options = options;
this.buildDir = options.buildDir || 'dist/';
this.plugins = options.plugins;
this.storageConfig = options.storageConfig;
this.configIpfsBin = this.storageConfig.ipfs_bin || "ipfs";
};
IPFS.prototype.deploy = function() { constructor(options) {
var self = this; this.options = options;
async.waterfall([ this.buildDir = options.buildDir || 'dist/';
function findBinary(callback) { this.plugins = options.plugins;
var ipfs_bin = shelljs.exec('which ' + self.configIpfsBin).output.split("\n")[0]; this.storageConfig = options.storageConfig;
this.configIpfsBin = this.storageConfig.ipfs_bin || "ipfs";
}
if (ipfs_bin === 'ipfs not found' || ipfs_bin === ''){ deploy() {
console.log(('=== WARNING: ' + self.configIpfsBin + ' not found or not in the path. Guessing ~/go/bin/ipfs for path').yellow); let self = this;
ipfs_bin = "~/go/bin/ipfs"; async.waterfall([
function findBinary(callback) {
let ipfs_bin = shelljs.exec('which ' + self.configIpfsBin).output.split("\n")[0];
if (ipfs_bin === 'ipfs not found' || ipfs_bin === '') {
console.log(('=== WARNING: ' + self.configIpfsBin + ' not found or not in the path. Guessing ~/go/bin/ipfs for path').yellow);
ipfs_bin = "~/go/bin/ipfs";
}
return callback(null, ipfs_bin);
},
function runCommand(ipfs_bin, callback) {
let cmd = ipfs_bin + " add -r " + self.buildDir;
console.log(("=== adding " + self.buildDir + " to ipfs").green);
console.log(cmd.green);
let result = shelljs.exec(cmd);
return callback(null, result);
},
function getHashFromOutput(result, callback) {
let rows = result.output.split("\n");
let dir_row = rows[rows.length - 2];
let dir_hash = dir_row.split(" ")[1];
return callback(null, dir_hash);
},
function printUrls(dir_hash, callback) {
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);
return callback();
} }
], function (err, result) {
return callback(null, ipfs_bin);
},
function runCommand(ipfs_bin, callback) {
var cmd = ipfs_bin + " add -r " + self.buildDir;
console.log(("=== adding " + self.buildDir + " to ipfs").green);
console.log(cmd.green);
var result = shelljs.exec(cmd);
return callback(null, result);
},
function getHashFromOutput(result, callback) {
var rows = result.output.split("\n");
var dir_row = rows[rows.length - 2];
var dir_hash = dir_row.split(" ")[1];
return callback(null, dir_hash);
},
function printUrls(dir_hash, callback) {
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);
return callback();
}
], function(err, result) {
if (err) { if (err) {
console.log("error uploading to ipfs".red); console.log("error uploading to ipfs".red);
console.log(err); console.log(err);
} }
}); });
}; }
}
module.exports = IPFS; module.exports = IPFS;

View File

@ -1,55 +1,57 @@
var colors = require('colors'); let colors = require('colors');
var async = require('async'); let async = require('async');
var shelljs = require('shelljs'); let shelljs = require('shelljs');
var Swarm = function(options) { class Swarm {
this.options = options; constructor(options) {
this.buildDir = options.buildDir || 'dist/'; this.options = options;
}; this.buildDir = options.buildDir || 'dist/';
}
Swarm.prototype.deploy = function() { deploy() {
var self = this; let self = this;
async.waterfall([ async.waterfall([
function findBinary(callback) { function findBinary(callback) {
var swarm_bin = shelljs.exec('which swarm').output.split("\n")[0]; let swarm_bin = shelljs.exec('which swarm').output.split("\n")[0];
if (swarm_bin==='swarm not found' || swarm_bin === ''){ if (swarm_bin === 'swarm not found' || swarm_bin === '') {
console.log('=== WARNING: Swarm not in an executable path. Guessing ~/go/bin/swarm for path'.yellow); console.log('=== WARNING: Swarm not in an executable path. Guessing ~/go/bin/swarm for path'.yellow);
swarm_bin = "~/go/bin/swarm"; swarm_bin = "~/go/bin/swarm";
}
return callback(null, swarm_bin);
},
function runCommand(swarm_bin, callback) {
let cmd = swarm_bin + " --defaultpath " + self.buildDir + "index.html --recursive up " + self.buildDir;
console.log(("=== adding " + self.buildDir + " to swarm").green);
console.log(cmd.green);
let result = shelljs.exec(cmd);
return callback(null, result);
},
function getHashFromOutput(result, callback) {
if (result.code !== 0) {
return callback("couldn't upload, is the swarm daemon running?");
}
let rows = result.output.split("\n");
let dir_hash = rows.reverse()[1];
return callback(null, dir_hash);
},
function printUrls(dir_hash, callback) {
console.log(("=== DApp available at http://localhost:8500/bzz:/" + dir_hash + "/").green);
return callback();
} }
], function (err, result) {
return callback(null, swarm_bin);
},
function runCommand(swarm_bin, callback) {
var cmd = swarm_bin + " --defaultpath " + self.buildDir + "index.html --recursive up " + self.buildDir;
console.log(("=== adding " + self.buildDir + " to swarm").green);
console.log(cmd.green);
var result = shelljs.exec(cmd);
return callback(null, result);
},
function getHashFromOutput(result, callback) {
if (result.code !== 0) {
return callback("couldn't upload, is the swarm daemon running?");
}
var rows = result.output.split("\n");
var dir_hash = rows.reverse()[1];
return callback(null, dir_hash);
},
function printUrls(dir_hash, callback) {
console.log(("=== DApp available at http://localhost:8500/bzz:/" + dir_hash + "/").green);
return callback();
}
], function(err, result) {
if (err) { if (err) {
console.log("error uploading to swarm".red); console.log("error uploading to swarm".red);
console.log(err); console.log(err);
} }
}); });
}; }
}
module.exports = Swarm; module.exports = Swarm;

15
lib/utils/async_extend.js Normal file
View File

@ -0,0 +1,15 @@
let async = require('async');
function asyncEachObject(object, iterator, callback) {
async.each(
Object.keys(object || {}),
function (key, next) {
iterator(key, object[key], next);
},
callback
);
}
async.eachObject = asyncEachObject;
module.exports = async;

View File

@ -5,9 +5,9 @@ function extend(filename, async) {
return; return;
} }
async._waterfall = async.waterfall; async._waterfall = async.waterfall;
async.waterfall = function(_tasks, callback) { async.waterfall = function (_tasks, callback) {
var tasks = _tasks.map(function(t) { let tasks = _tasks.map(function (t) {
var fn = function() { let fn = function () {
console.log("async " + filename + ": " + t.name); console.log("async " + filename + ": " + t.name);
t.apply(t, arguments); t.apply(t, arguments);
}; };

View File

@ -1,9 +1,9 @@
/*global exit */ /*global exit */
var path = require('path'); let path = require('path');
var globule = require('globule'); let globule = require('globule');
var merge = require('merge'); let merge = require('merge');
var http = require('http'); let http = require('http');
var shelljs = require('shelljs'); let shelljs = require('shelljs');
function joinPath() { function joinPath() {
return path.join.apply(path.join, arguments); return path.join.apply(path.join, arguments);
@ -22,15 +22,19 @@ function recursiveMerge(target, source) {
} }
function checkIsAvailable(url, callback) { function checkIsAvailable(url, callback) {
http.get(url, function(res) { http.get(url, function (res) {
callback(true); callback(true);
}).on('error', function(res) { }).on('error', function (res) {
callback(false); callback(false);
}); });
} }
function httpGet(url, callback) {
return http.get(url, callback);
}
function runCmd(cmd, options) { function runCmd(cmd, options) {
var result = shelljs.exec(cmd, options || {silent: true}); let result = shelljs.exec(cmd, options || {silent: true});
if (result.code !== 0) { if (result.code !== 0) {
console.log("error doing.. " + cmd); console.log("error doing.. " + cmd);
console.log(result.output); console.log(result.output);
@ -53,12 +57,14 @@ function exit(code) {
process.exit(code); process.exit(code);
} }
//TODO: Maybe desired to just `module.exports = this` ?
module.exports = { module.exports = {
joinPath: joinPath, joinPath: joinPath,
filesMatchingPattern: filesMatchingPattern, filesMatchingPattern: filesMatchingPattern,
fileMatchesPattern: fileMatchesPattern, fileMatchesPattern: fileMatchesPattern,
recursiveMerge: recursiveMerge, recursiveMerge: recursiveMerge,
checkIsAvailable: checkIsAvailable, checkIsAvailable: checkIsAvailable,
httpGet: httpGet,
runCmd: runCmd, runCmd: runCmd,
cd: cd, cd: cd,
sed: sed, sed: sed,

View File

@ -1,6 +1,6 @@
{ {
"name": "embark", "name": "embark",
"version": "2.4.2", "version": "2.5.0",
"description": "Embark is a framework that allows you to easily develop and deploy DApps", "description": "Embark is a framework that allows you to easily develop and deploy DApps",
"scripts": { "scripts": {
"test": "grunt jshint && mocha test/ --no-timeouts" "test": "grunt jshint && mocha test/ --no-timeouts"
@ -26,11 +26,14 @@
"fs-extra": "^2.0.0", "fs-extra": "^2.0.0",
"globule": "^1.1.0", "globule": "^1.1.0",
"merge": "^1.2.0", "merge": "^1.2.0",
"promptly": "^2.1.0",
"serve-static": "^1.11.1", "serve-static": "^1.11.1",
"shelljs": "^0.5.0", "shelljs": "^0.5.0",
"solc": "0.4.8", "solc": "0.4.11",
"toposort": "^1.0.0", "toposort": "^1.0.0",
"web3": "^0.18.2" "underscore": "^1.8.3",
"underscore.string": "^3.3.4",
"web3": "^0.19.1"
}, },
"author": "Iuri Matias <iuri.matias@gmail.com>", "author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [], "contributors": [],
@ -49,6 +52,8 @@
"devDependencies": { "devDependencies": {
"grunt": "^1.0.1", "grunt": "^1.0.1",
"grunt-cli": "^1.2.0", "grunt-cli": "^1.2.0",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-coffee": "^1.0.0",
"grunt-contrib-jshint": "^1.0.0", "grunt-contrib-jshint": "^1.0.0",
"grunt-mocha-test": "^0.13.2", "grunt-mocha-test": "^0.13.2",
"matchdep": "^1.0.1", "matchdep": "^1.0.1",
@ -56,5 +61,19 @@
"mocha-sinon": "^1.1.4", "mocha-sinon": "^1.1.4",
"sinon": "^1.15.4", "sinon": "^1.15.4",
"toposort": "^1.0.0" "toposort": "^1.0.0"
},
"jshintConfig": {
"indent": 2,
"white": true,
"node": true,
"undef": true,
"-W058": true,
"-W014": true,
"expr": true,
"esversion": 6,
"unused": false,
"globals": {
"node": true
}
} }
} }

View File

@ -1,23 +1,23 @@
/*globals describe, it*/ /*globals describe, it*/
var ABIGenerator = require('../lib/contracts/abi.js'); let ABIGenerator = require('../lib/contracts/abi.js');
var assert = require('assert'); let assert = require('assert');
// TODO: instead 'eval' the code with a fake web3 object // TODO: instead 'eval' the code with a fake web3 object
// and check the generate code interacts as expected // and check the generate code interacts as expected
describe('embark.ABIGenerator', function() { describe('embark.ABIGenerator', function() {
this.timeout(0);
describe('#generateProvider', function() { describe('#generateProvider', function() {
var generator = new ABIGenerator({blockchainConfig: {rpcHost: 'somehost', rpcPort: '1234'}, contractsManager: {}}); let generator = new ABIGenerator({blockchainConfig: {rpcHost: 'somehost', rpcPort: '1234'}, contractsManager: {}});
it('should generate code to connect to a provider', function() { it('should generate code to connect to a provider', function() {
var providerCode = "\nvar whenEnvIsLoaded = function(cb) {\n if (typeof window !== 'undefined' && window !== null) {\n window.addEventListener('load', cb);\n } else {\n cb();\n }\n}\nwhenEnvIsLoaded(function() {\nif (typeof web3 !== 'undefined' && typeof Web3 !== 'undefined') {\n\tweb3 = new Web3(web3.currentProvider);\n} else if (typeof Web3 !== 'undefined') {\n\tweb3 = new Web3(new Web3.providers.HttpProvider(\"http://somehost:1234\"));\n}\nweb3.eth.defaultAccount = web3.eth.accounts[0];\n})" var providerCode = "\nvar whenEnvIsLoaded = function(cb) {\n if (typeof document !== 'undefined' && document !== null) {\n document.addEventListener('DOMContentLoaded', cb);\n } else {\n cb();\n }\n}\nwhenEnvIsLoaded(function() {\nif (typeof web3 !== 'undefined' && typeof Web3 !== 'undefined') {\n\tweb3 = new Web3(web3.currentProvider);\n} else if (typeof Web3 !== 'undefined') {\n\tweb3 = new Web3(new Web3.providers.HttpProvider(\"http://somehost:1234\"));\n}\nweb3.eth.defaultAccount = web3.eth.accounts[0];\n})"
assert.equal(generator.generateProvider(), providerCode); assert.equal(generator.generateProvider(), providerCode);
}); });
}); });
describe('#generateContracts', function() { describe('#generateContracts', function() {
var generator = new ABIGenerator({blockchainConfig: {}, contractsManager: { let generator = new ABIGenerator({blockchainConfig: {}, contractsManager: {
contracts: { contracts: {
SimpleStorage: { SimpleStorage: {
abiDefinition: [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}], abiDefinition: [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}],
@ -35,19 +35,19 @@ describe('embark.ABIGenerator', function() {
}}); }});
describe('with EmbarkJS', function() { describe('with EmbarkJS', function() {
var withEmbarkJS = true; let withEmbarkJS = true;
it('should generate contract code', function() { it('should generate contract code', function() {
var contractCode = "\n\nwhenEnvIsLoaded(function() {\nSimpleStorage = new EmbarkJS.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x123', code: '12345', gasEstimates: 12000});\n});\nwhenEnvIsLoaded(function() {\nFoo = new EmbarkJS.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x124', code: '123456', gasEstimates: 12000});\n});"; var contractCode = "\n\nif (whenEnvIsLoaded === undefined) {\n var whenEnvIsLoaded = function(cb) {\n if (typeof document !== 'undefined' && document !== null) {\n document.addEventListener('DOMContentLoaded', cb);\n } else {\n cb();\n }\n }\n}\nwhenEnvIsLoaded(function() {\nSimpleStorage = new EmbarkJS.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x123', code: '12345', gasEstimates: 12000});\n});\nif (whenEnvIsLoaded === undefined) {\n var whenEnvIsLoaded = function(cb) {\n if (typeof document !== 'undefined' && document !== null) {\n document.addEventListener('DOMContentLoaded', cb);\n } else {\n cb();\n }\n }\n}\nwhenEnvIsLoaded(function() {\nFoo = new EmbarkJS.Contract({abi: [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}], address: '0x124', code: '123456', gasEstimates: 12000});\n});";
assert.equal(generator.generateContracts(withEmbarkJS), contractCode); assert.equal(generator.generateContracts(withEmbarkJS), contractCode);
}); });
}); });
describe('with default interface', function() { describe('with default interface', function() {
var withEmbarkJS = false; let withEmbarkJS = false;
it('should generate contract code', function() { it('should generate contract code', function() {
var contractCode = "\n\nwhenEnvIsLoaded(function() {\nSimpleStorageAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nSimpleStorageContract = web3.eth.contract(SimpleStorageAbi);\nSimpleStorage = SimpleStorageContract.at('0x123');\n});\nwhenEnvIsLoaded(function() {\nFooAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nFooContract = web3.eth.contract(FooAbi);\nFoo = FooContract.at('0x124');\n});"; var contractCode = "\n\nif (whenEnvIsLoaded === undefined) {\n var whenEnvIsLoaded = function(cb) {\n if (typeof document !== 'undefined' && document !== null) {\n document.addEventListener('DOMContentLoaded', cb);\n } else {\n cb();\n }\n }\n}\nwhenEnvIsLoaded(function() {\nSimpleStorageAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nSimpleStorageContract = web3.eth.contract(SimpleStorageAbi);\nSimpleStorage = SimpleStorageContract.at('0x123');\n});\nif (whenEnvIsLoaded === undefined) {\n var whenEnvIsLoaded = function(cb) {\n if (typeof document !== 'undefined' && document !== null) {\n document.addEventListener('DOMContentLoaded', cb);\n } else {\n cb();\n }\n }\n}\nwhenEnvIsLoaded(function() {\nFooAbi = [{\"constant\":true,\"inputs\":[],\"name\":\"storedData\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"retVal\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[{\"name\":\"initialValue\",\"type\":\"uint256\"}],\"type\":\"constructor\"}];\nFooContract = web3.eth.contract(FooAbi);\nFoo = FooContract.at('0x124');\n});";
assert.equal(generator.generateContracts(withEmbarkJS), contractCode); assert.equal(generator.generateContracts(withEmbarkJS), contractCode);
}); });
}); });

View File

@ -1,17 +1,18 @@
/*globals describe, it*/ /*globals describe, it*/
var Blockchain = require('../lib/cmds/blockchain/blockchain.js'); const Blockchain = require('../lib/cmds/blockchain/blockchain');
var assert = require('assert');
describe('embark.Blockchain', function() { const assert = require('assert');
//var Client = function() {};
describe('embark.Blockchain', function () {
//let Client = function() {};
//Client.prototype.name = "ClientName"; //Client.prototype.name = "ClientName";
describe('#initializer', function() { describe('#initializer', function () {
//var client = new Client(); //let client = new Client();
describe('with empty config', function() { describe('with empty config', function () {
it('should have a default config', function() { it('should have a default config', function (done) {
var config = { let config = {
networkType: 'custom', networkType: 'custom',
genesisBlock: false, genesisBlock: false,
geth_bin: 'geth', geth_bin: 'geth',
@ -31,15 +32,16 @@ describe('embark.Blockchain', function() {
account: {}, account: {},
bootnodes: "" bootnodes: ""
}; };
var blockchain = Blockchain(config, 'geth'); let blockchain = new Blockchain(config, 'geth');
assert.deepEqual(blockchain.config, config); assert.deepEqual(blockchain.config, config);
done();
}); });
}); });
describe('with config', function() { describe('with config', function () {
it('should take config params', function() { it('should take config params', function (done) {
var config = { let config = {
networkType: 'livenet', networkType: 'livenet',
genesisBlock: 'foo/bar/genesis.json', genesisBlock: 'foo/bar/genesis.json',
geth_bin: 'geth', geth_bin: 'geth',
@ -59,9 +61,10 @@ describe('embark.Blockchain', function() {
account: {}, account: {},
bootnodes: "" bootnodes: ""
}; };
var blockchain = Blockchain(config, 'geth'); let blockchain = new Blockchain(config, 'geth');
assert.deepEqual(blockchain.config, config); assert.deepEqual(blockchain.config, config);
done();
}); });
}); });

52
test/cmd.js Normal file
View File

@ -0,0 +1,52 @@
let Embark = require('../lib/index');
let Cmd = require('../lib/cmd');
// Function to send a line to stdin
function sendLine(line) {
setImmediate(function () {
process.stdin.emit('data', line + '\n');
});
}
let passingLines = function () {
let lines = [];
lines.push('Initializing Embark Template....');
lines.push('Installing packages.. this can take a few seconds');
lines.push('Init complete');
return lines;
};
describe('embark.Cmd', function () {
this.timeout(0);
describe('#new', function () {
it('it should create an app with a name', function (done) {
let cmd = new Cmd(Embark);
let pl = passingLines();
let appname = 'deleteapp';
cmd.newApp(appname, function (output) {
let lines = output.split('\n');
console.log(lines);
assert.equal(lines[0], pl[0]);
assert.equal(lines[1], pl[1]);
assert.equal(lines[2], pl[2]);
assert.equal(lines[3], 'App ready at ./' + appname);
});
done();
});
it('it should prompt when given an empty app name', function (done) {
let cmd = new Cmd(Embark);
let pl = passingLines();
let appname = 'deleteapp';
cmd.newApp(undefined, function (output) {
let lines = output.split('\n');
console.log(lines);
sendLine(appname + '\n');
assert.equal(lines[0], pl[0]);
});
done();
});
});
});

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,10 @@
/*globals describe, it*/ /*globals describe, it*/
var Config = require('../lib/core/config.js'); let Config = require('../lib/core/config.js');
var Plugins = require('../lib/core/plugins.js'); let Plugins = require('../lib/core/plugins.js');
var assert = require('assert'); let assert = require('assert');
var fs = require('fs');
describe('embark.Config', function() { describe('embark.Config', function() {
var config = new Config({ let config = new Config({
env: 'myenv', env: 'myenv',
configDir: './test/test1/config/' configDir: './test/test1/config/'
}); });
@ -14,7 +13,7 @@ describe('embark.Config', function() {
describe('#loadBlockchainConfigFile', function() { describe('#loadBlockchainConfigFile', function() {
it('should load blockchain config correctly', function() { it('should load blockchain config correctly', function() {
config.loadBlockchainConfigFile(); config.loadBlockchainConfigFile();
var expectedConfig = { let expectedConfig = {
"enabled": true, "enabled": true,
"networkType": "custom", "networkType": "custom",
"genesisBlock": "config/development/genesis.json", "genesisBlock": "config/development/genesis.json",
@ -36,7 +35,7 @@ describe('embark.Config', function() {
describe('#loadContractsConfigFile', function() { describe('#loadContractsConfigFile', function() {
it('should load contract config correctly', function() { it('should load contract config correctly', function() {
config.loadContractsConfigFile(); config.loadContractsConfigFile();
var expectedConfig = { let expectedConfig = {
"gas": "auto", "gas": "auto",
"contracts": { "contracts": {
"SimpleStorage": { "SimpleStorage": {

View File

@ -1,11 +1,12 @@
/*globals describe, it*/ /*globals describe, it*/
var Console = require('../lib/dashboard/console.js'); let Console = require('../lib/dashboard/console.js');
var Plugins = require('../lib/core/plugins.js'); let Plugins = require('../lib/core/plugins.js');
var assert = require('assert'); let assert = require('assert');
let version = require('../package.json').version;
describe('embark.Console', function() { describe('embark.Console', function() {
var plugins = new Plugins({plugins: {}}); let plugins = new Plugins({plugins: {}});
var console = new Console({plugins: plugins, version: '2.3.1'}); let console = new Console({plugins: plugins, version: version});
describe('#executeCmd', function() { describe('#executeCmd', function() {
@ -13,8 +14,8 @@ describe('embark.Console', function() {
it('it should provide a help text', function(done) { it('it should provide a help text', function(done) {
console.executeCmd('help', function(output) { console.executeCmd('help', function(output) {
var lines = output.split('\n'); let lines = output.split('\n');
assert.equal(lines[0], 'Welcome to Embark 2.3.1'); assert.equal(lines[0], 'Welcome to Embark ' + version);
assert.equal(lines[2], 'possible commands are:'); assert.equal(lines[2], 'possible commands are:');
done(); done();
}); });

View File

@ -1,16 +1,17 @@
/*globals describe, it*/ /*globals describe, it*/
var ContractsManager = require('../lib/contracts/contracts.js'); let ContractsManager = require('../lib/contracts/contracts.js');
var Logger = require('../lib/core/logger.js'); let Logger = require('../lib/core/logger.js');
var assert = require('assert'); let assert = require('assert');
var fs = require('fs'); let fs = require('fs');
var readFile = function(file) { let readFile = function(file) {
return {filename: file, content: fs.readFileSync(file).toString()}; return {filename: file, content: fs.readFileSync(file).toString()};
}; };
describe('embark.Contratcs', function() { describe('embark.Contratcs', function() {
this.timeout(0);
describe('simple', function() { describe('simple', function() {
var contractsManager = new ContractsManager({ let contractsManager = new ContractsManager({
contractFiles: [ contractFiles: [
readFile('test/contracts/simple_storage.sol'), readFile('test/contracts/simple_storage.sol'),
readFile('test/contracts/token.sol') readFile('test/contracts/token.sol')
@ -40,7 +41,7 @@ describe('embark.Contratcs', function() {
throw err; throw err;
} }
var contracts = contractsManager.listContracts(); let contracts = contractsManager.listContracts();
assert.equal(contracts.length, 2); assert.equal(contracts.length, 2);
assert.equal(contracts[0].deploy, true); assert.equal(contracts[0].deploy, true);
@ -69,7 +70,7 @@ describe('embark.Contratcs', function() {
}); });
describe('config with contract instances', function() { describe('config with contract instances', function() {
var contractsManager = new ContractsManager({ let contractsManager = new ContractsManager({
contractFiles: [ contractFiles: [
readFile('test/contracts/simple_storage.sol'), readFile('test/contracts/simple_storage.sol'),
readFile('test/contracts/token_storage.sol') readFile('test/contracts/token_storage.sol')
@ -109,7 +110,7 @@ describe('embark.Contratcs', function() {
throw err; throw err;
} }
var contracts = contractsManager.listContracts(); let contracts = contractsManager.listContracts();
assert.equal(contracts.length, 4); assert.equal(contracts.length, 4);
assert.equal(contracts[0].className, "MySimpleStorage"); assert.equal(contracts[0].className, "MySimpleStorage");
@ -126,7 +127,7 @@ describe('embark.Contratcs', function() {
//assert.equal(contracts[3].code, ''); //assert.equal(contracts[3].code, '');
//assert.equal(contracts[3].runtimeBytecode, ''); //assert.equal(contracts[3].runtimeBytecode, '');
var parentContract = contracts[2]; let parentContract = contracts[2];
//MySimpleStorage //MySimpleStorage
assert.equal(contracts[0].deploy, true); assert.equal(contracts[0].deploy, true);

View File

@ -2,6 +2,8 @@ pragma solidity ^0.4.7;
contract SimpleStorage { contract SimpleStorage {
uint public storedData; uint public storedData;
function() payable { }
function SimpleStorage(uint initialValue) { function SimpleStorage(uint initialValue) {
storedData = initialValue; storedData = initialValue;
} }

View File

@ -24,3 +24,27 @@ div {
margin-bottom: 0; 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;
}

View File

@ -9,8 +9,8 @@
<ul class="nav nav-tabs" role="tablist" id="myTabs"> <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" 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)</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)</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> </ul>
<div class="tab-content"> <div class="tab-content">
@ -37,7 +37,8 @@
</div> </div>
</div> </div>
<div role="tabpanel" class="tab-pane" id="storage"> <div role="tabpanel" class="tab-pane" id="storage">
note: You need to have an IPFS node running <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>Save text to IPFS</h3> <h3>Save text to IPFS</h3>
<div class="form-group form-inline"> <div class="form-group form-inline">
@ -72,11 +73,12 @@
<div class="logs"> <div class="logs">
<br> EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'}) <br> EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'})
</div> </div>
</div>
</div> </div>
<div role="tabpanel" class="tab-pane" id="communication"> <div role="tabpanel" class="tab-pane" id="communication">
<span class="error">The node you are using does not support whisper</span> <div class="error alert alert-danger" role="alert">The node you are using does not support Whisper</div>
<div class="errorVersion alert alert-danger" role="alert">The node uses an unsupported version of Whisper</div>
<div id="communication-controls">
<h3>Listen To channel</h3> <h3>Listen To channel</h3>
<div class="form-group form-inline listen"> <div class="form-group form-inline listen">
<input type="text" class="channel text form-control" placeholder="channel"> <input type="text" class="channel text form-control" placeholder="channel">
@ -97,7 +99,7 @@
<div class="logs"> <div class="logs">
<br> EmbarkJS.Messages.setProvider('whisper') <br> EmbarkJS.Messages.setProvider('whisper')
</div> </div>
</div>
</div> </div>
</div> </div>

View File

@ -28,23 +28,59 @@ $(document).ready(function() {
// Storage (IPFS) example // Storage (IPFS) example
// =========================== // ===========================
$(document).ready(function() { $(document).ready(function() {
// automatic set if config/storage.json has "enabled": true and "provider": "ipfs"
//EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'}); //EmbarkJS.Storage.setProvider('ipfs',{server: 'localhost', port: '5001'});
$("#storage .error").hide();
EmbarkJS.Storage.setProvider('ipfs')
.then(function(){
console.log('Provider set to IPFS');
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();
}
});
})
.catch(function(err){
console.log('Failed to set IPFS as Provider:', err.message);
$("#storage .error").show();
$("#status-storage").addClass('status-offline');
$("#storage-controls").hide();
});
$("#storage button.setIpfsText").click(function() { $("#storage button.setIpfsText").click(function() {
var value = $("#storage input.ipfsText").val(); var value = $("#storage input.ipfsText").val();
EmbarkJS.Storage.saveText(value).then(function(hash) { EmbarkJS.Storage.saveText(value).then(function(hash) {
$("span.textHash").html(hash); $("span.textHash").html(hash);
$("input.textHash").val(hash); $("input.textHash").val(hash);
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS saveText Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.saveText('" + value + "').then(function(hash) { })");
}); });
$("#storage button.loadIpfsHash").click(function() { $("#storage button.loadIpfsHash").click(function() {
var value = $("#storage input.textHash").val(); var value = $("#storage input.textHash").val();
EmbarkJS.Storage.get(value).then(function(content) { EmbarkJS.Storage.get(value).then(function(content) {
$("span.ipfsText").html(content); $("span.ipfsText").html(content);
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS get Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.get('" + value + "').then(function(content) { })");
}); });
$("#storage button.uploadFile").click(function() { $("#storage button.uploadFile").click(function() {
@ -52,8 +88,13 @@ $(document).ready(function() {
EmbarkJS.Storage.uploadFile(input).then(function(hash) { EmbarkJS.Storage.uploadFile(input).then(function(hash) {
$("span.fileIpfsHash").html(hash); $("span.fileIpfsHash").html(hash);
$("input.fileIpfsHash").val(hash); $("input.fileIpfsHash").val(hash);
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
})
.catch(function(err) {
if(err){
console.log("IPFS uploadFile Error => " + err.message);
}
}); });
addToLog("#storage", "EmbarkJS.Storage.uploadFile($('input[type=file]')).then(function(hash) { })");
}); });
$("#storage button.loadIpfsFile").click(function() { $("#storage button.loadIpfsFile").click(function() {
@ -73,13 +114,21 @@ $(document).ready(function() {
$(document).ready(function() { $(document).ready(function() {
$("#communication .error").hide(); $("#communication .error").hide();
//web3.version.getWhisper(function(err, res) { $("#communication .errorVersion").hide();
// if (err) { web3.version.getWhisper(function(err, version) {
// $("#communication .error").show(); if (err) {
// } else { $("#communication .error").show();
// EmbarkJS.Messages.setProvider('whisper'); $("#communication-controls").hide();
// } $("#status-communication").addClass('status-offline');
//}); } else if (version >= 5) {
$("#communication .errorVersion").show();
$("#communication-controls").hide();
$("#status-communication").addClass('status-offline');
} else {
EmbarkJS.Messages.setProvider('whisper');
$("#status-communication").addClass('status-online');
}
});
$("#communication button.listenToChannel").click(function() { $("#communication button.listenToChannel").click(function() {
var channel = $("#communication .listen input.channel").val(); var channel = $("#communication .listen input.channel").val();
@ -98,4 +147,3 @@ $(document).ready(function() {
}); });
}); });

View File

@ -1,4 +1,5 @@
{ {
"config": {},
"nonce": "0x0000000000000042", "nonce": "0x0000000000000042",
"difficulty": "0x0", "difficulty": "0x0",
"alloc": { "alloc": {

View File

@ -14,6 +14,7 @@
"buildDir": "dist/", "buildDir": "dist/",
"config": "config/", "config": "config/",
"plugins": { "plugins": {
"embark-babel": {"files": ["**/*.js", "**/*.jsx", "!**/_vendor/*.js"]} "embark-babel": {"files": ["**/*.js", "**/*.jsx", "!**/_vendor/*.js"]},
"embark-service": {}
} }
} }

View File

@ -0,0 +1,5 @@
module.exports = function(embark) {
embark.registerServiceCheck('PluginService', function(cb) {
cb({name: "ServiceName", status: "on"});
});
};

View File

@ -0,0 +1,11 @@
{
"name": "embark-service",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

View File

@ -10,11 +10,12 @@
"license": "ISC", "license": "ISC",
"homepage": "", "homepage": "",
"devDependencies": { "devDependencies": {
"embark": "../", "embark": "file:../",
"mocha": "^2.2.5" "mocha": "^2.2.5"
}, },
"dependencies": { "dependencies": {
"embark-babel": "^1.0.0", "embark-babel": "^1.0.0",
"embark-service": "./extensions/embark-service",
"ethereumjs-testrpc": "^3.0.3" "ethereumjs-testrpc": "^3.0.3"
} }
} }

View File

@ -5,6 +5,7 @@ var web3 = EmbarkSpec.web3;
describe("AnotherStorage", function() { describe("AnotherStorage", function() {
before(function(done) { before(function(done) {
this.timeout(0);
var contractsConfig = { var contractsConfig = {
"SimpleStorage": { "SimpleStorage": {
args: [100] args: [100]

View File

@ -5,6 +5,7 @@ var web3 = EmbarkSpec.web3;
describe("SimpleStorage", function() { describe("SimpleStorage", function() {
before(function(done) { before(function(done) {
this.timeout(0);
var contractsConfig = { var contractsConfig = {
"SimpleStorage": { "SimpleStorage": {
args: [100] args: [100]

View File

@ -5,6 +5,7 @@ var web3 = EmbarkSpec.web3;
describe("Token", function() { describe("Token", function() {
before(function(done) { before(function(done) {
this.timeout(0);
var contractsConfig = { var contractsConfig = {
"SimpleStorage": { "SimpleStorage": {
args: [100] args: [100]