Skip to content

feat: Non MFS Files API tutorial #303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 67 commits into from
Nov 6, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
9,531 changes: 5,185 additions & 4,346 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.39.0",
"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
33 changes: 25 additions & 8 deletions src/components/Lesson.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ marked.setOptions({
})

const _eval = async (text, ipfs, modules = {}, args = []) => {
await new Promise(resolve => ipfs.on('ready', resolve))

let fn
let result
try {
Expand Down Expand Up @@ -212,6 +210,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 @@ -279,9 +278,15 @@ export default {
}
let output = this.output
let ipfs = await this.createIPFS()

await ipfs.ready
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 @@ -347,12 +352,24 @@ export default {
},
createFile: function (ipfs) {
/* eslint-disable no-new */
new Promise((resolve, reject) => {
ipfs.on('ready', async () => {
await ipfs.add(this.ipfsConstructor.Buffer.from('You did it!'))
resolve()
})
})
return ipfs.add(this.ipfsConstructor.Buffer.from('You did it!'))
},
createTree: function (ipfs) {
/* eslint-disable no-new */
return ipfs.add([
{
content: this.ipfsConstructor.Buffer.from('¯\\_(ツ)_/¯'),
path: 'shrug.txt'
},
{
content: this.ipfsConstructor.Buffer.from(':)'),
path: 'smile.txt'
},
{
content: this.ipfsConstructor.Buffer.from('You did it!'),
path: 'fun/success.txt'
}
], { wrapWithDirectory: true })
},
resetCode: function () {
// TRACK? User chose to reset code
Expand Down
21 changes: 20 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ 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'
import T0005L08 from './tutorials/0005/08.vue'

Vue
.use(VueRouter)
Expand Down Expand Up @@ -96,7 +104,18 @@ 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: '/regular-files-api', component: Landing, props: { tutorialId: '0005' } },
{ path: '/regular-files-api/resources', component: ResourcesLesson, props: { tutorialId: '0005' } },
{ path: '/regular-files-api/01', component: T0005L01 },
{ path: '/regular-files-api/02', component: T0005L02 },
{ path: '/regular-files-api/03', component: T0005L03 },
{ path: '/regular-files-api/04', component: T0005L04 },
{ path: '/regular-files-api/05', component: T0005L05 },
{ path: '/regular-files-api/06', component: T0005L06 },
{ path: '/regular-files-api/07', component: T0005L07 },
{ path: '/regular-files-api/08', component: T0005L08 },
// 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": ["0001", "0004", "0005", "0002"]
}
44 changes: 43 additions & 1 deletion src/static/tutorials.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"url": "basics",
"project": "IPFS",
"title": "P2P data links with content addressing",
"description": "Store, fetch, and create verifiable links between peer-hosted datasets with IPFS and CIDs. It’s graphs with friends!",
"description": "Store, fetch, and create verifiable links between peer-hosted datasets using the IPFS DAG API and CIDs. It’s graphs with friends!",
"lessons": [
"Create a node and return a Content Identifier (CID)",
"Create a new node that's linked to an old one",
Expand Down Expand Up @@ -143,5 +143,47 @@
"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": "regular-files-api",
"project": "IPFS",
"title": "IPFS: Regular Files API",
"description": "The IPFS Regular Files API provides a way to store and share files in a peer-to-peer storage system.",
"lessons": [
"Introducing the Files API",
"Working with files in ProtoSchool",
"Add a file",
"Read the contents of a file",
"Add files in a directory",
"List the files in a directory",
"Read a file in a directory",
"Get all of the files in a directory"
],
"resources": [
{
"title": "Understanding How IPFS Deals with Files",
"link": "https://youtu.be/Z5zNPwMDYGg",
"type": "video",
"description": "This course from IPFS Camp 2019 offers a deep exploration of how IPFS deals with files, including key concepts like immutability, content addressing, hashing, the anatomy of CIDs, what the heck a Merkle DAG is, and how chunk size affects file imports. It also introduces some the joys and pitfalls of the Mutable File System (MFS)."
},
{
"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": "IPFS: Mutable File System (MFS)",
"link": "https://proto.school/#/mutable-file-system",
"type": "tutorial",
"description": "Wish adding files to IPFS felt more like using a traditional name-based file system? Explore 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."
}
]
}
}
4 changes: 2 additions & 2 deletions src/tutorials/0004/10.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const validate = async (result, ipfs) => {

if (!result) {
return { fail: 'You forgot to return a result. Did you accidentally edit the return statement?' }
} else if (result.error) {
return { error: result.error }
} else if (result && typeof result !== 'string') {
return { fail: 'Oops. `secretMessage` should be a string. Did you forget to convert the buffer to a string?' }
} else if (result !== correctMessage) {
Expand All @@ -34,8 +36,6 @@ const validate = async (result, ipfs) => {
logDesc: "Here's the secret message you discovered in the file:",
log: result
}
} else if (result.error) {
return { error: result.error }
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/tutorials/0005/01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

## 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 web 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 Files API vs the DAG API

You can store multiple types of data with IPFS. If you've explored our [P2P Data Links with Content Addressing](https://proto.school/#/basics) or [Blogging on the Decentralized Web](https://proto.school/#/blog) tutorial, you've already seen how you can store primitives, objects and arrays on the network using the DAG API.

The DAG API allows you to use the unique and versatile primitive data structures offered by [IPLD](https://github.com/ipld/ipld) (InterPlanetary Linked Data) within IPFS. You can recognize its methods in js-ipfs (the JavaScript implementation of IPFS) because they take the following format: `ipfs.dag.someMethod()`

The DAG API is the most generic and flexible approach to adding data to the IPFS node, but it's not the most efficient when it comes to the very common use case of sharing files. What if you wanted to share a picture of a kitten, or a larger file like a funny video of your favorite celebrity dog? How would you add these files to the network and provide a way for your friends to see them? How should each 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 add files to an IPFS node, it would be a labor-intensive task.

The Files API, on the other hand, is custom-built for a more specific use case. The Files API prepares files to be placed in the network and ensures that IPFS knows how to access them and handle them efficiently. The Files API is made of two parts: the Regular Files API, which we'll cover in this tutorial, and the Mutable File System (MFS).

## The Regular Files API vs the MFS Files 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 work with files on IPFS. How will this be any different?"

The Mutable File System (MFS) provides an API designed to replicate familiar file system operations such as `mkdir`, `ls`, `cp`, and others, mimicking the way you organize files and directories on a computer. 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 or directory will result in an entirely new address. The MFS Files 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 Files 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. In the Regular Files API you'll find methods like `add`, `cat`, `get` and `ls`.

Unlike the MFS API, which can be recognized in js-ipfs by the format `ipfs.files.someMethod()`, the Regular Files API uses top-level methods that take the format `ipfs.someMethod()`.

The distinction between these two versions of the Files APIs is a bit confusing the moment, but the IPFS team is currently working on revamping them to make the whole Files API more user-friendly. We'll be sure to update our tutorials when things change!
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 a `File` object, as defined by the browser's [File API](https://developer.mozilla.org/en-US/docs/Web/API/File) (not to be confused with the IPFS Files API). Aside from the contents of the uploaded file, a `File` object also contains the following attributes:

* **name** (name of the uploaded file)
* **lastModified** (date the uploaded file was last modified)
* **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) {
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 seems to be wrong. Please click "Reset Code" and try again, taking another look at the instructions and editing only the portion of code indicated. Feeling really stuck? You can click "View Solution" to see our suggested code.` }
}
}

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>
3 changes: 3 additions & 0 deletions src/tutorials/0005/03-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add the files in your browser (available in the `files` array below) to your IPFS node using the `add` method.

**Hint:** You can pass either a single `File` object or an array of `File` objects to the `add` method.
Loading