Fluence: Building a front-end for a p2p app
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Murygin, Pavel
Fluence is an open application platform where apps can build on each other, share data and users. Fluence not only allows hosting services inside p2p network but also provides JS SDK for building web applications, which communicate with the services. After the introductory talk, we will dive right into something very practical. We will demonstrate the process of making a web application with Fluence JS SDK. We will start with an empty create-react-app project and work our way towards the fully functional solution. By the end of this talk, we will develop a text editor, which synchronizes it’s state and the user online status with collaborators over Fluence p2p network. The application will be interacting with two minimalistic services pre-deployed to Fluence: user-list and history, but all of the features will be implemented on client-side without any need to modify existing software. Expect a lot frontend and a lot of code in TypeScript!
 Hi everyone, my name is Pavel. I'm a frontend developer at Fluence Labs. And in this talk, I will be showing you how you can build frontend applications for Fluence Network. So my talk would be primarily focused on showing you some code in TypeScript and React. So let me just go through the slides real quick and get to the code as soon as quickly as possible. So in case you missed the introductory talk, what Fluence is, it is an open application platform. It is based upon peer-to-peer network with distributed compute protocol. It also has Okamarin language, which is used to compose applications together. And it will come with a blockchain economic layer a bit later. So speaking of application compositions, this is a wonderful feature of Fluence. Basically applications can build upon one another. They can share data, they can share users. And it is a really wonderful thing. You should definitely check out the introductory talk in case you missed it. So I will be mostly speaking about the frontend applications, which are running browsers. So from a frontend developer perspective, Fluence is a little bit different from usual development. The main difference is that with Fluence, we have the whole peer-to-peer network exposed to us. Usually when we develop web applications, we use HTTP requests and sometimes web sockets. And I'd say 99% of the time we have a single host, which serves all our requests. But with Fluence, we are free to call many different services, get data from them and compose the data. And we're using Okamarin and Particles for that. That would be the biggest difference. And I really would like to show you this in code. Welcome to the code demo. Unfortunately, I'm very short on time, so I won't be able to do live coding. Instead, I will be working you through a series of Git commits showcasing you how you can build a web application for Fluence network. It will be a step-by-step presentation starting from an empty Creator Act app all the way up to the fully working collaborative text editor. So I've already removed everything from the root component of the React app, and I've added some styles. I will be using during my presentation, so just to spare some time writing all of them by hand. So we will be using some NPM packages. First of all, we will need Fluence.js SDK. Well, obviously, since we are working with Fluence network. Another Fluence-related one is this network environment. Basically this is the place where we are keeping an up-to-date list of known Fluence networks and nodes in them. We will need this information to connect to one of the nodes. Auto Merge is a very nice CRDT-based library for various JSON format document synchronizations. We will be using it for text synchronization, but it can actually work with various JSON documents. This one will be used for gluing some plain text to auto merge document format. Okay, so let's start with our initial app structure. We have a header with two header items, and we also have a content area. We are not using any fancy routing framework, just a couple of statements. So when a user is not logged in, we are displaying just a simple welcome form, and when a user is logged in, we are showing the actual application. The actual application consists of a user list and the text editor itself. The user list is pretty simple at that point in time. So we are only showing our own name here, and text editor is very basic as well. So we are only using a single text area, and we are just wiring an on-change update handler. So here is what it looks like. Let's say I'm a kitten. I can get into the room, write some text, and that's it. Nothing happens. So we should definitely work towards a more interesting application. So we will start by utilizing Fluence. The way you do is by using Fluence package, and you should start with the creation of Fluence client. Here, we are storing it in the use state hook, but you are free to store it wherever you like. For example, you can store client in a global variable, or if you are using a dependency injection framework, you can store it there. We will be just initializing the client when the application renders. So we are creating it with createClient function. And the argument here is a name or, I'd say, the multi-address of the any known node. This is where our environment package comes in handy. For example, in our application, we are connecting to the dev network and to the first node of the state work to be precise. So let's do something useful with the client. You can check the connection state using this isConnected property. And let's just show the connection status inside the header. So if we refresh a page, we see that we're getting connected just as the application renders. Okay, let's make our first call to the Fluence network. So I've created the file API, where we will be storing all, let's say, API calls to our application. And I've wired up a couple of API calls to button handlers. Yeah, and I should really have to mention that this way of using login form is oversimplified. In real world, you will be dealing with private keys and wallets and stuff like that. So I don't want to do all of that during the presentation. So let's just stick to a simple form where everyone is welcome. You can just say your name and you can get logged in. So we will have to call a user list service telling it that we are getting logged in. So the way you work with network calls in Fluence is by utilizing things called particles. You create it. You have a particle class and you create particle with this class. And you can later send it with one of the send particle functions. So I really have to raise a couple of very important points here. First of all, don't really bother too much with all this scary text. I'm just focusing primarily on the front end side here. And I will be explaining you in simple words what is being done here. Second, this is actually meant to be a compilation target rather than an end user language. So there would be a lot of improvements in this area. And I don't want to get too much into the details here just because we will be having two more talks where all these details would be explained. So I will just give you an analogy of what particle is. Basically with HTTP calls you're on the query single server and the URL and all these parameters in the HTTP call describe what do you want from server and the server responds with the data. But with Fluence you can query any node from your web client. So you might think of it as an exposed facade, for example, where you can query any microservice just from a single web application. So that's why you might think of this script as an alternative to URL. So what we're doing here is we are describing what we're actually doing with the network. And to be precise, we're just calling a user list service, which is located on user list node. And you should definitely pass these things as parameters. Think of it as a prepared statement. So getting back to analogy with HTTP, you might think of a particle as an HTTP on steroids just because you can query multiple servers and get multiple results. And it is actually very powerful. So knowing all that, we've created a particle and we're sending it using send particle as fetch. What it means is we are waiting for a particle to get back with the data and dysfunctional return a promise, which will be resolved with receive data, hence the name send as fetch. Here we are just checking the return result and the leave call is pretty similar to the join. Instead, we're just calling leave instead of join. So we are taking advantage of the fact that there are promises, so we are waiting on them and we will proceed only when the promise is resolved. So let's just try to connect. Let's say I'm a kitten and I can get inside the room and I can get out of the room. Nice, but we are not still working with the text, so let's fix that. Okay. I will be using this class. We only have to bother about several functions. So what this class does is it helps us to synchronize between our plain text and the auto merge state. So we should call this receive function or receive changes function when some changes from another peer comes to us. Handle doc update is a function which will be called by auto merge when it decides there are some changes to the state of the document and handle send changes will be called by auto merge as well when it decides to share some of the changes with outside world. So here's how we wire this function up. Again when the component renders, we are wiring up handle doc update and we are basically setting the text. We will do the changes broadcast later. We are starting the client and the last thing we are doing here is querying the history. We are using the history service to store all the changes made to the text area. Let's see this call. This is a particle as well, but it is a little bit more interesting mainly because we are using two different services here. First we are calling user list the same way we did in the previous particle. And we are asking for the authentication token. And then we are getting to the history service with this token. Otherwise it would say that we aren't unauthorized. So again we are sending particle as fetch just because we want data back and we would like to wait until the date is received. And once the date is received we are just updating our changes with the auto merge. Okay, let's try that. Cool. Let's say hello from Kitten, but it won't work just because we are not propagating our changes back. So let's fix this issue. So here we actually start to update our, to propagate our changes to other peers and we will do this with add entry API. I also wired up some updates. So when the text get updated I am updating this state with auto merge and I am doing it with this little function here and we are debouncing it just so in case someone writes too fast. So let's see the most interesting part here is the API call. And again this is not a particle, but it is different from the call. The usage of this particle is different from the others. So here we, again we are getting the token and we are adding our history log entry to the service. But we actually don't want to wait here and we don't need any data back, so we are just using playing send particle. This function will return a promise which would be resolved just when this particle got into the network. So it resolves almost immediately. So let's see how it works. We're still at Kitten. And we are trying to say hello to other animals. And we actually see that the text gets updated, but the updates don't happen immediately. So we should definitely fix that as well. So the way we do it is by changing the add entry API call. As you can see some more Airstrips, Airstript part has been added here. So what is happening here is we are querying user list twice. First we are getting the token, the same way we did in the previous example. And now we are also getting all users from the user list. And later we are actually iterating through the user list. And we are notifying every other user in this list that we have some changes to be applied. So this line here is actually a call to a service which should be implemented on the web client. So Influence web clients can also respond to service calls. And you might think of it as incoming notifications from the network. So something like WebSockets. But Fluence is a little bit more powerful than that. For example, we have an out-of-the-box ready-to-use request response pattern. So in order all this to work, we have to implement this callback. So with this particle we are querying where sending notifications to other peers. And now we have to respond to these notifications. So the way we do this is by using a function subscribe to event. This is a function you should use when you don't want to respond with anything. It would be just a subscription to all calls with the same service ID and function name. So please note that we are using the same variables here and here. So we are creating these services just for that. And we are receiving the same arguments. So we are passing the initiating peer who is doing the notification changes themselves and the token. And we are destructuring these arguments. And the actual workload is pretty basic here. We're just synchronizing changes with the auto merge. Let's try this. First let's leave. And it works. Cool. We have updates both here and from the, let's say, first browser. Nice. So you might be wondering what are tetraplets and why this is authorized is just simple Boolean. The short answer is you can actually with tetraplets, you can validate this that this is authorized has come from the right service and it hasn't been forged and it is verified by math. So I won't be doing this in my talk simply because it would be described in much more details in the later one. So be sure to check this our future talks. Okay, so the last piece missing here is the actual user list. I'm running out of time. So let me just quickly walk you through the code here. So let's first look how it works. So we have online status synchronization. We can leave and we see the user list update. We can open. So we can open another one. So third one, for example, and we get everything updated. And if you just close the browser, the user is getting offline after a couple of seconds. So let me just walk you through this code. We're using a similar subscribe to events. We are storing user list in a single map and we are refreshing. So the user has this should become online flag and we are updating this flag on timer. And the interesting part here is three subscriptions here. First one is the subscription to user edit event. The second one is a subscription to user removed event. And third one to notification that a user is online. So I would really like to show you how it works in Fluence calls. So first of all, I've added some calls here in the leave particle. So we are not just leaving the room. So we are not just calling leave from user list, but we are also getting all the users after that and notifying all of them. And the most interesting one is how online status is getting updated. So here we are getting all the users from the user list. And we are iterating this list. And we are basically sending a pin to another peer and getting back with the notification. So basically this works in the way that if a peer does not respond, we are not getting this notification and the user will become offline in the interface. And the way it works in callbacks, I need user list. We are just setting the online status. But I would point out that the most interesting thing here is that we have created the online status notification without any changes to either user list service or the history. So we've actually built another application on top of what we've got here and without needing to do any changes to the existing ones. And this is a really powerful feature of Fluence. So here is it. Here is how you can make a collaborative text editor with Fluence network. So here it is. Don't be afraid if you've missed something or you didn't understand some of the concepts or I believe that was quite a lot of code for a 20-minute presentation. So anyways, feel free to check our GitHub page. We have everything open sourced. The code for this demo will be available here in Fluence pod repository. Also check out our Fluence.js SDK and of course check out the documentation there. We also have a dedicated documentation page. So don't hesitate to visit it and check out the docs yourselves. And of course we have a very friendly community on Telegram. So feel free to come there and ask any questions in case you have any. So as far as I understand, we will be moving to some other place here where I will be happy to answer to all your questions.
 Hi everyone, my name is Pavel.  I'm a frontend developer at Fluence Labs.  And in this talk, I will be showing you how you can build frontend applications for Fluence  Network.  So my talk would be primarily focused on showing you some code in TypeScript and React.  So let me just go through the slides real quick and get to the code as soon as quickly  as possible.  So in case you missed the introductory talk, what Fluence is, it is an open application  platform.  It is based upon peer-to-peer network with distributed compute protocol.  It also has Okamarin language, which is used to compose applications together.  And it will come with a blockchain economic layer a bit later.  So speaking of application compositions, this is a wonderful feature of Fluence.  Basically applications can build upon one another.  They can share data, they can share users.  And it is a really wonderful thing.  You should definitely check out the introductory talk in case you missed it.  So I will be mostly speaking about the frontend applications, which are running browsers.  So from a frontend developer perspective, Fluence is a little bit different from usual  development.  The main difference is that with Fluence, we have the whole peer-to-peer network exposed  to us.  Usually when we develop web applications, we use HTTP requests and sometimes web sockets.  And I'd say 99% of the time we have a single host, which serves all our requests.  But with Fluence, we are free to call many different services, get data from them and  compose the data.  And we're using Okamarin and Particles for that.  That would be the biggest difference.  And I really would like to show you this in code.  Welcome to the code demo.  Unfortunately, I'm very short on time, so I won't be able to do live coding.  Instead, I will be working you through a series of Git commits showcasing you how you can  build a web application for Fluence network.  It will be a step-by-step presentation starting from an empty Creator Act app all the way  up to the fully working collaborative text editor.  So I've already removed everything from the root component of the React app, and I've  added some styles.  I will be using during my presentation, so just to spare some time writing all of them  by hand.  So we will be using some NPM packages.  First of all, we will need Fluence.js SDK.  Well, obviously, since we are working with Fluence network.  Another Fluence-related one is this network environment.  Basically this is the place where we are keeping an up-to-date list of known Fluence networks  and nodes in them.  We will need this information to connect to one of the nodes.  Auto Merge is a very nice CRDT-based library for various JSON format document synchronizations.  We will be using it for text synchronization, but it can actually work with various JSON  documents.  This one will be used for gluing some plain text to auto merge document format.  Okay, so let's start with our initial app structure.  We have a header with two header items, and we also have a content area.  We are not using any fancy routing framework, just a couple of statements.  So when a user is not logged in, we are displaying just a simple welcome form, and when a user  is logged in, we are showing the actual application.  The actual application consists of a user list and the text editor itself.  The user list is pretty simple at that point in time.  So we are only showing our own name here, and text editor is very basic as well.  So we are only using a single text area, and we are just wiring an on-change update handler.  So here is what it looks like.  Let's say I'm a kitten.  I can get into the room, write some text, and that's it.  Nothing happens.  So we should definitely work towards a more interesting application.  So we will start by utilizing Fluence.  The way you do is by using Fluence package, and you should start with the creation of  Fluence client.  Here, we are storing it in the use state hook, but you are free to store it wherever you  like.  For example, you can store client in a global variable, or if you are using a dependency  injection framework, you can store it there.  We will be just initializing the client when the application renders.  So we are creating it with createClient function.  And the argument here is a name or, I'd say, the multi-address of the any known node.  This is where our environment package comes in handy.  For example, in our application, we are connecting to the dev network and to the first node of  the state work to be precise.  So let's do something useful with the client.  You can check the connection state using this isConnected property.  And let's just show the connection status inside the header.  So if we refresh a page, we see that we're getting connected just as the application  renders.  Okay, let's make our first call to the Fluence network.  So I've created the file API, where we will be storing all, let's say, API calls to our  application.  And I've wired up a couple of API calls to button handlers.  Yeah, and I should really have to mention that this way of using login form is oversimplified.  In real world, you will be dealing with private keys and wallets and stuff like that.  So I don't want to do all of that during the presentation.  So let's just stick to a simple form where everyone is welcome.  You can just say your name and you can get logged in.  So we will have to call a user list service telling it that we are getting logged in.  So the way you work with network calls in Fluence is by utilizing things called particles.  You create it.  You have a particle class and you create particle with this class.  And you can later send it with one of the send particle functions.  So I really have to raise a couple of very important points here.  First of all, don't really bother too much with all this scary text.  I'm just focusing primarily on the front end side here.  And I will be explaining you in simple words what is being done here.  Second, this is actually meant to be a compilation target rather than an end user language.  So there would be a lot of improvements in this area.  And I don't want to get too much into the details here just because we will be having  two more talks where all these details would be explained.  So I will just give you an analogy of what particle is.  Basically with HTTP calls you're on the query single server and the URL and all these parameters  in the HTTP call describe what do you want from server and the server responds with the  data.  But with Fluence you can query any node from your web client.  So you might think of it as an exposed facade, for example, where you can query any microservice  just from a single web application.  So that's why you might think of this script as an alternative to URL.  So what we're doing here is we are describing what we're actually doing with the network.  And to be precise, we're just calling a user list service, which is located on user list  node.  And you should definitely pass these things as parameters.  Think of it as a prepared statement.  So getting back to analogy with HTTP, you might think of a particle as an HTTP on steroids  just because you can query multiple servers and get multiple results.  And it is actually very powerful.  So knowing all that, we've created a particle and we're sending it using send particle as  fetch.  What it means is we are waiting for a particle to get back with the data and dysfunctional  return a promise, which will be resolved with receive data, hence the name send as fetch.  Here we are just checking the return result and the leave call is pretty similar to the  join.  Instead, we're just calling leave instead of join.  So we are taking advantage of the fact that there are promises, so we are waiting on them  and we will proceed only when the promise is resolved.  So let's just try to connect.  Let's say I'm a kitten and I can get inside the room and I can get out of the room.  Nice, but we are not still working with the text, so let's fix that.  Okay.  I will be using this class.  We only have to bother about several functions.  So what this class does is it helps us to synchronize between our plain text and the  auto merge state.  So we should call this receive function or receive changes function when some changes  from another peer comes to us.  Handle doc update is a function which will be called by auto merge when it decides there  are some changes to the state of the document and handle send changes will be called by  auto merge as well when it decides to share some of the changes with outside world.  So here's how we wire this function up.  Again when the component renders, we are wiring up handle doc update and we are basically  setting the text.  We will do the changes broadcast later.  We are starting the client and the last thing we are doing here is querying the history.  We are using the history service to store all the changes made to the text area.  Let's see this call.  This is a particle as well, but it is a little bit more interesting mainly because we are  using two different services here.  First we are calling user list the same way we did in the previous particle.  And we are asking for the authentication token.  And then we are getting to the history service with this token.  Otherwise it would say that we aren't unauthorized.  So again we are sending particle as fetch just because we want data back and we would  like to wait until the date is received.  And once the date is received we are just updating our changes with the auto merge.  Okay, let's try that.  Cool.  Let's say hello from Kitten, but it won't work just because we are not propagating our  changes back.  So let's fix this issue.  So here we actually start to update our, to propagate our changes to other peers and  we will do this with add entry API.  I also wired up some updates.  So when the text get updated I am updating this state with auto merge and I am doing it  with this little function here and we are debouncing it just so in case someone writes  too fast.  So let's see the most interesting part here is the API call.  And again this is not a particle, but it is different from the call.  The usage of this particle is different from the others.  So here we, again we are getting the token and we are adding our history log entry to  the service.  But we actually don't want to wait here and we don't need any data back, so we are just  using playing send particle.  This function will return a promise which would be resolved just when this particle  got into the network.  So it resolves almost immediately.  So let's see how it works.  We're still at Kitten.  And we are trying to say hello to other animals.  And we actually see that the text gets updated, but the updates don't happen immediately.  So we should definitely fix that as well.  So the way we do it is by changing the add entry API call.  As you can see some more Airstrips, Airstript part has been added here.  So what is happening here is we are querying user list twice.  First we are getting the token, the same way we did in the previous example.  And now we are also getting all users from the user list.  And later we are actually iterating through the user list.  And we are notifying every other user in this list that we have some changes to be applied.  So this line here is actually a call to a service which should be implemented on the  web client.  So Influence web clients can also respond to service calls.  And you might think of it as incoming notifications from the network.  So something like WebSockets.  But Fluence is a little bit more powerful than that.  For example, we have an out-of-the-box ready-to-use request response pattern.  So in order all this to work, we have to implement this callback.  So with this particle we are querying where sending notifications to other peers.  And now we have to respond to these notifications.  So the way we do this is by using a function subscribe to event.  This is a function you should use when you don't want to respond with anything.  It would be just a subscription to all calls with the same service ID and function name.  So please note that we are using the same variables here and here.  So we are creating these services just for that.  And we are receiving the same arguments.  So we are passing the initiating peer who is doing the notification changes themselves  and the token.  And we are destructuring these arguments.  And the actual workload is pretty basic here.  We're just synchronizing changes with the auto merge.  Let's try this.  First let's leave.  And it works.  Cool.  We have updates both here and from the, let's say, first browser.  Nice.  So you might be wondering what are tetraplets and why this is authorized is just simple  Boolean.  The short answer is you can actually with tetraplets, you can validate this that this  is authorized has come from the right service and it hasn't been forged and it is verified  by math.  So I won't be doing this in my talk simply because it would be described in much more  details in the later one.  So be sure to check this our future talks.  Okay, so the last piece missing here is the actual user list.  I'm running out of time.  So let me just quickly walk you through the code here.  So let's first look how it works.  So we have online status synchronization.  We can leave and we see the user list update.  We can open.  So we can open another one.  So third one, for example, and we get everything updated.  And if you just close the browser, the user is getting offline after a couple of seconds.  So let me just walk you through this code.  We're using a similar subscribe to events.  We are storing user list in a single map and we are refreshing.  So the user has this should become online flag and we are updating this flag on timer.  And the interesting part here is three subscriptions here.  First one is the subscription to user edit event.  The second one is a subscription to user removed event.  And third one to notification that a user is online.  So I would really like to show you how it works in Fluence calls.  So first of all, I've added some calls here in the leave particle.  So we are not just leaving the room.  So we are not just calling leave from user list, but we are also getting all the users  after that and notifying all of them.  And the most interesting one is how online status is getting updated.  So here we are getting all the users from the user list.  And we are iterating this list.  And we are basically sending a pin to another peer and getting back with the notification.  So basically this works in the way that if a peer does not respond, we are not getting  this notification and the user will become offline in the interface.  And the way it works in callbacks, I need user list.  We are just setting the online status.  But I would point out that the most interesting thing here is that we have created the online  status notification without any changes to either user list service or the history.  So we've actually built another application on top of what we've got here and without  needing to do any changes to the existing ones.  And this is a really powerful feature of Fluence.  So here is it.  Here is how you can make a collaborative text editor with Fluence network.  So here it is.  Don't be afraid if you've missed something or you didn't understand some of the concepts  or I believe that was quite a lot of code for a 20-minute presentation.  So anyways, feel free to check our GitHub page.  We have everything open sourced.  The code for this demo will be available here in Fluence pod repository.  Also check out our Fluence.js SDK and of course check out the documentation there.  We also have a dedicated documentation page.  So don't hesitate to visit it and check out the docs yourselves.  And of course we have a very friendly community on Telegram.  So feel free to come there and ask any questions in case you have any.  So as far as I understand, we will be moving to some other place here where I will be happy  to answer to all your questions.
fluence_frontend_0_1415.png fluence_frontend_1416_1907.png fluence_frontend_1908_3287.png fluence_frontend_3288_3383.png fluence_frontend_3384_8051.png fluence_frontend_8052_11231.png fluence_frontend_11232_17207.png fluence_frontend_17208_18035.png fluence_frontend_18036_18095.png fluence_frontend_18096_18275.png fluence_frontend_18276_20579.png fluence_frontend_20580_22079.png fluence_frontend_22080_22355.png fluence_frontend_22356_24875.png fluence_frontend_24876_27575.png fluence_frontend_27576_29555.png fluence_frontend_29556_31403.png fluence_frontend_31404_36983.png fluence_frontend_36984_37139.png fluence_frontend_37140_37187.png fluence_frontend_37188_37271.png fluence_frontend_37272_38639.png fluence_frontend_38640_38747.png fluence_frontend_38748_38843.png fluence_frontend_38844_39272.png