Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
da63860
feat: first draft of first lesson
dominguesgm Sep 19, 2019
07788f6
feat: draft of the second lesson done. also bumped ipfs version
dominguesgm Sep 24, 2019
a485251
feat: first draft of the 3rd lesson
dominguesgm Sep 26, 2019
9c83fd5
chore: first draft of the 4th lesson
dominguesgm Oct 2, 2019
f312363
chore: first draft of the 5th lesson
dominguesgm Oct 2, 2019
99c83b4
feat: first draft of 6th and last lesson
dominguesgm Oct 3, 2019
603cdb1
chore: revisit lesson 2: change information on add method argument
dominguesgm Oct 3, 2019
7979d0b
Er suggestions nonmfs (#304)
Oct 10, 2019
443d50c
chore: made several revisions from feedback. missing discussion on di…
dominguesgm Oct 17, 2019
38421ac
copy edits to lesson 1
terichadbourne Oct 18, 2019
2cb95f8
copy edits to lesson 2
terichadbourne Oct 18, 2019
3598c68
copy edits to lesson 3
terichadbourne Oct 18, 2019
721179a
fix typos
terichadbourne Oct 18, 2019
270d7b2
remove old comments from Vue files
terichadbourne Oct 18, 2019
e952f8b
add MFS tutorial to resources page
terichadbourne Oct 18, 2019
372a164
update featured courses
terichadbourne Oct 21, 2019
383d196
fix typo
terichadbourne Oct 21, 2019
ae27adb
copy edits to lesson 4
terichadbourne Oct 21, 2019
60518e3
chore: update approach to lesson 5
dominguesgm Oct 22, 2019
5ac8aa5
Merge branch 'feat/tutorial-nonmfs' of github.com:ProtoSchool/protosc…
dominguesgm Oct 22, 2019
c844570
chore: update lesson 6 to match lesson 5
dominguesgm Oct 22, 2019
ca3d27e
chore: added content to lesson 5
dominguesgm Oct 22, 2019
2f1c7bf
copy edits to Lesson 5k
terichadbourne Oct 23, 2019
8e32c38
fix tutorial path
terichadbourne Oct 23, 2019
6fb2b60
add IPFS Camp course to resources
terichadbourne Oct 23, 2019
8e5c7e9
fix: fixed bug causing race conditions on fast executing user code
dominguesgm Oct 24, 2019
69de401
copy edits to lesson 6
terichadbourne Oct 24, 2019
aae72cb
add resulting code block sample to L6
terichadbourne Oct 24, 2019
a82f488
chore: added lesson on cat file inside directory
dominguesgm Oct 25, 2019
64297d8
Merge branch 'feat/tutorial-nonmfs' of github.com:ProtoSchool/protosc…
dominguesgm Oct 25, 2019
7134742
copy edits to lesson 7
terichadbourne Oct 25, 2019
0990fda
feat: improved lessons 7 and 8
dominguesgm Oct 28, 2019
a2f0191
feat: made some improvements to lesson 5
dominguesgm Oct 28, 2019
19d7afb
lesson 7 copy edits
dominguesgm Oct 28, 2019
3ee0f22
copy edit to lesson 5 success msg
terichadbourne Oct 28, 2019
d9863fc
lesson 8 copy edits, adding ls comparison
terichadbourne Oct 28, 2019
325620b
fix merge issue
terichadbourne Oct 28, 2019
db2907a
update references to Regular Files API
terichadbourne Oct 28, 2019
e36ba80
update tutorial description
terichadbourne Oct 28, 2019
8cf4920
fix: lesson 1: add format for mfs files API method calls
dominguesgm Oct 29, 2019
8164af5
fix copy paste errors
terichadbourne Oct 29, 2019
30dde25
mention IPLD when describing DAG API
terichadbourne Oct 29, 2019
b9851ff
change tutorial url
terichadbourne Oct 29, 2019
4ba1e8e
chore: minor changes
dominguesgm Oct 29, 2019
9c17177
Merge branch 'feat/tutorial-nonmfs' of github.com:ProtoSchool/protosc…
dominguesgm Oct 29, 2019
21ea889
chore: update with most of the changes suggested by Alan
dominguesgm Oct 31, 2019
4e66138
Merge branch 'code' into feat/tutorial-nonmfs
terichadbourne Nov 1, 2019
845489e
Use ipfs in path in src/tutorials/0005/07.md
terichadbourne Nov 1, 2019
7f83c47
Apply suggestions from code review
terichadbourne Nov 1, 2019
873b6e9
add /ipfs/ to paths
terichadbourne Nov 1, 2019
98f17d3
incorporate feedback from Alan & Marcin
terichadbourne Nov 1, 2019
d9b45ec
chore: change main solution in lesson 05
dominguesgm Nov 4, 2019
90ed173
chore: updated file structure and contents
dominguesgm Nov 4, 2019
75bb007
chore: update src/tutorials/0005/07-exercise.md
dominguesgm Nov 4, 2019
59c83f5
chore: updated validation for lessons 3, 4, and 5. Fixed a bug in val…
dominguesgm Nov 5, 2019
9a09a62
Merge branch 'feat/tutorial-nonmfs' of github.com:ProtoSchool/protosc…
dominguesgm Nov 5, 2019
f72672f
chore: update to lesson 6 validation
dominguesgm Nov 5, 2019
898990b
chore: update feedback on lesson 7
dominguesgm Nov 5, 2019
cc946fa
chore: update lesson 8 validation
dominguesgm Nov 5, 2019
a26cdca
remove all references to 'root' directory
terichadbourne Nov 5, 2019
07d5112
imrpove catch-all error msg
terichadbourne Nov 5, 2019
f085853
tweaks to error messages
terichadbourne Nov 5, 2019
a4bbd17
move javascript hints from solution to hints in exercise
terichadbourne Nov 5, 2019
de3e8e5
chore: update validation for lessons 5 and 7 according to comments
dominguesgm Nov 6, 2019
6df2537
validation tweaks + new override
terichadbourne Nov 6, 2019
721ef5a
rename variable
terichadbourne Nov 6, 2019
6cd313c
minor copy edit
terichadbourne Nov 6, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,024 changes: 4,220 additions & 3,804 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
},
"dependencies": {
"async": "^2.6.1",
"cids": "^0.5.6",
"cids": "^0.7.1",
"highlight.js": "^9.12.0",
"ipfs": "^0.36.4",
"ipfs": "^0.37.1",
"ipfs-css": "^0.6.0",
"marked": "^0.4.0",
"monaco-editor": "^0.6.1",
"p-timeout": "^3.2.0",
"raw-loader": "^0.5.1",
"shallow-equal": "^1.0.0",
"tachyons": "^4.11.1",
Expand Down
30 changes: 30 additions & 0 deletions src/components/Lesson.vue
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export default {
lessonKey: 'passed' + self.$route.path,
lessonPassed: !!localStorage['passed' + self.$route.path],
createTestFile: self.$attrs.createTestFile,
createTestTree: self.$attrs.createTestTree,
output: self.output,
showUploadInfo: false,
expandExercise: false,
Expand Down Expand Up @@ -282,6 +283,9 @@ export default {
if (this.createTestFile) {
await this.createFile(ipfs)
}
if (this.createTestTree) {
await this.createTree(ipfs)
}
let code = this.editor.getValue()
let modules = {}

Expand Down Expand Up @@ -354,6 +358,32 @@ export default {
})
})
},
createTree: function (ipfs) {
/* eslint-disable no-new */
new Promise((resolve, reject) => {
ipfs.on('ready', async () => {
await ipfs.add([
{
content: this.ipfsConstructor.Buffer.from('This is file1.txt in /root/foo!'),
path: '/root/foo/file1.txt'
},
{
content: this.ipfsConstructor.Buffer.from('This is file2.txt in /root/foo!'),
path: '/root/foo/file2.txt'
},
{
content: this.ipfsConstructor.Buffer.from('This is file3.txt in /root/foo!'),
path: '/root/foo/file3.txt'
},
{
content: this.ipfsConstructor.Buffer.from('This is file4.txt, which is in /root/bar!'),
path: '/root/bar/file4.txt'
}
])
resolve()
})
})
},
resetCode: function () {
// TRACK? User chose to reset code
this.code = this.$attrs.code || defaultCode
Expand Down
19 changes: 18 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ import T0004L08 from './tutorials/0004/08.vue'
import T0004L09 from './tutorials/0004/09.vue'
import T0004L10 from './tutorials/0004/10.vue'
import T0004L11 from './tutorials/0004/11.vue'
import T0005L01 from './tutorials/0005/01.vue'
import T0005L02 from './tutorials/0005/02.vue'
import T0005L03 from './tutorials/0005/03.vue'
import T0005L04 from './tutorials/0005/04.vue'
import T0005L05 from './tutorials/0005/05.vue'
import T0005L06 from './tutorials/0005/06.vue'
import T0005L07 from './tutorials/0005/07.vue'

Vue
.use(VueRouter)
Expand Down Expand Up @@ -96,7 +103,17 @@ const routes = [
{ path: '/mutable-file-system/08', component: T0004L08 },
{ path: '/mutable-file-system/09', component: T0004L09 },
{ path: '/mutable-file-system/10', component: T0004L10 },
{ path: '/mutable-file-system/11', component: T0004L11 },
{ path: '/mutable-file-system/01', component: T0004L11 },
// Tutorial 0005
{ path: '/file-api', component: Landing, props: { tutorialId: '0005' } },
{ path: '/file-api/resources', component: ResourcesLesson, props: { tutorialId: '0005' } },
{ path: '/file-api/01', component: T0005L01 },
{ path: '/file-api/02', component: T0005L02 },
{ path: '/file-api/03', component: T0005L03 },
{ path: '/file-api/04', component: T0005L04 },
{ path: '/file-api/05', component: T0005L05 },
{ path: '/file-api/06', component: T0005L06 },
{ path: '/file-api/07', component: T0005L07 },
// 404
{ path: '*', name: '404', component: NotFound, props: { notFound: true } }
]
Expand Down
3 changes: 2 additions & 1 deletion src/pages/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export default {

<style scoped>
.tutorial-tile {
max-width: 49%
max-width: 49%;
min-height: 167px;
}
.tutorial-tile a {
text-decoration: none;
Expand Down
4 changes: 2 additions & 2 deletions src/static/courses.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"all": ["0004", "0001", "0002", "0003"],
"featured": ["0004", "0001", "0002", "0003"]
"all": ["0004", "0005", "0001", "0002", "0003"],
"featured": ["0004", "0001", "0002", "0003", "0005"]
}
29 changes: 29 additions & 0 deletions src/static/tutorials.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,34 @@
"description": "You've seen the IPFS Files API. Now explore the IPFS DAG API, where you'll use CIDs to create verifiable links between datasets."
}
]
},
"0005": {
"url": "file-api",
"project": "IPFS",
"title": "IPFS: Regular File API",
"description": "The IPFS File API provides a way to store and share files in a peer-to-peer storage system",
"lessons": [
"Introducing the File API",
"Working with files in ProtoSchool",
"Add a file with the API",
"Read the contents of a file",
"Add files in a directory",
"List the files in a directory",
"Get all of the files in a directory"
],
"resources": [
{
"title": "JS-IPFS Files API",
"link": "https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/FILES.md",
"type": "docs",
"description": "Notice that these docs contain two sections, one for top-level methods relevant to files, which we learned about in this tutorial, and one for the Mutable File System (MFS)."
},
{
"title": "P2P Data Links with Content Addressing",
"link": "https://proto.school/#/basics/",
"type": "tutorial",
"description": "You've seen the IPFS Files API. Now explore the IPFS DAG API, where you'll use CIDs to create verifiable links between datasets."
}
]
}
}
23 changes: 23 additions & 0 deletions src/tutorials/0005/01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

## IPFS: The InterPlanetary File System

[IPFS](https://ipfs.io/) is a peer-to-peer (P2P) networking protocol used to share data on the distributed web. You can think of it as a file system with some unique characteristics that make it ideal for safe, decentralized sharing.

If you haven't yet done so, we encourage you to check out our [Decentralized Data Structures](https://proto.school/#/data-structures/) tutorial, to learn all about the decentralized web and how it compares to the one you're accustomed to. There you'll learn all about content addressing, cryptographic hashing, Content Identifiers (CIDs), and sharing with peers, all of which you'll need to understand to make the most of this tutorial.

## The File API vs the DAG API

You can store multiple types of data with IPFS. If you've gone through our Decentralized Data Structures tutorial — or even [Blogging on the Decentralized Web](https://proto.school/#/blog) — you already know you can store primitives, objects and arrays in the network.

The DAG API is the most generic approach to write data to the IPFS node. What if you want to share a picture of a kitten? How would you upload it to the network and provide a way for your friends to see it? What about a larger file, such as a funny video? How should the file be placed in the Directed Acyclic Graph (DAG) — in a single block or split into chunks? These are optimization details that fall beyond the scope of the DAG API. Though it would be possible to use the DAG API to write files to an IPFS node, it would be a labour intensive task.

You can think of the File API as an abstraction layer above the DAG API. The File API prepares files to be placed in the network, and ensures that IPFS knows how to access them. The details of what this API actually does will be covered later in this tutorial.

## The Regular File API vs the MFS File API

If you've read our [Mutable File System tutorial](https://proto.school/#/mutable-file-system), you may be thinking, "I've already learned how to use files on IPFS. How will this be any different?"

The Mutable File System (MFS) provides a File API designed to replicate familiar file-system operations such as `mkdir`, `ls`, `cp`, and others. However, the way that content is addressed in IPFS makes it an immutable file system. The address to a file or directory depends on its contents, so any change to a file will result in an entirely new address. The MFS File API works on a familiar looking file system with regular paths — like `/some/stuff` — in the local IPFS node, which hides the complexity of immutable content addressing.

Although MFS is very useful, the abstraction it provides hides some of the inner workings of IPFS. The Regular File API we will discuss here is instead a "bare bones" approach to managing files in IPFS. It trades the powerful abstractions of MFS for a scheme which helps you understand what is actually happening in the file system.

17 changes: 17 additions & 0 deletions src/tutorials/0005/01.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<Lesson :text="text" />
</template>

<script>
import Lesson from '../../components/Lesson'
import text from './01.md'

export default {
components: {
Lesson
},
data: () => {
return { text }
}
}
</script>
1 change: 1 addition & 0 deletions src/tutorials/0005/02-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
First, upload one or more files by dragging and dropping below or clicking to make a selection from your file explorer. Next, in the code editor, remove the comment markers (`//`) that precede `return files` within the `run` function.
12 changes: 12 additions & 0 deletions src/tutorials/0005/02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
As a matter of security, web browsers don't let us directly change files that live in your computer's file system. Therefore you'll need to upload one or more files to the browser that you can use throughout this tutorial.

Within each exercise, you'll see that you can upload files from your computer either by dragging and dropping or selecting them from your file explorer. If you look closely at the `run` function in the code editor, you'll notice that it now takes an argument `files`. When you upload files from your computer, we'll make sure they're passed into the function as the `files` array. As long as you don't refresh your browser, these files will remain accessible for the next lesson in the tutorial, but you'll also have the option to upload different files to work with for each lesson.

Each element in this `files` array will be of type `File`. You can find more about the `File` type [here](https://developer.mozilla.org/en-US/docs/Web/API/File). Aside from the contents of the uploaded file, a `File` type also contains the following attributes:

* **name** (name of the uploaded file)
* **lastModified** (date the uploaded file was last modified in)
* **size** (size of the uploaded file)
* **type** (type of the uploaded file)

To practice, let's upload one or more files from your computer and take a look at what's been received by the browser as the `files` array.
56 changes: 56 additions & 0 deletions src/tutorials/0005/02.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<template>
<FileLesson
:text="text"
:code="code"
:validate="validate"
:modules="modules"
:exercise="exercise"
:solution="solution" />
</template>

<script>
import FileLesson from '../../components/FileLesson.vue'
import text from './02.md'
import exercise from './02-exercise.md'
import { logFiles } from '../../utils/files'

const validate = async (result, ipfs) => {
if (!result || typeof result.length === 'undefined') {
return { fail: 'Looks like you forgot to return a result. Did you forget to remove the `//` before `return files`?' }
} else if (typeof result.length === 'number') {
const fileCount = result.length > 1 ? `${result.length} files` : '1 file'
return {
success: `You successfully uploaded ${fileCount}!`,
logDesc: "Check out the data below to see the data now accessible in the `files` array. Note that these files are only in the browser right now. In the next lesson we'll see how to add them to IPFS.",
log: logFiles(result)
}
} else {
return { fail: 'Something is wrong. Reset the code and see the instructions.' }
}
}

const code = `const run = async (files) => {
/* remove the '//' on the line below to complete this challenge */
// return files
}
return run
`

const solution = `const run = async (files) => {
return files
}

return run
`

const modules = { cids: require('cids') }

export default {
components: {
FileLesson
},
data: () => {
return { text, validate, code, modules, exercise, solution }
}
}
</script>
4 changes: 4 additions & 0 deletions src/tutorials/0005/03-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Let's try to add a file to your IPFS node! First, try to upload one or more files.

**Hint:** You can pass either a `File` or an array of `File`s to the `add` method.

41 changes: 41 additions & 0 deletions src/tutorials/0005/03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

## Working with files in ProtoSchool
Here in our ProtoSchool tutorials, we create a new IPFS node for you in the browser each time you hit the "Submit" button in a lesson. Whenever you see `ipfs.someMethod()` in our lessons, `ipfs` is a variable that refers to your IPFS instance, also known as a node. The actions that you take only affect your own IPFS node, not nodes belonging to your peers.

We create this special IPFS node behind the scenes, so you can focus on the content of our lessons. To host a fully functional IPFS node of your own, though, IPFS must be installed on your machine, and a local daemon running in your terminal. If you haven't already experimented with this, visit our docs to learn how to [install IPFS](https://docs.ipfs.io/guides/guides/install/) and [initialize your node](https://docs.ipfs.io/introduction/usage/#initialize-the-repository).

As mentioned previously, the methods discussed in this tutorial are part of the [Files API](https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/FILES.md). Check the documentation for more specific details, such as options for each API function.

## Add a file

First let's learn how to add a file to your IPFS node. We'll do this by executing the following expression:

```javascript
await ipfs.add(data, [options], [callback])
```

So if we had a file object in our browser, accessible via a variable catPic, and we wanted to add it to our IPFS node, we could do it like so:

```javascript
await ipfs.add(catPic)
```

You can find the full documentation for this method [here](https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/FILES.md#add).

It's important to note that whether you want to add a `File` or multiple `File`s, you can pass either a `File` or an array of `File`s as an argument to the `add` method.

The `add` function returns a `Promise`, so you can place an `await` before the function call to block the execution until the return value of the promise is ready to be used.

The result of this `Promise` is an array of objects with the following structure:
```javascript
{
path: string,
hash: string,
size: number
}
```

This `hash` is what we call a `CID`, a generated address based on the content of the node. For a more in depth look of how `CID`s are generated and what they are, feel free to take a look at the [Decentralized data structures](https://proto.school/#/data-structures) tutorial.

In a future lesson, we will learn how to use this `hash`, or `CID`, to get the contents of a file.

Loading