Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit d95e3a8

Browse files
committed
Expose Buffer on ipfs objects, add examples
This lets you construct a Buffer even in browser code that doesn't have access to the Node Buffer global, so that you can pass it back to IPFS API calls that want a Buffer. Add some usage documentation Mentions the `ipfs.Buffer` field you can use to stamp out `Buffer`s so you can actually insert stuff given just an `IPFS` instance and no Node.js APIs in scope. Also add examples for using IPFS in browser with a script tag, and for using libp2p-webrtc-star.
1 parent 2027b96 commit d95e3a8

File tree

6 files changed

+259
-0
lines changed

6 files changed

+259
-0
lines changed

README.md

+45
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Consult the [Roadmap](/ROADMAP.md) for a complete state description of the proje
3939
- [HTTP-API](#http-api)
4040
- [IPFS Core examples (use IPFS as a module)](#ipfs-core-examples-use-ipfs-as-a-module)
4141
- [Create a IPFS node instance](#create-a-ipfs-node-instance)
42+
- [Add a file](#add-a-file)
43+
- [Retrieve a file](#retrieve-a-file)
4244
- [More to come](#more-to-come)
4345
- [API](#api)
4446
- [Generic API](#generic-api)
@@ -48,6 +50,7 @@ Consult the [Roadmap](/ROADMAP.md) for a complete state description of the proje
4850
- [Files API](#files-api)
4951
- [Swarm API](#swarm-api)
5052
- [libp2p API](#libp2p-api)
53+
- [Domain data types](#domain-data-types)
5154
- [Development](#development)
5255
- [Clone](#clone)
5356
- [Install Dependencies](#install-dependencies)
@@ -142,6 +145,8 @@ The HTTP-API exposed by the js-ipfs daemon follows the [`http-api-spec`](https:/
142145

143146
#### Create a IPFS node instance
144147

148+
The basic startup flow involves (optionally) creating a Repo, creating an IPFS node, `init`-ing it so it can generate its keys, `load`-ing its configuration, and putting it online with `goOnline`. Here is a structural example:
149+
145150
```JavaScript
146151
// IPFS will need a repo, it can create one for you or you can pass
147152
// it a repo instance of the type IPFS Repo
@@ -173,6 +178,38 @@ node.init({ emptyRepo: true, bits: 2048 }, (err) => {
173178
174179
> We are working on making this init process better, see https://github.com./ipfs/js-ipfs/issues/556 for the discussion.
175180
181+
Below are some more examples of JavaScript IPFS in action.
182+
183+
#### Add a file
184+
185+
Once you have an IPFS node up and running, you can add files to it from `Buffer`s, `Readable` streams, or [arrays of objects of a certain form](https://github.com./ipfs/interface-ipfs-core/tree/master/API/files#add). If you don't have `Buffer` conveniently available (say, because you're in a browser without the Node API handy), it's available as a property of the IPFS node.
186+
187+
```javascript
188+
// Add a single file
189+
node.files.add(node.Buffer.from('Hello world'), (err, returned) => {
190+
if (err) {
191+
throw err
192+
}
193+
console.log('IPFS hash: ', returned[0].hash)
194+
})
195+
```
196+
197+
#### Retrieve a file
198+
199+
To retrieve the contents of a file, you can use the [cat method](https://github.com./ipfs/interface-ipfs-core/tree/master/API/files#cat), which will call your callback with a Node.js-style `Readable` stream.
200+
201+
```javascript
202+
node.files.cat('QmNRCQWfgze6AbBCaT1rkrkV5tJ2aP4oTNPb5JZcXYywve',
203+
(err, content_stream) => {
204+
if (err) {
205+
throw err
206+
}
207+
content_stream.on('data', (buffer) => {
208+
console.log('File contents:', buffer.toString('ascii'))
209+
})
210+
})
211+
```
212+
176213
#### More to come
177214
178215
> If you have built an example, please share it with the community by submitting a Pull Request to this repo!.
@@ -202,6 +239,12 @@ Every IPFS instance also exposes the libp2p API at `ipfs.libp2p`. The formal int
202239
- [libp2p-ipfs](https://github.com./ipfs/js-libp2p-ipfs)
203240
- [libp2p-ipfs-browser](https://github.com./ipfs/js-libp2p-ipfs-browser)
204241
242+
#### Domain data types
243+
244+
IPFS exposes the Buffer class in every ipfs instance, so that you can create buffers and add them to IPFS just like if you were using it in Node.js.
245+
246+
You can get it at `ipfs.Buffer`
247+
205248
## Development
206249
207250
### Clone
@@ -219,6 +262,8 @@ Every IPFS instance also exposes the libp2p API at `ipfs.libp2p`. The formal int
219262
220263
### Run Tests
221264
265+
#### Block Service
266+
222267
```sh
223268
> npm test
224269

examples/browser-script/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Use IPFS in the browser with `<script>` tags
2+
3+
You can use IPFS in your in-browser JavaScript code with just a `<script>` tag.
4+
5+
```
6+
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>
7+
```
8+
9+
This exposes a global `Ipfs`; you can get a node by making a `new Ipfs()`.
10+
11+
See `index.html` for a working example.
12+
13+

examples/browser-script/index.html

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>IPFS in the Browser</title>
5+
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>
6+
<script type="text/javascript">
7+
// Set this if you have a libp2p-webrtc-star server
8+
// Something like
9+
// const SIGNALING_SERVER = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/ipfs/'
10+
const SIGNALING_SERVER = null
11+
12+
// Make an IPFS node
13+
var ipfs = new Ipfs()
14+
15+
// Init a repo in the given IPFS node it if hasn't got one already. Calls the
16+
// setup callback, passing the normal callback, after first initialization.
17+
// Calls the normal callback directly after subsequent initializations. Calls
18+
// the normal callback with an error parameter if there is an error.
19+
function initIfNeeded (ipfs, setup, callback) {
20+
ipfs.init((err) => {
21+
if (!err) {
22+
// This is the first time we have started a node
23+
setup(callback)
24+
} else if (err.message == 'repo already exists') {
25+
// The node already exists
26+
callback()
27+
} else {
28+
callback(err)
29+
}
30+
})
31+
}
32+
33+
// Init the node
34+
initIfNeeded(ipfs, (callback) => {
35+
// On first initialization, do some setup
36+
// Get the node config we just init-ed
37+
ipfs.config.get((err, config) => {
38+
if (err) {
39+
throw err
40+
}
41+
if (SIGNALING_SERVER) {
42+
// Add at least one libp2p-webrtc-star address. Without an address like this
43+
// the libp2p-webrtc-star transport won't be installed, and the resulting
44+
// node won't be able to dial out to libp2p-webrtc-star addresses.
45+
var star_addr = (SIGNALING_SERVER + config.Identity.PeerID)
46+
ipfs.config.set('Addresses.Swarm[1]', star_addr, (err) => {
47+
if (err) {
48+
throw err
49+
}
50+
// Continue down the already-initialized code path
51+
callback()
52+
})
53+
} else {
54+
// No signaling server is known. Just cointinue without it.
55+
// We don't want to spam the console in our demo
56+
callback()
57+
}
58+
})
59+
}, (err) => {
60+
// If the repo was already initialized, or after the first-time initialization
61+
// code is run, we'll do this.
62+
if (err) {
63+
throw err
64+
}
65+
// Have the node set itself up
66+
ipfs.load(() => {
67+
// Go online and connect to things
68+
ipfs.goOnline(() => {
69+
console.log('Online status: ', ipfs.isOnline() ? 'online' : 'offline')
70+
document.getElementById("status").innerHTML= 'Node status: ' + (ipfs.isOnline() ? 'online' : 'offline')
71+
// TODO: Write your code here!
72+
// Use methods like ipfs.files.add, ipfs.files.get, and so on in here
73+
// Methods requiring buffers can use ipfs.Buffer
74+
})
75+
})
76+
})
77+
</script>
78+
</head>
79+
<body>
80+
<h1>IPFS in the Browser</h1>
81+
<p>This page creates an IPFS node in your browser and drops it into the global Javascript namespace as <em>ipfs</em>. Open the console to play around with it.</p>
82+
<p>Note that opening two tabs of this page in the same browser won't work well, because they will share node configuration. You'll end up trying to run two instances of the same node, with the same private key and identity, which is a Bad Idea.</p>
83+
<div id="status">Node status: offline</div>
84+
</body>
85+
</html>

examples/libp2p-webrtc-star/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Robust Initialization and libp2p-webrtc-star Signaling
2+
3+
There's still a bit of work required to start up an in-browser node in a robust way, so that it will work whether or not there is an existing initialized IPFS repo in the user's browser. If there isn't one, you need to call `init` as above, but if there is one, calling `init` will fail. Moreover, there's currently no good way to check if you need to call `init` or not.
4+
5+
Also, an in-browser node isn't able to call up normal IPFS nodes over raw TCP; it can only communicate over Websockets and WebRTC. Currently, there are no Websockets or WebRTC bootstrap nodes run by the IPFS maintainers. You will probably want to set up a [libp2p-webrtc-star signaling server](https://github.com./libp2p/js-libp2p-webrtc-star) so nodes used in your application can find each other:
6+
7+
```bash
8+
npm i libp2p-webrtc-star -g
9+
star-sig
10+
```
11+
12+
You will then want to point IPFS nodes used in your application at your signaling server, so they can connect to each other. This is accomplished by adding an address to the node's configuration referencing the signaling server, of the form `/libp2p-webrtc-star/ip4/<server-ip>/tcp/<server-port>/ws/ipfs/<peer-id>`, where `<peer-id>` is the peer ID of the node that the address is being added to. This causes the node to think of itself as being contactable through the signaling server. It will then initializes its libp2p-webrtc-star implementation and automatically peer with other nodes using the same server.
13+
14+
The `index.html` page in this directory is an example which initializes an IPFS node in a browser safely, whether a node has already been initialized by the current domain or not. It also configures `libp2p-webrtc-star` communication, using a signaling server running on the local host. (Note that since IPFS node configuration information is stored in IndexedDB in browsers, opening two tabs of this code from a local file in the same browser won't work, because they'll share the same node keys and identity. Either run the code from multiple domains, or run it in two different browsers, like Chrome and Firefox.)
+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>IPFS in the Browser with WebRTC</title>
5+
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>
6+
<script type="text/javascript">
7+
// Set this if you have a libp2p-webrtc-star server
8+
// Something like
9+
const SIGNALING_SERVER = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/9090/ws/ipfs/'
10+
11+
// Make an IPFS node
12+
var ipfs = new Ipfs("webrtc-demo")
13+
14+
// Init a repo in the given IPFS node it if hasn't got one already. Calls the
15+
// setup callback, passing the normal callback, after first initialization.
16+
// Calls the normal callback directly after subsequent initializations. Calls
17+
// the normal callback with an error parameter if there is an error.
18+
function initIfNeeded (ipfs, setup, callback) {
19+
ipfs.init((err) => {
20+
if (!err) {
21+
// This is the first time we have started a node
22+
setup(callback)
23+
} else if (err.message == 'repo already exists') {
24+
// The node already exists
25+
callback()
26+
} else {
27+
callback(err)
28+
}
29+
})
30+
}
31+
32+
function showPeers () {
33+
ipfs.swarm.peers(function (err, peerInfos) {
34+
document.getElementById("peers").innerHTML= ''
35+
for (var i = 0; i < peerInfos.length; i++) {
36+
document.getElementById("peers").innerHTML += peerInfos[i].addr + '<br/>'
37+
}
38+
39+
setTimeout(showPeers, 1000)
40+
})
41+
}
42+
43+
// Init the node
44+
initIfNeeded(ipfs, (callback) => {
45+
// On first initialization, do some setup
46+
// Get the node config we just init-ed
47+
ipfs.config.get((err, config) => {
48+
if (err) {
49+
throw err
50+
}
51+
if (SIGNALING_SERVER) {
52+
// Add at least one libp2p-webrtc-star address. Without an address like this
53+
// the libp2p-webrtc-star transport won't be installed, and the resulting
54+
// node won't be able to dial out to libp2p-webrtc-star addresses.
55+
var star_addr = (SIGNALING_SERVER + config.Identity.PeerID)
56+
ipfs.config.set('Addresses.Swarm[1]', star_addr, (err) => {
57+
if (err) {
58+
throw err
59+
}
60+
// Continue down the already-initialized code path
61+
callback()
62+
})
63+
} else {
64+
// No signaling server is known. Just cointinue without it.
65+
// We don't want to spam the console in our demo
66+
callback()
67+
}
68+
})
69+
}, (err) => {
70+
// If the repo was already initialized, or after the first-time initialization
71+
// code is run, we'll do this.
72+
if (err) {
73+
throw err
74+
}
75+
// Have the node set itself up
76+
ipfs.load(() => {
77+
// Go online and connect to things
78+
ipfs.goOnline(() => {
79+
console.log('Online status: ', ipfs.isOnline() ? 'online' : 'offline')
80+
document.getElementById("status").innerHTML= 'Node status: ' + (ipfs.isOnline() ? 'online' : 'offline')
81+
setTimeout(showPeers, 1000)
82+
// TODO: Write your code here!
83+
// Use methods like ipfs.files.add, ipfs.files.get, and so on in here
84+
// Methods requiring buffers can use ipfs.Buffer
85+
})
86+
})
87+
})
88+
</script>
89+
</head>
90+
<body>
91+
<h1>IPFS in the Browser with WebRTC</h1>
92+
<p>This page creates an IPFS node in your browser and drops it into the global Javascript namespace as <em>ipfs</em>. Open the console to play around with it.</p>
93+
<p>Note that opening two tabs of this page in the same browser won't work well, because they will share node configuration. You'll end up trying to run two instances of the same node, with the same private key and identity, which is a Bad Idea.</p>
94+
<div id="status">Node status: offline</div>
95+
<p>Run a libp2p-webrtc-star signaling server! Peers detected through the server will be displayed below:</p>
96+
<p>Peers:</p>
97+
<div id="peers"></div>
98+
</body>
99+
</html>

src/core/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ function IPFS (repoInstance) {
6767
this.files = files(this)
6868
this.bitswap = bitswap(this)
6969
this.ping = ping(this)
70+
71+
// expose Buffer for browser applications
72+
this.Buffer = Buffer
7073
}

0 commit comments

Comments
 (0)