Skip to content
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

feat: add MFS tutorial #200

Merged
merged 84 commits into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
1493427
Surface MFS tutorials
terichadbourne Apr 22, 2019
21e0e81
Grammar fixes
terichadbourne Apr 22, 2019
0316e88
update lesson validation wording
terichadbourne Apr 22, 2019
c80c954
change _solution to solution
terichadbourne Apr 23, 2019
bd96f59
Merge branch 'code' into feat/mfs-tutorial
terichadbourne Apr 23, 2019
db8d2c7
add missing solution code to mfs lesson 2
terichadbourne Apr 23, 2019
ff96c55
add solution prop to MFS lessons and boilerplates
terichadbourne Apr 23, 2019
a126b30
Merge branch 'code' into feat/mfs-tutorial
terichadbourne Apr 26, 2019
c500fd4
Merge branch 'code' into feat/mfs-tutorial
fsdiogo Apr 26, 2019
8b00bb8
Rework lesson order in MFS tutorial
terichadbourne Apr 26, 2019
196593e
Merge branch 'code' into feat/mfs-tutorial
terichadbourne Apr 29, 2019
ecea23b
Update stat lesson content
terichadbourne Apr 29, 2019
fa33bee
Fix syntax error and validation in stat lesson
terichadbourne Apr 29, 2019
78d9639
update lesson on stating again
terichadbourne Apr 29, 2019
6e201df
swap order of lessons 2 and 3
terichadbourne Apr 29, 2019
4c356ca
Rework messaging for IPFS introk
terichadbourne Apr 29, 2019
09e2af0
Merge branch 'code' into feat/mfs-tutorial
terichadbourne Apr 30, 2019
b786fbb
Apply new logging feature to file upload demo
terichadbourne Apr 30, 2019
39e139a
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 2, 2019
888dfee
Validate directory creation for mkdir (MFS #7)
terichadbourne May 2, 2019
45cec48
chore: simplify js object files logging
fsdiogo May 3, 2019
424c0a6
add validation for missing {parents:true}
terichadbourne May 3, 2019
8f7872c
add validation for use of ls in stat lesson
terichadbourne May 3, 2019
6e4cae3
update text of lessons 3, 4, 5
terichadbourne May 3, 2019
9f9281f
improve formatting of references to root directory
terichadbourne May 3, 2019
d293b45
improve example for mkdir lesson
terichadbourne May 3, 2019
0906027
add validation for other errors in mkdir lesson 7
terichadbourne May 3, 2019
2ed5e24
add blank space around user code area
terichadbourne May 3, 2019
e401847
add validation for matching filenames in #7
terichadbourne May 6, 2019
6655da7
remove console logs
terichadbourne May 6, 2019
ced1bb8
validate ls-ing wrong directory in #7
terichadbourne May 6, 2019
e513197
improve error msg when returning wrong ls in #7
terichadbourne May 6, 2019
2a4a272
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 7, 2019
d78057b
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 7, 2019
66592b6
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 7, 2019
e5d8d94
add boilerplates for lessons 8-12
terichadbourne May 7, 2019
1473267
correct relative filepaths in readme
terichadbourne May 7, 2019
66c06e5
fix typo lesson 7
terichadbourne May 7, 2019
5347613
add lesson 8 text
terichadbourne May 7, 2019
d1abb57
fix typo and scope issues lsn 7
terichadbourne May 7, 2019
13cdf99
update lesson 8 instructions
terichadbourne May 7, 2019
158cbc4
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 8, 2019
6aff4e1
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 8, 2019
d78163f
add globals to boilerplates
terichadbourne May 8, 2019
48e6a9b
add code and first pass validation for lsn 8
terichadbourne May 8, 2019
45ac12e
attempt to test for incorrect use of await
terichadbourne May 8, 2019
e03f04a
test for mistakenly moving directory
terichadbourne May 8, 2019
e81939c
swap order of validation to fix bug
terichadbourne May 8, 2019
312c243
add first draft of files.cp lesson
terichadbourne May 8, 2019
e306c48
tweak lesson 9 solution display
terichadbourne May 8, 2019
3314cbf
first draft of files.read lesson
terichadbourne May 8, 2019
812e4e7
lesson 10 validation edits
terichadbourne May 9, 2019
f751225
fix: lesson 7 validations
fsdiogo May 9, 2019
5e26cea
address await problems in lesson 8
terichadbourne May 9, 2019
e9ec6ff
add text for lesson 11
terichadbourne May 9, 2019
05e5bc7
revamp lesson 8 mv solution
terichadbourne May 10, 2019
7f49d1e
remove lesson 12
terichadbourne May 10, 2019
4cb1298
add initial validation for lesson 11 rm
terichadbourne May 10, 2019
ce71d33
attempt to add test file to non-mfs ipfs
terichadbourne May 10, 2019
4b84b75
Merge branch 'code' into feat/mfs-tutorial
terichadbourne May 13, 2019
13ad8f5
add notes on TBValidated lessons
terichadbourne May 13, 2019
bc3ff5e
chore: lessons cleanup
fsdiogo May 20, 2019
3fc3726
chore: update lesson 09
fsdiogo May 21, 2019
e342f59
feat: lesson 9 now copies file from ipfs
fsdiogo May 22, 2019
b547b15
feat: make lesson 10 work
fsdiogo May 22, 2019
8dce93f
feat: finish lesson 11
fsdiogo May 23, 2019
6b17177
fix: appease linter
fsdiogo May 23, 2019
32181d0
fix: LessonLink spacing
fsdiogo May 23, 2019
c33cfc1
Merge branch 'code' into feat/mfs-tutorial
fsdiogo May 23, 2019
6b9b527
fix: grow file upload container
fsdiogo Jun 3, 2019
b517b9d
chore: apply suggestions from code review
fsdiogo Jun 3, 2019
3b02330
chore: replace folder word with directory
fsdiogo Jun 3, 2019
b7fa36d
chore: rephrase mfs editing
fsdiogo Jun 3, 2019
57881c7
chore: typos
fsdiogo Jun 3, 2019
a9c0350
text edits
terichadbourne Jun 5, 2019
97a94e8
make user name file when copying
terichadbourne Jun 5, 2019
5b17226
improve lesson 9 validation
terichadbourne Jun 5, 2019
7ee253b
read from success.txt in lesson 10
terichadbourne Jun 5, 2019
eef27cd
improve validation for lesson 11
terichadbourne Jun 5, 2019
53bdd02
update headline and lesson titles
terichadbourne Jun 5, 2019
8a6c254
chore: update mfs description
fsdiogo Jun 6, 2019
b9ffb61
fix: add await to ipfs.files.mv
fsdiogo Jun 6, 2019
1c0c52b
chore: tidying up
fsdiogo Jun 6, 2019
f5d62e8
feat: add loading animation
fsdiogo Jun 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
16 changes: 14 additions & 2 deletions src/components/Lesson.vue
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ export default {
lessonKey: 'passed' + self.$route.path,
lessonPassed: !!localStorage['passed' + self.$route.path],
lessonTitle: self.$attrs.lessonTitle,
createTestFile: self.$attrs.createTestFile,
output: self.output,
expandExercise: false,
dragging: false,
Expand Down Expand Up @@ -343,8 +344,10 @@ export default {
}
let output = this.output
let ipfs = await this.createIPFS()
if (this.createTestFile) {
await this.createFile(ipfs)
}
let code = this.editor.getValue()

let modules = {}
if (this.$attrs.modules) modules = this.$attrs.modules
if (this.isFileLesson) args.unshift(this.uploadedFiles)
Expand Down Expand Up @@ -374,11 +377,20 @@ export default {
return this.$attrs.createIPFS()
} else {
let ipfs = this.IPFSPromise.then(IPFS => {
return new IPFS({repo: Math.random().toString()})
this.ipfsConstructor = IPFS
return new IPFS({ repo: Math.random().toString() })
})
return ipfs
}
},
createFile: function (ipfs) {
new Promise((resolve, reject) => {
ipfs.on('ready', async () => {
await ipfs.add(this.ipfsConstructor.Buffer.from('You did it!'))
resolve()
})
})
},
resetCode: function () {
// TRACK? User chose to reset code
this.code = this.$attrs.code || defaultCode
Expand Down
4 changes: 2 additions & 2 deletions src/components/LessonLink.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<router-link :to="to" class="link db pa3 bb b--white green hover-bg-washed-yellow">
<div class="flex">
<div class="green ttu f6" style="min-width: 72px">Lesson {{index}}</div>
<div class="pr2">
<div class="tc green ttu f6" style="min-width: 92px">Lesson {{index}}</div>
<div class="pr3">
<img v-if="lessonPassed('passed' + to)" src="../static/images/complete.svg" alt="complete" style="height: 1rem;"/>
<img v-else-if="lessonCached('cached' + to)" src="../static/images/in-progress.svg" alt="in progress" style="height: 1rem;"/>
<img v-else src="../static/images/not-started.svg" alt="not yet started" style="height: 0.9rem;"/>
Expand Down
34 changes: 23 additions & 11 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ import LessonDataStructures02 from './tutorials/Data-Structures/02.vue'
import LessonDataStructures03 from './tutorials/Data-Structures/03.vue'
import LessonDataStructures04 from './tutorials/Data-Structures/04.vue'
import LessonDataStructures05 from './tutorials/Data-Structures/05.vue'
// import MutableFileSystem01 from './tutorials/Mutable-File-System/01.vue'
// import MutableFileSystem02 from './tutorials/Mutable-File-System/02.vue'
// import MutableFileSystem03 from './tutorials/Mutable-File-System/03.vue'
// import MutableFileSystem04 from './tutorials/Mutable-File-System/04.vue'
// import MutableFileSystem05 from './tutorials/Mutable-File-System/05.vue'
import MutableFileSystem01 from './tutorials/Mutable-File-System/01.vue'
import MutableFileSystem02 from './tutorials/Mutable-File-System/02.vue'
import MutableFileSystem03 from './tutorials/Mutable-File-System/03.vue'
import MutableFileSystem04 from './tutorials/Mutable-File-System/04.vue'
import MutableFileSystem05 from './tutorials/Mutable-File-System/05.vue'
import MutableFileSystem06 from './tutorials/Mutable-File-System/06.vue'
import MutableFileSystem07 from './tutorials/Mutable-File-System/07.vue'
import MutableFileSystem08 from './tutorials/Mutable-File-System/08.vue'
import MutableFileSystem09 from './tutorials/Mutable-File-System/09.vue'
import MutableFileSystem10 from './tutorials/Mutable-File-System/10.vue'
import MutableFileSystem11 from './tutorials/Mutable-File-System/11.vue'

Vue
.use(VueRouter)
Expand Down Expand Up @@ -70,12 +76,18 @@ const routes = [
{ path: '/blog/06', component: LessonBlog06 },
{ path: '/blog/07', component: LessonBlog07 },
// Lessons - MFS
// { path: '/mutable-file-system', component: Landing, props: { tutorialId: 'mutableFileSystem' } },
// { path: '/mutable-file-system/01', component: MutableFileSystem01 },
// { path: '/mutable-file-system/02', component: MutableFileSystem02 },
// { path: '/mutable-file-system/03', component: MutableFileSystem03 },
// { path: '/mutable-file-system/04', component: MutableFileSystem04 },
// { path: '/mutable-file-system/05', component: MutableFileSystem05 },
{ path: '/mutable-file-system', component: Landing, props: { tutorialId: 'mutableFileSystem' } },
{ path: '/mutable-file-system/01', component: MutableFileSystem01 },
{ path: '/mutable-file-system/02', component: MutableFileSystem02 },
{ path: '/mutable-file-system/03', component: MutableFileSystem03 },
{ path: '/mutable-file-system/04', component: MutableFileSystem04 },
{ path: '/mutable-file-system/05', component: MutableFileSystem05 },
{ path: '/mutable-file-system/06', component: MutableFileSystem06 },
{ path: '/mutable-file-system/07', component: MutableFileSystem07 },
{ path: '/mutable-file-system/08', component: MutableFileSystem08 },
{ path: '/mutable-file-system/09', component: MutableFileSystem09 },
{ path: '/mutable-file-system/10', component: MutableFileSystem10 },
{ path: '/mutable-file-system/11', component: MutableFileSystem11 },
// 404
{ path: '*', name: '404' }
]
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": ["dataStructures", "basics", "blog"],
"featured": ["dataStructures", "basics", "blog"]
"all": ["mutableFileSystem", "dataStructures", "basics", "blog"],
"featured": ["mutableFileSystem", "dataStructures", "basics", "blog"]
}
18 changes: 12 additions & 6 deletions src/static/tutorials.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,20 @@
},
"mutableFileSystem": {
"project": "IPFS",
"title": "IPFS as a Mutable File System",
"title": "IPFS: A Mutable File System",
"description": "Store, edit, and share files with with the Mutable File System (MFS).",
"lessons": [
{ "to": "/mutable-file-system/01", "name": "Working with your IPFS node" },
{ "to": "/mutable-file-system/02", "name": "Working with files in ProtoSchool" },
{ "to": "/mutable-file-system/03", "name": "Add a new file to MFS" },
{ "to": "/mutable-file-system/04", "name": "View files in your directory" },
{ "to": "/mutable-file-system/05", "name": "Create a directory" }
{ "to": "/mutable-file-system/01", "name": "Introducing IPFS" },
{ "to": "/mutable-file-system/02", "name": "Check the status of a directory" },
{ "to": "/mutable-file-system/03", "name": "Working with files in ProtoSchool" },
{ "to": "/mutable-file-system/04", "name": "Add a new file to MFS" },
{ "to": "/mutable-file-system/05", "name": "View files in your directory" },
{ "to": "/mutable-file-system/06", "name": "See how CIDs change as data changes" },
{ "to": "/mutable-file-system/07", "name": "Add a directory" },
{ "to": "/mutable-file-system/08", "name": "Move a file" },
{ "to": "/mutable-file-system/09", "name": "Copy a file using a CID" },
{ "to": "/mutable-file-system/10", "name": "Read the contents of a file" },
{ "to": "/mutable-file-system/11", "name": "Remove a file or directory" }
]
}
}
21 changes: 13 additions & 8 deletions src/tutorials/Mutable-File-System/01.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@

## Data added to IPFS is stored in a local node
## IPFS: The InterPlanetary File System

One of the most common questions for those new to IPFS is where content lives when it's added to the network.
[IPFS](https://ipfs.io/), or the InterPlanetary File System, is a peer-to-peer (P2P) networking protocol used to share data on the distributed web. As its full name suggests, you can think of IPFS as a file system, and it has some unique characteristics that make it ideal for safe, decentralized sharing.

As a peer-to-peer data storage system, IPFS allows each user (peer) to host whatever data they'd like locally. Typically you'd install IPFS on your own computer and create a new instance of IPFS (also known as a node) there. That's where your data would live locally, referenced by content addresses (CIDs). Data stored in IPFS can take many forms, but one of the most common use cases is the sharing of tradional files, which we'll learn more about in this tutorial.
If you haven't yet done so, we encourgage you to check out our [Decentralized Data Structures tutorial](https://proto.school/#/data-structures/), where you can 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 on IPFS.

You could choose to share your data or files with your peers when you had a network connection, but if you were the only one hosting a particular resource, it would become unavailable to your peers when your machine went offline. Having multiple peers hosting the same files is what makes them more readily available, and using CIDs is what makes this system secure. We'll talk more about sharing in future tutorials, but for now we'll focus on how to work with files within your own IPFS instance.
## Storing and sharing data in IPFS

## Working with your IPFS node in ProtoSchool
Where does content live when it's added to the IPFS network?

Here in our ProtoSchool tutorials, rather than using your machine itself, we're creating a new IPFS node for you in the browser each time you hit the "Submit" button in a lesson.
As a peer-to-peer data storage system, IPFS allows each user (peer) to host whatever data they'd like locally. When you add first add new content to IPFS, you're really just setting it up on your own machine in a format suitable for sharing via the IPFS protocol. Typically you'd install IPFS on your own computer and create a new instance of IPFS (also known as a node) there. That's where your data would live locally, referenced by content addresses (CIDs). Data stored in IPFS can take many forms, but one of the most common use cases is the sharing of tradional files, which we'll learn more about in this tutorial.
fsdiogo marked this conversation as resolved.
Show resolved Hide resolved

Whenever you see `ipfs.someMethod()` in our lessons, `ipfs` is a variable that refers to your IPFS instance. When you replicate this process on your own machine, you can choose to call your node `ipfs` or `node` or `myNode` or `zebra`... the choice is yours! What's important to know is that the methods we're showing you will only affect your own instance of IPFS.
You could choose to share your data or files with your peers when you had a network connection, but if you were the only one hosting a particular resource, it would become unavailable to your peers when your machine went offline. Having multiple peers hosting the same files is what makes them more readily available, and using CIDs (unique content identifiers created through cryptograhpic hashing) is what makes this system secure. We'll talk more about sharing in future tutorials, but for now we'll focus on how to work with files within your own IPFS instance.

We're creating your IPFS node behind the scenes so you can focus on the content of our lessons, but eventually you'll need to learn to host your own node locally. When you're ready to experiment, you can find instructions for [installing IPFS](https://docs.ipfs.io/introduction/install/) and [initializing your node](https://docs.ipfs.io/introduction/usage/) in our docs.
## Mutable File System
Because files in IPFS are content-addressed and immutable, they can be complicated to edit. **Mutable File System (MFS)** is a tool built into IPFS that lets you treat files like you normally would in a name-based filesystem — you can add, remove, move, and edit MFS files and have all the work of updating links and hashes taken care of for you.
fsdiogo marked this conversation as resolved.
Show resolved Hide resolved

MFS is accessed through the `files` commands in the IPFS CLI (command-line interface) and API. In this tutorial we'll explore the [Files API](https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/FILES.md#the-files-api-aka-mfs-the-mutable-file-system).

If you've worked with files and folders (directories) from the command line before, many of the MFS methods will look very familiar!

Let's start exploring how we can work with files in IPFS!
2 changes: 1 addition & 1 deletion src/tutorials/Mutable-File-System/01.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<Lesson
:text="text"
lessonTitle="Working with a local IPFS node">
lessonTitle="Introducing IPFS">
</Lesson>
</template>

Expand Down
2 changes: 1 addition & 1 deletion src/tutorials/Mutable-File-System/02-exercise.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
First, upload one or more files by dropping it below or clicking to make a selection from your file explorer. Next, in the code editor, remove the comment markers that precede `return files.length` within the `run` function, which will make the function calculate how many files have been uploaded (the "length" of an array is the number of items it contains). Open your inspector and select `Console` before you hit the "Submit" button. What do you see?
Run `files.stat` to check the status of your root directory ( `/` ) in IPFS. Be sure to return your result.
27 changes: 24 additions & 3 deletions src/tutorials/Mutable-File-System/02.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
As a matter of security, web browsers don't let us change files that live on your computer. Therefore you'll need to upload one or more files to the browser that you can use throughout this tutorial.
## Working with files in ProtoSchool
Here in our ProtoSchool tutorials, rather than using your machine itself, we're creating 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here in our ProtoSchool tutorials, rather than using your machine itself, we're creating a new IPFS node for you in the browser

I'm not sure I understand this sentence...is it referring to the difference between running a daemon on your machine and running it in the browser?

I think this could be confusing to people, the browser is running on my machine, so how is IPFS not running on my machine?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this sentence...is it referring to the difference between running a daemon on your machine and running it in the browser?

Yeah, I think @terichadbourne was trying to differentiate between having to install IPFS and run a daemon in your terminal from running an on-demand disposable one in the browser.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, so essentially you can do all of ProtoSchool without ever learning to install IPFS. So we need to call out that we're skipping a whole step... which I can't describe accurately because I'm never done it NOT in the browser. Want to propose something that sounds accurate to you while still explaining what we're doing in the background?


Within each exercise, you'll see that you can upload from your computer either by dragging and dropping or selecting 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.
We're creating your IPFS node behind the scenes so you can focus on the content of our lessons, but eventually you'll need to learn to host your own node locally. When you're ready to experiment, you can find instructions for [installing IPFS](https://docs.ipfs.io/introduction/install/) and [initializing your node](https://docs.ipfs.io/introduction/usage/) in our docs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

host your own node locally

Perhaps needs a rephrase? When running IPFS in the browser it is running locally as well, it's just running in your browser's sandbox.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never done it the other way, so perhaps you can help me describe it more accurately. Would it be "eventually you'll need to learn to IPFS and run a daemon in your terminal"?

Copy link
Member Author

@terichadbourne terichadbourne Jun 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know how this sounds to you @alanshaw. Does it address your concerns?

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're creating your IPFS node behind the scenes so you can focus on the content of our lessons, but eventually you'll need to learn to host your own node locally by installing IPFS and running a daemon in your terminal. When you're ready to experiment, you can find instructions for installing IPFS and initializing your node in our docs.


To practice, let's upload one or more files from your computer and create a console log to see what's been received by the browser as the `files` array.
As mentioned previously, methods associated with the Mutable File System are part of the Files API, so they'll take the format of `ipfs.files.someMethod()`. Let's take a look at a simple method you can start using even before you've added any files to your IPFS node.

## Exploring your IPFS node with `ipfs.files.stat`
When working with your IPFS node, you'll often want to check the status of a file or directory. You can do this with `ipfs.files.stat`, passing in the path you'd like to check on.

For example, to check the status of a directory called `stuff` located within our root directory ( `/` ), we could call the method like so:

`await ipfs.files.stat('/stuff/')`
fsdiogo marked this conversation as resolved.
Show resolved Hide resolved

This method returns an object with some essential data about our file or directory:

* **hash** (a string with the cryptographic hash)
* **size** (an integer with the file or folder size in Bytes)
* **cumulativeSize** (an integer with the size of the DAGNodes making up the file in Bytes)
* **type** (a string that can be either `directory` or `file`)
* **blocks** (if type is `directory`, this is the number of files in the directory; if type is `file`, it's the number of blocks that make up the file)
* **withLocality** (a boolean to indicate if locality information are present)
* **local** (a boolean to indicate if the queried dag is fully present locally)
* **sizeLocal** (an integer indicating the cumulative size of the data present locally)

It's important to note that you can `stat` your IPFS node even when you don't have anything in it yet. Even empty nodes have CIDs (hashes) that represent their contents.
fsdiogo marked this conversation as resolved.
Show resolved Hide resolved
53 changes: 36 additions & 17 deletions src/tutorials/Mutable-File-System/02.vue
Original file line number Diff line number Diff line change
@@ -1,46 +1,65 @@
<template>
<FileLesson
<Lesson
:text="text"
:code="code"
:validate="validate"
:modules="modules"
:overrideErrors="true"
:exercise="exercise"
lessonTitle="Working with files in ProtoSchool">
</FileLesson>
:solution="solution"
lessonTitle="Check the status of a directory" />
</template>

<script>
import FileLesson from '../../components/File-Lesson.vue'
import Lesson from '../../components/Lesson.vue'
import text from './02.md'
import exercise from './02-exercise.md'

const validate = async (result, ipfs) => {
if (!result || typeof result === 'undefined') {
return { fail: "Looks like you forgot to return a result. Remember to remove the '//' on Line 5." }
} else if (typeof result === 'number') {
const fileCount = result > 1 ? `${result} files` : '1 file'
return { success: `You successfully uploaded ${fileCount}! Check out your console in the inspector. The last entry there is the \`files\` array your browser now has access to. Click the triangle to expand its contents and see what fields are included.` }
} else {
return { fail: 'Something is wrong. Reset the code and see the instructions.' }
const correctHash = "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"

if (!result) {
return { fail: 'Oops! You forgot to return a result :(' }
} else if (!!result & !result.hash) {
return { fail: "That result doesn't look right. Are you sure you ran the `stat` method on your empty root directory?" }
} else if (!!result && result.hash === correctHash) {
return {
success: 'Success! You did it!',
logDesc: "Here's the status of your root directory (`/`). Notice that it has a hash (CID) even though it doesn't have contents yet. Every empty IPFS node has this exact same hash, because their non-existent contents are identical!",
log: result
}
}

// Output the default error if we haven't caught any
return { error: result.error }
}

const code = `/* global ipfs */

const run = async () => {
// your code goes here
}

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

const solution = `/* global ipfs */

const run = async () => {
return await ipfs.files.stat('/')
}

return run
`

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

export default {
components: {
FileLesson
Lesson
},
data: () => {
return { text, validate, code, modules, exercise }
return { text, validate, code, modules, exercise, solution }
}
}
</script>
4 changes: 1 addition & 3 deletions src/tutorials/Mutable-File-System/03-exercise.md
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
Let's add some files to IPFS using MFS. Since `files` is an array representing the files currently available to us in the browser, we'll need to loop through the array and use `files.write()` to add each file we find there to IPFS, one at a time. (Only have a single file uploaded? No problem!)

Put your files in the root directory (`/`) and be sure to add the name of each file to the path when you add it (**hint:** the file object in the browser stores the filename as `file.name`). Be sure to set up your options so that a new file is created when one isn't found at the given path.
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.
fsdiogo marked this conversation as resolved.
Show resolved Hide resolved
Loading