Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
VictorTaelin committed Mar 2, 2017
0 parents commit 3cd4c5a
Show file tree
Hide file tree
Showing 18 changed files with 853 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
tests.js
148 changes: 148 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
## Swarm.js

This library allows you to interact with the Swarm network from JavaScript. It:

- Communicates with the network through the HTTP API;

- Can be used either with a local node or a gateway;

- Solves manifests recursively;

- Enables you to upload/download raw data and directores;

- Enables you to upload/download from disk or from pure JS;

- Works on the browser and on Node.js;

- Can automatically download the Swarm binaries safely and administer the local node for you.

## Installing

npm install swarm-js

## Basic usage

The simplest use case for Swarm is uploading/downloading raw data and directories.

```javascript
// Loads the Swarm API pointing to the official gateway
const swarm = require("swarm-js").at("http://swarm-gateways.net");
```

#### Upload raw data

```javascript
const file = "test file";
swarm.uploadData(new Buffer(file)).then(hash => {
console.log("Uploaded file. Address:", hash);
})
```

#### Downlod raw data

```javascript
const fileHash = "a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23";
swarm.downloadData(fileHash).then(buffer => {
console.log("Downloaded file:", buffer.toString());
});
```

#### Upload a directory

```javascript
const dir = {
"/foo.txt": "sample file",
"/bar.txt": "another file"
};
swarm.uploadDirectory(dir).then(hash => {
console.log("Uploaded directory. Address:", hash);
});
```

#### Download a directory

```javascript
const dirHash = "7e980476df218c05ecfcb0a2ca73597193a34c5a9d6da84d54e295ecd8e0c641";
swarm.downloadDirectory(dirHash).then(dir => {
console.log("Downloaded directory:");
for (let path in dir) {
console.log("-", path, ":", dir[path].toString());
}
}
```
For examples of how to upload/download from disk, please check the [`examples`](https://github.com/MaiaVictor/swarm-js/tree/master/examples) directory.
## Uploading an Ethereum DApp
When it comes to decentralized applications (DApps), the Ethereum network is responsible for the back-end logic, while Swarm is responsible for hosting and serving the front-end code. Hosting a DApp on Swarm is as simple as creating a directory with some HTMLs and a default route (the "index.html"). This, too, can be done with Swarm.js either [from disk](https://github.com/MaiaVictor/swarm-js/blob/master/examples/dapp_upload_from_disk.js), or with [pure JavaScript](https://github.com/MaiaVictor/swarm-js/blob/master/examples/dapp_upload.js). Here is a sneak peek:
```javascript
const swarm = require("swarm-js").at("http://swarm-gateways.net");

const indexHtml =
`<html>
<body>
<h3><img src="ethereum_icon.png"/> Swarm.js example DApp</h3>
<p><a href="foo/test_text_1.txt">Test #1</a></p>
<p><a href="foo/test_text_2.txt">Test #2</a></p>
</body>
</html>`;

(...)

const exampleDApp = {
"" : indexHtml,
"/index.html" : indexHtml,
"/ethereum_icon.png" : ethereumIconPng,
"/foo/test_text_1.txt" : testText1,
"/foo/test_text_2.txt" : testText2
}

swarm.uploadDirectory(exampleDApp)
.then(console.log)
.catch(console.log);
```
When you run that script, it outputs a hash. You can then use that hash to access the uploaded DApp, by either using a Swarm-enabled browser such as Mist, or through a gateway. That demo DApp is live and can be accessed:
- If your browser recognizes Swarm, [click here](bzz:/8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891).
- If you are in a conventional browser, [click here](http://swarm-gateways.net/bzz:/8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891/).
## Running a local node
Rather than using a gateway, you might wish to run your own local node. For that, you can either [download/install/run it yourself](http://swarm-guide.readthedocs.io/en/latest/), and then use `require("swarm-js").at("http://localhost:8500")`, or let Swarm.js take care of it:
```javascript
const Swarm = require("swarm-js");

// To run Swarm locally, you need a running Geth
// node and an Ethereum account/password
const config = {
account: "d849168d52ea5c40de1b0b973cfd96873c961963",
password: "sap",
dataDir: process.env.HOME+"/Library/Ethereum/testnet",
ethApi: process.env.HOME+"/Library/Ethereum/testnet/geth.ipc"
};

// Magically starts a local Swarm node
// Downloads binaries if necessary
Swarm.local(config, swarm => new Promise((resolve, reject) => {

// Uploads data using the local node
swarm.uploadData("test").then(hash => {
console.log("Uploaded data. Address:", hash);

// Closes the Swarm process.
resolve();
});

})).then(() => console.log("Done!"));
```
That function does everything required to start a local Swarm node, including downloading binaries (if not available yet) and manging the process. It then gives you a `swarm` object pointing to the local node. If the Swarm process was started by `Swarm.js`, it will be closed when you call `resolve()`. While it is up, you're able to access it on your browser at `http://localhost:8500`.

## API

TODO: document the API.
21 changes: 21 additions & 0 deletions examples/dapp_download.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Downloads a DApp without the filesystem; that is, instead of saving the
// directory tree to disk, it returns a JSON mapping routes to contents
// (buffers). That allows any DApp to download the directory tree of any other
// DApp in pure JavaScript.

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");

// The hash of the DApp we uploaded on the other example.
const exampleDAppHash = "8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891";

// Download the example DApp and print its index.html.
swarm.downloadDirectory(exampleDAppHash)
.then(console.log)
.catch(console.log);

// This script outputs:
// { '': <Buffer 3c 68 74 6d 6c 3e 0a 20 20 3c 62 6f 64 79 3e 0a 20 20 20 20 3c 68 33 3e 3c 69 6d 67 20 73 72 63 3d 22 65 74 68 65 72 65 75 6d 5f 69 63 6f 6e 2e 70 6e ... >,
// 'index.html': <Buffer 3c 68 74 6d 6c 3e 0a 20 20 3c 62 6f 64 79 3e 0a 20 20 20 20 3c 68 33 3e 3c 69 6d 67 20 73 72 63 3d 22 65 74 68 65 72 65 75 6d 5f 69 63 6f 6e 2e 70 6e ... >,/
// 'ethereum_icon.png': <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 10 00 00 00 10 08 04 00 00 00 b5 fa 37 ea 00 00 00 f7 49 44 41 54 28 91 63 60 40 01 0d 09 0e ... >,
// 'foo/test_text_1.txt': <Buffer 74 65 73 74 20 74 65 78 74 20 23 31>,
// 'foo/test_text_2.txt': <Buffer 74 65 73 74 20 74 65 78 74 20 23 32> }
12 changes: 12 additions & 0 deletions examples/dapp_download_to_disk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Downloads a directory hosted on the Swarm network to the disk.

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");
const path = require("path");

// The hash of the DApp we uploaded on the other example.
const exampleDAppHash = "8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891";
const targetDirPath = path.join(__dirname,"example_dapp");

swarm.downloadDirectoryToDisk(exampleDAppHash)(targetDirPath)
.then(dirPath => console.log(`Downloaded DApp to ${dirPath}.`))
.catch(console.log);
16 changes: 16 additions & 0 deletions examples/dapp_get_routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Solves the Swarm manifest at a given path recursively, returns a flat JSON
// mapping the routes of its directory tree to the hash of each file on it.

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");
const exampleDAppHash = "8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891";

swarm.downloadRoutes(exampleDAppHash)
.then(console.log)
.catch(console.log);

// This script outputs:
// { '': '957eb52bccea0e9a359952dc13542b3021c8f5fb772ea15f78324a807689eeb6',
// 'index.html': '957eb52bccea0e9a359952dc13542b3021c8f5fb772ea15f78324a807689eeb6',
// 'ethereum_icon.png': '9da2d2d06748a1af3dc4764fc8124af6b47e331f814797f00b7367eb64600cd5',
// 'foo/test_text_1.txt': '9544a960bf1fbc30eb34e828d9afa70b01d6c9d19e3eda8964a63aec942067a9',
// 'foo/test_text_2.txt': '707cc95f1bbbb3df75be110beaef79738b11915204e8c83db43cbba6738d548e' }
64 changes: 64 additions & 0 deletions examples/dapp_upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// This uploads a DApp to the Swarm network *without* using the filesystem.
// That allows a web application running on the browser to upload any DApp.
// Outputs the DApp address. In this case, it is:
// 8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891
// You can access it at:
// http://swarm-gateways.net/bzz:/8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891/

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");

// The contents of index.html.
const indexHtml =
`<html>
<body>
<h3><img src="ethereum_icon.png"/> Swarm.js example DApp</h3>
<p><a href="foo/test_text_1.txt">Test #1</a></p>
<p><a href="foo/test_text_2.txt">Test #2</a></p>
</body>
</html>`;

// For binary data, we can just use a buffer.
// This is a 16x16 Ethereum icon png.
const ethereumIconPng = new Buffer([
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x08,0x04,0x00,0x00,0x00,0xb5,0xfa,0x37,
0xea,0x00,0x00,0x00,0xf7,0x49,0x44,0x41,0x54,0x28,0x91,0x63,0x60,0x40,0x01,0x0d,
0x09,0x0e,0x8e,0x0c,0xb8,0xc1,0x2c,0xa1,0xce,0x9b,0xc6,0xcf,0xa3,0xf8,0x70,0x2a,
0x98,0x90,0xd7,0xf9,0xdf,0xf0,0xbf,0x55,0x27,0x2e,0xfd,0x62,0x7d,0xff,0x40,0x0a,
0x4c,0xdf,0x3a,0x2a,0x62,0x55,0xd0,0x77,0xac,0xe7,0x3f,0x48,0x81,0xf1,0x7f,0xcb,
0xcd,0x58,0xa4,0x27,0xc6,0xf6,0xfc,0xe9,0xf9,0xdf,0x01,0x56,0x60,0xfc,0xdf,0x25,
0x04,0xdd,0x78,0x9e,0x89,0x97,0xbb,0xfe,0x17,0xff,0x0f,0xf8,0x2f,0xfb,0x5f,0xeb,
0xbf,0xd1,0x7f,0xf3,0xa7,0x81,0x42,0x28,0x0a,0x26,0x95,0x66,0xfd,0x77,0xf9,0x6f,
0xf5,0xdf,0xec,0xbf,0xf0,0x7f,0xd1,0xff,0x12,0xff,0xd5,0xfe,0x5b,0xd4,0xa0,0x28,
0xf0,0x5d,0x61,0xfa,0xd3,0xe2,0xbf,0xc5,0x7f,0x73,0xa0,0x02,0x11,0x10,0xfc,0xa6,
0xba,0x0c,0x45,0xc1,0x7c,0x97,0xdc,0x76,0x8b,0xf5,0x96,0x50,0x05,0x12,0x6b,0x0c,
0x5b,0x7c,0xfc,0x50,0x14,0x4c,0x15,0xea,0x3b,0xd7,0xbb,0xc6,0x2f,0xc4,0xfc,0x93,
0xe8,0x2f,0xdd,0x04,0xcb,0x8d,0xa6,0x0f,0x82,0x84,0xd1,0x9c,0x39,0xc9,0xa3,0xe7,
0x7f,0xff,0xab,0x96,0x74,0xc7,0x68,0xb3,0xe7,0xc6,0xff,0x5d,0x1d,0xb0,0x79,0xb4,
0xbe,0xe7,0x7f,0xf7,0x5f,0x23,0xa0,0x27,0x6d,0x8b,0xb0,0x06,0x14,0x30,0xa8,0xf7,
0x83,0x02,0xca,0x7c,0xaf,0x27,0x17,0x0e,0x05,0xd3,0x54,0x3b,0xdf,0x1a,0x7d,0x73,
0x35,0xc0,0x21,0x0d,0x02,0x4d,0x05,0xb6,0xe1,0xa8,0x22,0x00,0xbf,0x45,0x6f,0x1b,
0x57,0x23,0xc8,0x42,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82]);

// Some test .txt file.
const testText1 = "test text #1";

// Other test .txt file.
const testText2 = "test text #2";

// The DApp is just an object mapping routes to contents, which can be either
// strings or buffers. Mime types are inferred from the extension. You can also
// force them by using `{"type": "application/json", "content": "[1,2,3]"}`, for
// example. Notice the empty route also poiting to index.html.
const exampleDApp = {
"" : indexHtml,
"/index.html" : indexHtml,
"/ethereum_icon.png" : ethereumIconPng,
"/foo/test_text_1.txt" : testText1,
"/foo/test_text_2.txt" : testText2
}

// Now we just upload it.
swarm.uploadDirectory(exampleDApp)
.then(console.log)
.catch(console.log);
12 changes: 12 additions & 0 deletions examples/dapp_upload_from_disk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Uploads a DApp from a local directory to the Swarm network.
// Outputs the DApp address. In this case, it is:
// 8587c8e716bfceea12a7306d85a8a8ccad5019020916eb5a21fa47a7f1826891

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");
const path = require("path");

// Notice we use the `WithDefaultPath` version, which allows us to specify a
// root file that will be served on the empty path (e.g., bzz:/my_dapp.eth/).
swarm.uploadDirectoryFromDiskWithDefaultPath("/index.html")(path.join(__dirname,"example_dapp"))
.then(console.log)
.catch(console.log);
10 changes: 10 additions & 0 deletions examples/data_download.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Downloads raw data from the Swarm network.
// Outputs the downloaded data: "test string"

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");
const hash = "a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23";

swarm.downloadData(hash)
.then(buffer => console.log(buffer.toString()))
.catch(console.log);

8 changes: 8 additions & 0 deletions examples/data_upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Uploads raw data to the Swarm network.
// Outputs the Swarm address: a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23

const swarm = require("./../swarm.js").at("http://swarm-gateways.net");

swarm.uploadData("test string")
.then(console.log)
.catch(console.log);
Binary file added examples/example_dapp/ethereum_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/example_dapp/foo/test_text_1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test text #1
1 change: 1 addition & 0 deletions examples/example_dapp/foo/test_text_2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test text #2
7 changes: 7 additions & 0 deletions examples/example_dapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<body>
<h3><img src="ethereum_icon.png"/> Swarm.js example DApp</h3>
<p><a href="foo/test_text_1.txt">Test #1</a></p>
<p><a href="foo/test_text_2.txt">Test #2</a></p>
</body>
</html>
31 changes: 31 additions & 0 deletions examples/examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const swarm = require("./../swarm.js").at("http://swarm-gateways.net");

// Uploading raw data
const file = "test file";
swarm.uploadData(new Buffer(file)).then(hash => {
console.log("Uploaded file. Address:", hash);
})

// Downloading raw data
const fileHash = "a5c10851ef054c268a2438f10a21f6efe3dc3dcdcc2ea0e6a1a7a38bf8c91e23";
swarm.downloadData(fileHash).then(buffer => {
console.log("Downloaded file:", buffer.toString());
});

// Uploading directory
const dir = {
"/foo.txt": "sample file",
"/bar.txt": "another file"
};
swarm.uploadDirectory(dir).then(hash => {
console.log("Uploaded directory. Address:", hash);
});

// Downloaading a directory
const dirHash = "7e980476df218c05ecfcb0a2ca73597193a34c5a9d6da84d54e295ecd8e0c641";
swarm.downloadDirectory(dirHash).then(dir => {
console.log("Downloaded directory:");
for (let path in dir) {
console.log("-", path, ":", dir[path].toString());
}
});
25 changes: 25 additions & 0 deletions examples/runNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const Swarm = require("./../swarm.js");

// To run Swarm locally, you need a running Geth
// node and an Ethereum account/password
const config = {
account: "d849168d52ea5c40de1b0b973cfd96873c961963",
password: "sap",
dataDir: process.env.HOME+"/Library/Ethereum/testnet",
ethApi: process.env.HOME+"/Library/Ethereum/testnet/geth.ipc"
};

// Magically starts a local Swarm node
// Downloads binaries if necessary
Swarm.local(config)(swarm => new Promise((resolve, reject) => {

// Uploads data using the local node
swarm.uploadData("test").then(hash => {
console.log("Uploaded data. Address:", hash);

// Closes the Swarm process.
resolve();
});

})).then(() => console.log("Done!"));

Loading

0 comments on commit 3cd4c5a

Please sign in to comment.