Introducing the Textile Desktop Series

Textile is expanding quickly. Our next target? Your desktop and browser.

Photo by Norbert Levajsics on Unsplash

This week the Textile team is proud to kickoff our new ‘Textile Desktop Series’. As some of you way be aware, we’ve recently started to expand some of our developer tools and products to make it easier for folks to build awesome tools and apps on top of Textile protocols and libraries. These new tools are already starting to see some use from external developers and Textile early adopters.

But its not just external developers who are benefiting from these new tools. Textile is also expanding our desktop offerings to make it easier to setup your own Textile peers and Cafes. We’ve even started working on a Textile Photos Desktop edition, and a super handy Textile tray app. So to help get other developers interested and up-to-date with our latest work in this area, were going to showcase the work we’re doing, as we’re doing it. Each time we add a new feature, or expand an underlying library, we’ll try to add it to this blog series. Think of it as our desktop odyssey 😉.

New Tools

Just this past week, Textile stealthily released two new ‘products’. The first, the Textile tray app, is bundled with go-textile, and provides a minimalist go-textile install with one-click convenience (grab the app releases here). Basically, it is a simple Electron-based (we actually use go-astilectron to bridge the gap between go-textile and Electron) tray app that runs a Textile node in the background. It exposes that node’s REST API so that other apps running on your local machine can access it. Right now, that list of other apps is empty 😬… but the plan is to a) start building Textile-based apps and bundling them up with the tray app, and b) to get other developers to start thinking about building desktop (Electron, etc) and browser (React, etc) apps on top of Textile. Come talk to us in our Slack channel if you think that could be you!

The second product we quietly released recently was js-http-client. This is a super handy Javascript (supports Node and browser) wrapper library around the Textile REST API. With it, developers can now leverage advanced Textile functionality on the desktop with just a little bit of Javascript! This is cool for a number of reasons, not least because it means you don’t need to know Go or mobile software development to get started with Textile. So in this first installment of the Textile Desktop Series, we’ll do a quick introduction to js-http-client to show you how easy it is to start hacking on your next Textile project.

Getting Started

First, let’s grab the latest release of the Textile desktop tray app. Just download and unzip it. Its ready to run. On a Mac, just move it into your Applications folder and you’ve installed it. Easy. Run it like you’d run any normal app. Right now, there’s no configuring, no on-boarding, nothing. You should see a little Textile logo in your desktop’s tray. On Linux and Windows, this might require a little bit more setup… see our go-textile README for all the nitty-gritty details.

Now we’re ready to start interfacing with this tray app peer. Its running on port 40602 by default, but you can configure that if you know what you’re doing. So to make things as easy (and fast) as possible to get going with Textile, we’ve spent a bunch of time recently working on new developer tools. The first tool we’ll introduce is textile-cookies. These are really simple app templates that have js-http-client baked in from the start, with some simple example scripts and views to play around with. We’ll keep making more as we need them, but for now we have node, react, and electron cookies ready to use. You certainly don’t need these to get going with js-http-client, but they make spinning up new apps really easy:

# If you have Python installed
pip install cookiecutter --user
# Or, if you don't want to use Python...
brew install cookiecutter # OSX only
pipsi install cookiecutter # Linux/OSX only
sudo apt-get install cookiecutter # Debian/Ubuntu

Then, its just a matter of using the cookiecutter template and ‘checking out’ the one you want:

cookiecutter gh:textileio/textile-cookies --checkout react

The tool will ask you a series of questions (your GitHub handle, your app’s name, etc) and create a new app for you. In this case, a fairly minimal React app. Right away, you can start up the app, test it out, change things, break things, and get a feel for working with Textile’s APIs:

cd my-awesome-app
yarn install
yarn start

This is essentially a create-react-app app, with some extra goodies (via craco) to enable more fine-grained control of the build process. But that’s not the cool part. The cool part is, its designed to work with js-http-client out of the box. The default app simply displays your node’s default account address. But its easy to start to expand things… so let’s do that now.

Next Steps

Our explore repo (which you should check out) has some examples of early apps created on top of Textile. One of those demo apps is based on a simple React app. So let’s build that one ‘from scratch’ here. Starting with our React template, all we really need to implement is a setProfile method on our Store and we’re 60% of the way there. Then, we’ll implement a profile view using React Semantic UI components, and we’re done. Easy peasy 😉.

Well, not quite that easy. This is actually a pretty complicated example for such a simple UI. That’s because, changing or updating your Textile avatar requires you to a) create a new (or use an existing) thread, b) add a photo to said thread, c) extract the added file information, and then d) change your avatar information. Creating a new thread in-and-of-itself requires several steps to do it right. Luckily, all of these steps can be done really easily using the Textile API. So let’s dig in. For the impatient, here’s the full diff from cookie to ‘completed’ app, for the curious, keep reading 👇.

Modify your Store

Here’s the diff. You’re really just adding a few imports, and a new method called setProfile. So let’s work through this diff piece by piece to make sure we’re all on the same page:

View the raw gist

First things first, on line 22 we check if our app has passed us a username string. If we have, then we’ll process this. We could update username and avatar at the same time, though our UI doesn’t really support this. Anyway, if we are going to update the username, we simply pass this string directly to the textile.profile.setUsername API and we’re done. We also ‘manually’ update the profile object to cause the UI to update. The only funny thing here is, because we’re using an async action, we need to run this inside a runInAction call, otherwise, mobx is unable to track our observable update. Ok, easy part done.

If we have actually passed a valid avatar multipart form file object, then we have some work to do. So first we list all our threads, and check to see if any of them have a ‘key’ that matches our app’s expected avatar thread. In this case, we’ve used ‘avatarThreadKey’. A key is really just a nice easy way to have some way to identify app-specific threads. If we already have an avatar thread, then we’re good to go. Jump down to line 50, and we’ll just textile.files.addFile the file to our thread using our found avatarThread.id, set our new avatar with textile.profile.setAvatar using the hash from the added file, and update our store. Done and done.

If however, at line 39 we haven’t found an existing avatar thread, we need to create one. In this case, we’ll grab a built-in schema for avatars (you’re welcome for including that), add this schema to the node (line 42), and then add/create a new thread using said schema (lines 43–48). From now on, any app (including our own) that wants to use this schema for avatars can do so. Very handy. Oh, I’ve also added the little toast thing as a fun way to notify your user of the change. I think its classy.

So that’s pretty much it in terms of Textile stuff really. We’ve managed to use about 7 new API endpoints in under 40 lines of verbose code. That’s pretty good. Next, we’re wire up the required component(s) to make a pretty page for viewing and updating this profile information.

Create the component

The component itself is pretty straight-forward. We’re relying on the React Semantic UI library here to build up our profile screen/container. We rely on just five components from that library, plus a few default React components. I also really like the react-moment library for easily formatting dates into nice human-readable strings. Otherwise, we just build it up piece by piece. Here’s the gist of it:

View the raw gist

Pretty standard React component. The only special bits in there are a) we’re using mobx for our state management, so we decorate the component by injecting our global ‘store’ and making it an observer. This let’s it react to observables that we’ve defined in our global state. I’m not going to dwell on the details here, because frankly, you probably already have your preferred state management library (Redux perhaps?) in mind, and I’m not here to tell you how to live your life. But, I am here to tell you those two handler methods (handleUsername and handleAvatar) simply setup the required data to send to our store’s updateProfile action. In the case of the avatar, we’re actually expecting a multipart form data object, so that’s what we’ll send. The only other funny thing here is we use a ‘hidden’ input item so that we can trigger it with our Avatar image, rather than one of those ugly file input elements.

Update the app

Now all we need to to is import our component from Profile.js in our Main.js screen and we’re off to the races:

...
import Profile from './Profile'
@inject('store') @observer
class Main extends Component {
render() {
return <Profile />
}
}
...

So let’s give this puppy a go!

Our ‘micro’ Textile app in action. Easy profile updates in the browser.

Awesome, it works (hopefully yours does as well)! The really cool thing about all of this, is that you are really changing your desktop peer’s avatar and username. You can test this out by accessing it from the command line. You just have to remember to add the --api flag to make sure you’re accessing the right node. For example, you can grab your profile data with this:

textile profile get --api=http://127.0.0.1:40602

Does it match? Sure does! Is that pretty cool? Sure is!

What’s next?

Well that was fun, wasn’t it? And pretty easy given all the moving pieces we were able to deal with. But what about if you wanted to develop a desktop app via Electron? We’ve got you covered! You prefer TypeScript? Sure you do, and we’ve also got you covered! Plus, the Textile team is using these APIs and tools in production apps, so if you’re playing around with the libraries now, you’re playing around with them as we build them. Want us to implement a new feature or API? Let’s chat! Need some guidance on how to use Textile in your own app? Let’s do a demo or tutorial together! Give us a shout, we’re happy to engage, and build the best tools to help us all build awesome decentralized apps.

So be sure to tune in for our next episode of the Textile Desktop Series. We’ll cover bundling Textile APIs into an Electron app, and even start to add things like chat and photo sharing. Its going to be a learning experience for us as well, so be prepared to break and build things along the way. In the mean time, feel free to reach out on Slack, or share your thoughts on Twitter. If you’re a fellow decentralized web developer, let us know what cool distributed web projects you’re working on —maybe Textile can help out? Also check out Textile Photos, and join our mailing list to get updates about new features and progress.