Using Textile, Threads, & IPFS in your EthDen Hack
Textile is a set of tools to help you and your team build decentralized apps, fast. Textile is primrarily built on IPFS and makes it easy for you or your application to store and distribute data over the IPFS network. Some features of Textile you may find useful include:
- Push files, directories and websites to the IPFS network. Textile's Buckets tool allows you to not only pin files and folders, it allows you to manage those files and folders just like a normal directory, with static paths and names. No CIDs to remember!
- Collaboratively update and manage those files and folders with your team through simple team creation and sharing. Your team can quickly host app assets or entire webpages on IPFS.
- Add decentralized databases to your web, mobile, or desktop applicatin. Create databases on IPFS that are private for one user or shared with many. Threads is an advanced decentralized data protocol and database for IPFS.
- Specify that Threads databases should be private or shared depending on your requirements.
Other things about Textile and Threads you may like include their open source, MIT licenses, active support on the ground at EthDen, and their public Slack group.
Why use Textile at EthDen?
- Pin your first file to a remote IPFS node.
- Pin your website or dApp assets
- Run decentralized databases (called
threads
) in your app. - Host a dynamic "public" folder on IPFS.
Getting Started with Textile
Textile is a command-line interface that gives you access to everything listed above and more. To get started, here's what you need to do:
- Download Textile to your computer. You can find the latest release for on our GitHub releases page. Textile is built for all the common architectures used in Mac (Darwin), Windows, and Linux. If your architecture isn't listed, ping us on Slack and we can give you instructions to build a version ready for your system.
- Run Textile for the first time, the
help
command is a useful place to start.
textile --help
The Textile client.
Usage:
textile [command]
Available Commands:
buckets Manage project buckets
help Help about any command
init Init a new project
login Login
logout Logout
projects Manage projects
switch Switch teams or personal account
teams Team management
whoami Show user or team
Login to Textile
Textile provides a simple login tool that only requires your valid email. By logging in, you will immediately get access to remote IPFS pinning, hosted database services, and more, all of which we'll show you below.
To login:
textile login
Enter your email: [email protected]█
> We sent an email to [email protected] Please follow the steps provided inside it.
Now, go to your inbox and look for the verification email and follow the instructions inside. After complete, your terminal should output a confirmation:
✔ Email confirmed
> Success! You are now logged in. Initialize a new project directory with `textile init`.
That's it, you can now start using Textile, IPFS, and Threads.
Collaborative teams on Textile
By default, you'll be on your own in Textile, you'll probably want to create (or join) a team before you start building.
Create a team
textile teams add <name>
Switch to your new team
You wont be using your new team until you switch to it in your current session. Use the switch team and select your newly created team as follows:
textile switch
Use the arrow keys to navigate: ↓ ↑ → ←
? Switch to:
▸ [email protected] (current)
faketeam
winners
Invite another member to your team
textile teams invite
Enter email to invite: [email protected]█
> Success! We sent [email protected] an invitation to the faketeam team
Join a team
If someone else has already created a team for you to join, they'll invite you by the email address you used when logging in. Their invite will be sent to you as an email containing a verified link to join the team. Click the link and the team should become part of your available team options.
List your teams
textile teams ls
NAME ID
faketeam f62cdc2b-9404-40ed-8467-ea804fcc35f1
winners af5ad38d-0e20-4699-8862-b0d2015ffcac
> Found 2 teams
Projects on Textile
Teams on Textile may create different Projects. Projects are useful to organize resources or user groups in your app. Creating a new one is simple.
First, navigate to the directory where you'd like to build your project,
mkdir ethden
cd ethden/
Next, tell Textile to create a project in this directory. Similar to Git, Textile will create a simple config file in this directly under, .textile/config.yaml
.
textile projects init ethden
> Success! Initialized empty project in /Users/me/ethden/.textile
Because you are have switched to your team, this project should now be available to other members of your team also.
Pin your first file to a remote IPFS node.
Textile includes a textile buckets
tool that makes it simple for you to pin files to IFPS. The files you pin can be used as part or all of the interface to your dApp. You can think of buckets
much like you might already think of buckets on S3 (or if you aren't familiar, just think of them as folders). As an extra bonus, if any bucket you create contains an index.html
file, Textile will host the bucket as a web site at https://<bucket-name>.textile.cafe
. Read on to see an example.
Push files to a bucket
To start pinning files in your Textile project, use the push
sub command. You can push
a single file to a bucket or an entire directory, in which case all contained files and directories are pushed recursively. All paths will be created if they don't exist and you can use push
repeatedly to keep adding more files to a bucket.
Here, we push files for a static web site to a bucket called aaron
:
textile buckets push public/* aaron
Add 44 files? Press ENTER to confirm: █
> Pushing mySite/public/404/index.html to aaron/404/index.html
9.87 kB / 9.87 kB [--------------------------------] 100.00% 78.69 kB p/s 0s
> Pushing mySite/public/404.html to aaron/404.html
9.88 kB / 9.88 kB [--------------------------------] 100.00% 260.14 kB p/s 1s
> Pushing mySite/public/app-b1262bbd5ce4afcb17ea.js to aaron/app-b1262bbd5ce4afcb17ea.js
98.14 kB / 98.14 kB [--------------------------------] 100.00% 307.59 kB p/s 0s
> Pushing mySite/public/app-b1262bbd5ce4afcb17ea.js.map to aaron/app-b1262bbd5ce4afcb17ea.js.map
390.09 kB / 390.09 kB [--------------------------------] 100.00% 376.47 kB p/s 1s
> Pushing mySite/public/chunk-map.json to aaron/chunk-map.json
...
> Success! Pushed 44 files to aaron
Inspecting buckets
You can list the files in a bucket or at any depth in the bucket, similar to listing files locally on your computer:
textile buckets ls aaron/icons
NAME SIZE DIR ITEMS PATH
icon-144x144.png 9130 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-144x144.png
icon-192x192.png 12422 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-192x192.png
icon-256x256.png 16837 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-256x256.png
icon-384x384.png 29004 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-384x384.png
icon-48x48.png 2813 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-48x48.png
icon-512x512.png 22446 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-512x512.png
icon-72x72.png 4425 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-72x72.png
icon-96x96.png 5926 false n/a /ipfs/QmSe8nSJsAW7eJXvMP5gYM6TCkuyJKeU8MusHs2kVBdFMZ/icons/icon-96x96.png
> Found 8 items
Pulling files from a bucket
Use the buckets pull
command to download files from a bucket to your computer. You can pull an entire bucket, a sub tree of a bucket, or a single file.
textile buckets pull aaron/icons/icon-512x512.png ./
> Pulling aaron/icons/icon-512x512.png to icon-512x512.png
22.45 kB / 22.45 kB [--------------------------------] 100.00% 818.35 kB p/s 0s
> Success! Pulled 1 files to ./
Removing files from a bucket
The buckets rm
command is used to remove files or directories from a bucket. Once a bucket is empty, the root bucket directory is deleted and will no longer appear in the list of buckets output from textile buckets ls
.
textile buckets rm aaron/aaron.txt
> Success! Removed aaron/aaron.txt
Accessing bucket files on cloud.textile.io
You can access the latest version of the files in your bucket (without needing to know any CID!) at https://cloud.textile.io/dashboard/<project name>/<bucket name>
. Of course since the data is all stored in IPFS, it's also available over https://gateway.ipfs.io/ipfs/<CID>
. The CID for any Textile bucket or bucket sub directory is listed at the top of the corresponding cloud.textile.io/dahsboard
page and in the output from textile buckets ls
.
Viewing web sites hosted in buckets
Any bucket that contains an index.html
file will be hosted as a web site at https://<bucket-name>.textile.cafe
. In the textile buckets push
example above, we pushed files that make up a static web site to a bucket named aaron
. That web site is automatically available (with TLS!) at https://aaron.textile.cafe.
Threads: add decentralized databases to your app
Want simple Filebase or MongoDB type functionality in your app? Textile provides Threads - A decentralized database built on IPFS. Threads give your app a way to store private data for one user or synchronize data across many peers. For a deep dive over breakfast, read the Threads Whitepaper. For now, here's a quick tour.
The Threads Whitepaper outlines a number of new innovations, some highlights include:
- Standardized key management for securing data created in your apps
- An easy interface to create and update models (think MongoDB)
- A simple way for data owners to invite new members to their database
Technically,
- Each thread is contains a store (where data is kept) and models (the data structures you store and update).
- Threads are collaborative, for one to many users. By default, each thread your app creates for a user is private (fully encrypted) but can then be shared with other users who can then have access to just read or read & write to the same Thread.
- Data is transferred over IPFS, but it is encrypted by keys only available to people invited to the thread.
Getting started with hosted Threads
The easiest way to get started with Threads is through Textile's hosted service. In this case, Threads can leverage your team's Textile resources (buckets, pinning, and networking). First, you'll need to create a Textile app token using the textile
CLI.
Create an app token
App tokens allow you to access Textile resources from within apps you build. You can create new app tokens in your project in just a few seconds.
textile project tokens add
> Selected ethden
> Success! Added new token <your new token>
Use the token in your app
To use your token with your app, simply follow the instructions available in either of the Textile client libraries here (support for other languages and platfirms coming soon!):
- js-textile: a library to authenticate your textile app token and use
- dart-textile: a library to authenticate your textile app token and use dart-threads-client in your app.
Voila, now you have an app running a Threads database over IPFS with Textile ensuring that database content is pinned to the network no matter when or if your users remain online.
Threads app example
The best way to learn how to use Threads is by checkout out our todo list and folder sync example apps.
Local debugging with the Threads daemon
The preceding instructions have you set up to use Textile's hosted Threads server. Sometimes when developing with Threads, it can be helpful to use a local Threads server called threadsd
instead. You can connect an app using any of the Threads client libraries to the local threadsd
, and then use the threads
shell to view models, data, and watch events as they change data in real-time.
Install the local Threads daemon and shell
- Visit the threads releases page. https://github.com/textileio/go-threads/releases
- Download the latest release for your platform, Linux, Windows, or Mac (darwin).
- Install
threadsd
andthreads
(or the.exe
s on Windows) application. - Run the
threadsd
application without any parameters.
tar -xzvf go-threads_v0.1.9_darwin-amd64.tar.gz
x install-threads/
x install-threads/install
x install-threads/threadsd
x install-threads/LICENSE
x install-threads/README.md
x install-threads/threads
cd install-threads/
./install
Moved ./threads to /usr/local/bin
Moved ./threadsd to /usr/local/bin
threadsd
Welcome to Threads!
Your peer ID is 12D3KooWFFCiJt6B8Dog9ECpt7KGfqxjUxNktzpTK4e4mzQ51WPG
Note for MacOS: By default, MacOS will prevent threadsd
from running. After trying and failing once, you'll have to visit System Preferences > Security & Privacy > General, choose to allow threadsd
to run, and then run threadsd
again.
Update your project to use local daemon
Updating your project to use the locally running threadsd
is as simple as setting the dev
flag in the Textile.API
constructor. Here's an example in Javascript:
import {API} from '@textile/textile'
import {Client} from '@textile/threads-client'
const api = new API({
token: "<textile project token>",
deviceId: "<user id>",
dev: true // causes the below client to use the local threadsd
})
await api.start()
const threadsClient = new Client(api.threadsConfig)
Use threads
shell to monitor data updates
Start up the threads
shell which will connect to your local threadsd
:
threads
Successfully connected.
>>>
You first need to specify a store id to operate on using the use
command:
>>> use <store id>
Switched to <store id>
>>>
Note: You can find your store id by logging it or setting a breakpoint in your app when you create a Theads store.
Another note: In reality, you'll want to keep track of store ids you app creates so you can access those stores at a later time.
View all updates to the data in the current store using the listen
command:
>>> listen
<enter> to cancel
{
"ID": "5389d030-22b4-4327-aed5-10ae1f1f14d8",
"files": [],
"owner": "myFolder"
}
{
"ID": "5389d030-22b4-4327-aed5-10ae1f1f14d8",
"files": [
{
"ID": "25ea5bc5-cbef-4619-9380-9725388f873b",
"cid": "",
"files": [],
"isDirectory": false,
"name": "filecoin.pdf"
}
],
"owner": "myFolder"
}
Explore data using the modelFind
and modelFindById
commands.