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

Commit ed49df6

Browse files
haadcodedaviddias
authored andcommitted
docs(example): create an example of catting files added from ipfs CLI
1 parent 5078ddc commit ed49df6

File tree

8 files changed

+514
-0
lines changed

8 files changed

+514
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
public/ipfs.js
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# access-go-ipfs-files - cat-a-file
2+
3+
**WIP**
4+
5+
## TODO
6+
7+
- Add "connect to peer" input field and "connect" button under the "Peers" section in index.html
8+
- Add `connectToPeer` function which calls `ipfs.swarm.connect(multiaddr)`. See https://github.com/ipfs/js-ipfs/blob/b0a7cd83cbf146b0f147467dedc686f94a5f751f/examples/ipfm/src/DataStore.js#L82 and https://github.com/ipfs/js-ipfs/blob/b0a7cd83cbf146b0f147467dedc686f94a5f751f/examples/ipfm/README.md#start-an-interplanetary-file-exchange-daemon. The multiaddr to connect to looks like this: `/ip4/127.0.0.1/tcp/9999/ws/ipfs/QmZGH8GeASSkSZoNLPEBu1MqtzLTERNUEwh9yTHLEF5kcW`
9+
- Hook up "connect" button's click event to `connectToPeer` function
10+
- Add instructions to this README on how to add a file in go-ipfs
11+
- Add instructions to this README on how to cat it in the UI
12+
- Make sure the "Start a go-ipfs daemon" instructions are correct
13+
- Make sure go-ipfs daemon and the example connect to each other
14+
15+
## Step-by-step Instructions
16+
17+
### Start a go-ipfs daemon
18+
19+
1. Install go-ipfs from master (TODO: link).
20+
21+
2. Run `ipfs init`
22+
23+
3. Edit your IPFS config file, located at `~/.ipfs/config`
24+
25+
4. Add a Websocket listener address to `Addresses.Swarm`. It should look like this after editing:
26+
```
27+
"Addresses": {
28+
"API": "/ip4/127.0.0.1/tcp/5001",
29+
"Gateway": "/ip4/0.0.0.0/tcp/8080",
30+
"Swarm": [
31+
"/ip4/0.0.0.0/tcp/4001",
32+
"/ip4/0.0.0.0/tcp/9999/ws"
33+
]
34+
},
35+
```
36+
37+
5. Start the go-ipfs daemon with:
38+
```
39+
ipfs daemon
40+
```
41+
42+
6. You should see the Websocket address in the output:
43+
```
44+
Initializing daemon...
45+
Swarm listening on /ip4/127.0.0.1/tcp/4001
46+
Swarm listening on /ip4/127.0.0.1/tcp/9999/ws
47+
Swarm listening on /ip4/192.168.10.38/tcp/4001
48+
Swarm listening on /ip4/192.168.10.38/tcp/9999/ws
49+
API server listening on /ip4/127.0.0.1/tcp/5001
50+
Gateway (readonly) server listening on /ip4/0.0.0.0/tcp/8080
51+
Daemon is ready
52+
```
53+
54+
If you see address like `Swarm listening on /ip4/127.0.0.1/tcp/9999/ws`, it means all good!
55+
56+
## Start the example
57+
58+
**NOTE!** Before running the examples, you need to build `js-ipfs`. You can do this by following the instructions in https://github.com/ipfs/js-ipfs#clone-and-install-dependnecies and then building it as per https://github.com/ipfs/js-ipfs#build-a-dist-version.
59+
60+
```
61+
npm install
62+
npm start
63+
```
64+
65+
Open http://127.0.0.1:8080 in a browser.
66+
67+
**TODO: add instructions how to cat a hash in the UI.**
68+
69+
## Tutorial
70+
71+
Steps
72+
1. create IPFS instance
73+
74+
TODO. See `./start-ipfs.js`
75+
76+
3. add a file in go-ipfs
77+
4. copy file's hash
78+
5. ipfs.files.cat
79+
80+
TODO. add ipfs.files.cat code examples from index.html
81+
82+
6. output the buffer to <img>
83+
84+
```
85+
...
86+
stream.on('end', () => {
87+
const blob = new Blob(buf)
88+
picture.src = URL.createObjectURL(blob)
89+
})
90+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "cat-a-file",
3+
"version": "1.0.0",
4+
"description": "",
5+
"scripts": {
6+
"postinstall": "cp ../../../dist/index.js ./public/ipfs.js",
7+
"start": "http-server -c-1"
8+
},
9+
"author": "Haad",
10+
"license": "MIT",
11+
"devDependencies": {
12+
"http-server": "^0.9.0"
13+
}
14+
}
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8">
4+
<link rel="stylesheet" href="styles.css">
5+
<!-- Include IPFS -->
6+
<script src="ipfs.js"></script>
7+
<!-- Include a helper script that starts IPFS -->
8+
<script type="text/javascript" src="start-ipfs.js" charset="utf-8"></script>
9+
</head>
10+
11+
<body>
12+
<div class="center">
13+
<div id="ipfs" class="ipfs" ondragover="event.preventDefault()">
14+
<h1 id="state" class="center"></h1>
15+
<div>
16+
<div id="buttons" class="buttons center">
17+
<button id="start" type="button">Start</button>
18+
<button id="stop" type="button">Stop</button>
19+
</div>
20+
<div id="directory">
21+
<h2>IPFS Settings</h2>
22+
<label for="dir">Data Directory</label>
23+
<input id="dir" type="text" placeholder="IPFS data directory"/>
24+
<br><br>
25+
<label for="signalServerInput">Signal Server</label>
26+
<input id="signalServerInput" type="text" value="188.166.203.82:20000"/>
27+
</div>
28+
</div>
29+
<div id="details"></div>
30+
<div id="peers"></div>
31+
<div id="files">
32+
<h2>Files</h2>
33+
<div id="filesStatus"></div>
34+
<br>
35+
<label for="multihash">Mutihash</label>
36+
<input id="multihash" type="text" placeholder="Multihash"/>
37+
<button id="cat" type="button">Cat</button>
38+
<img id="picture"/>
39+
</div>
40+
<pre id="errors"></pre>
41+
</div>
42+
</div>
43+
44+
<script type="text/javascript">
45+
const rootElement = document.getElementById("ipfs")
46+
const startButton = document.getElementById("start")
47+
const stopButton = document.getElementById("stop")
48+
const output = document.getElementById("state")
49+
const details = document.getElementById("details")
50+
const peers = document.getElementById("peers")
51+
const errors = document.getElementById("errors")
52+
const directory = document.getElementById("directory")
53+
const dirInput = document.getElementById("dir")
54+
const signalServerInput = document.getElementById("signalServerInput")
55+
const files = document.getElementById("files")
56+
const filesStatus = document.getElementById("filesStatus")
57+
const picture = document.getElementById("picture")
58+
const multihashInput = document.getElementById("multihash")
59+
const catButton = document.getElementById("cat")
60+
61+
let ipfs, peerInfo, pollPeersTimer
62+
63+
const ipfsOptions = {
64+
// Directory to which save IPFS data to
65+
IpfsDataDir: dirInput.value,
66+
// IPFS dev server: webrtc-star-signalling.cloud.ipfs.team
67+
SignalServer: signalServerInput.value,
68+
// Local webrtc-star server, you can get it from:
69+
// https://github.com/libp2p/js-libp2p-webrtc-star
70+
// SignalServer: '127.0.0.1:9090',
71+
}
72+
73+
// Start IPFS instance
74+
const start = () => {
75+
if (!ipfs) {
76+
// Update the UI with initial settings
77+
updateView('starting', ipfs)
78+
79+
// Create an IPFS instance
80+
// window.startIpfs() is exposed in ./start-ipfs.js
81+
window.startIpfs(ipfsOptions, (err, node) => {
82+
if (err) {
83+
onError(err)
84+
return
85+
}
86+
87+
ipfs = node
88+
89+
// Get our IPFS instance's info: ID and address
90+
ipfs.id().then((id) => {
91+
peerInfo = id
92+
// Update the UI
93+
updateView('ready', ipfs)
94+
95+
// Poll for peers from IPFS and display them
96+
pollPeersTimer = setInterval(updatePeers, 1000)
97+
peers.innerHTML = '<h2>Peers</h2><i>Waiting for peers...</i>'
98+
})
99+
})
100+
}
101+
}
102+
103+
// Stop IPFS instance
104+
const stop = () => {
105+
if (ipfs) {
106+
if (pollPeersTimer)
107+
clearInterval(pollPeersTimer)
108+
109+
ipfs.goOffline()
110+
ipfs = null
111+
updateView('stopped', ipfs)
112+
}
113+
}
114+
115+
// Fetch file contents from IPFS and display it
116+
const catFile = () => {
117+
// Get the hash to cat from the input field
118+
const multihash = multihashInput.value
119+
120+
// Update UI
121+
picture.innerHTML = multihash ? '<i>Loading...</i>' : ''
122+
picture.className = multihash ? 'picture visible' : 'hidden'
123+
errors.className = 'hidden'
124+
125+
// Get the file from IPFS
126+
if (multihash) {
127+
// IPFS.files.cat()
128+
// https://github.com/ipfs/interface-ipfs-core/tree/master/API/files#javascript---ipfscatmultihash-callback
129+
ipfs.files.cat(multihash)
130+
.then((stream) => {
131+
// Buffer all contents of the file as text
132+
// and once buffered, create a blob for the picture
133+
let buf = []
134+
stream.on('data', (d) => buf.push(d))
135+
stream.on('end', () => {
136+
const blob = new Blob(buf)
137+
picture.src = URL.createObjectURL(blob)
138+
})
139+
})
140+
.catch(onError)
141+
}
142+
}
143+
144+
// Display an error
145+
const onError = (e) => {
146+
console.error(e)
147+
errors.innerHTML = '<br/><span class="error">' + e.stack + '</span>'
148+
errors.className = 'error visible'
149+
}
150+
151+
// Handle file drop
152+
const onDrop = (event) => {
153+
picture.innerHTML = ''
154+
picture.className = 'hidden'
155+
errors.className = 'hidden'
156+
157+
event.preventDefault()
158+
var dt = event.dataTransfer
159+
var files = dt.files
160+
161+
const readFileContents = (file) => {
162+
return new Promise((resolve) => {
163+
const reader = new FileReader()
164+
reader.onload = (event) => resolve(event.target.result)
165+
reader.readAsArrayBuffer(file)
166+
})
167+
}
168+
169+
// TODO: Promise reduce?
170+
for (var i = 0; i < files.length; i++) {
171+
const file = files[i]
172+
console.log("Add file", file.name, file.size)
173+
readFileContents(file)
174+
.then((buffer) => {
175+
// IPFS.files.add()
176+
// https://github.com/ipfs/interface-ipfs-core/tree/master/API/files#javascript---ipfsfilesadddata-options-callback
177+
return ipfs.files.add([{
178+
path: file.name,
179+
content: new ipfs.types.Buffer(buffer)
180+
}])
181+
})
182+
.then((files) => {
183+
console.log("Files added", files)
184+
multihashInput.value = files[0].hash
185+
filesStatus.innerHTML = files
186+
.map((e) => `Added ${e.path} as ${e.hash}`)
187+
.join('<br>')
188+
})
189+
.catch(onError)
190+
}
191+
}
192+
193+
// Get peers from IPFS and display them
194+
const updatePeers = () => {
195+
ipfs.swarm.peers((err, res) => {
196+
// PeerId.toJSON()
197+
// https://github.com/libp2p/js-peer-id/blob/3ef704ba32a97a9da26a1f821702cdd3f09c778f/src/index.js#L106
198+
// Multiaddr.toString()
199+
// https://multiformats.github.io/js-multiaddr/#multiaddrtostring
200+
const peersAsHtml = res
201+
.map((e, idx) => {
202+
return (idx + 1) + '.'
203+
+ e.peer.id.toJSON().id
204+
+ '<br>'
205+
+ e.addr.toString()
206+
+ '<br>'
207+
})
208+
.join('')
209+
210+
peers.innerHTML = res.length > 0
211+
? '<h2>Peers</h2>' + peersAsHtml
212+
: '<h2>Peers</h2><i>Waiting for peers...</i>'
213+
})
214+
}
215+
216+
/* UI functions */
217+
function initView() {
218+
const initElement = (e, className) => {
219+
e.innerHTML = ''
220+
e.className = className
221+
}
222+
223+
// Initial view
224+
const elements = [errors, details, peers]
225+
elements.map((e) => initElement(e, 'hidden'))
226+
errors.innerHTML = ''
227+
output.innerHTML = '🔌 IPFS stopped'
228+
dirInput.value = '/ipfs/' + new Date().getTime()
229+
directory.className = 'visible'
230+
files.className = 'hidden'
231+
filesStatus.innerHTML = ''
232+
picture.innerHTML = ''
233+
startButton.disabled = false
234+
stopButton.disabled = true
235+
multihashInput.value = null
236+
picture.className = 'hidden'
237+
// Remove old event listeners
238+
rootElement.removeEventListener('drop', onDrop)
239+
startButton.removeEventListener('click', start)
240+
stopButton.removeEventListener('click', stop)
241+
catButton.removeEventListener('click', catFile)
242+
// Setup event listeners for interaction
243+
rootElement.addEventListener('drop', onDrop)
244+
startButton.addEventListener('click', start)
245+
stopButton.addEventListener('click', stop)
246+
catButton.addEventListener('click', catFile)
247+
}
248+
249+
function updateView(state, ipfs) {
250+
if (state === 'ready') {
251+
// Set the header to display the current state
252+
output.innerHTML = '🚀 IPFS started'
253+
// Display IPFS info
254+
details.innerHTML = '<div>'
255+
+ '<h2>IPFS Node</h2>'
256+
+ '<b>ID</b><br>'
257+
+ peerInfo.id + '<br><br>'
258+
+ '<b>Address</b><br>'
259+
+ peerInfo.addresses[0] + '<br><br>'
260+
+ '<b>IPFS Data Directory</b><br>'
261+
+ dirInput.value
262+
// Set the file status
263+
filesStatus.innerHTML = '<i>Drop a picture here to add it to IPFS.</i>'
264+
details.className = 'visible'
265+
peers.className = 'visible'
266+
files.className = 'visible'
267+
stopButton.disabled = false
268+
} else if (state === 'starting') {
269+
output.innerHTML = '📡 IPFS starting'
270+
startButton.disabled = true
271+
directory.className = 'hidden'
272+
} else if (state === 'stopped') {
273+
initView()
274+
}
275+
}
276+
277+
// Start the app
278+
initView()
279+
</script>
280+
</body>
281+
</html>

0 commit comments

Comments
 (0)