This commit is contained in:
Pavel Murygin 2021-09-06 03:55:28 +03:00
parent 968ea1ff85
commit 3e5f5958e8
13 changed files with 516 additions and 52 deletions

View File

@ -1,33 +1,33 @@
# Table of contents
* [Introduction](README.md)
* [Thinking In Aquamarine](p2p.md)
* [Concepts](concepts.md)
* [Quick Start](quick-start/README.md)
* [1. Browser-to-Browser](quick-start/1.-browser-to-browser-1.md)
* [2. Hosted Services](quick-start/2.-hosted-services.md)
* [3. Browser-to-Service](quick-start/3.-browser-to-service.md)
* [Aquamarine](knowledge_aquamarine/README.md)
* [Aqua](knowledge_aquamarine/hll.md)
* [Marine](knowledge_aquamarine/marine/README.md)
* [Marine CLI](knowledge_aquamarine/marine/marine-cli.md)
* [Marine REPL](knowledge_aquamarine/marine/marine-repl.md)
* [Marine Rust SDK](knowledge_aquamarine/marine/marine-rs-sdk.md)
* [Tools](knowledge_tools.md)
* [Node](node.md)
* [JS SDK](js-sdk/readme.md)
* [Concepts?](js-sdk/1.md)
* [Using Aqua compiler with SDK?](js-sdk/2.md)
* [Running app in nodejs?](js-sdk/3.md)
* [Running app in browser?](js-sdk/4.md)
* [api reference?](js-sdk/5.md)
* [changelog?](js-sdk/changelog.md)
* [Security](knowledge_security.md)
* [Tutorials](tutorials_tutorials/README.md)
* [Setting Up Your Environment](tutorials_tutorials/recipes_setting_up.md)
* [Deploy A Local Fluence Node](tutorials_tutorials/tutorial_run_local_node.md)
* [cUrl As A Service](tutorials_tutorials/curl-as-a-service.md)
* [Add Your Own Builtins](tutorials_tutorials/add-your-own-builtin.md)
* [Building a Frontend with JS-SDK](tutorials_tutorials/building-a-frontend-with-js-sdk.md)
* [Research, Papers And References](research-papers-and-references.md)
- [Introduction](README.md)
- [Thinking In Aquamarine](p2p.md)
- [Concepts](concepts.md)
- [Quick Start](quick-start/README.md)
- [1. Browser-to-Browser](quick-start/1.-browser-to-browser-1.md)
- [2. Hosted Services](quick-start/2.-hosted-services.md)
- [3. Browser-to-Service](quick-start/3.-browser-to-service.md)
- [Aquamarine](knowledge_aquamarine/README.md)
- [Aqua](knowledge_aquamarine/hll.md)
- [Marine](knowledge_aquamarine/marine/README.md)
- [Marine CLI](knowledge_aquamarine/marine/marine-cli.md)
- [Marine REPL](knowledge_aquamarine/marine/marine-repl.md)
- [Marine Rust SDK](knowledge_aquamarine/marine/marine-rs-sdk.md)
- [Tools](knowledge_tools.md)
- [Node](node.md)
- [JS SDK](js-sdk/readme.md)
- [Concepts](js-sdk/1_concepts.md)
- [Basics](js-sdk/2_basics.md)
- [In-depth](js-sdk/3_basics.md)
- [Running app in nodejs](js-sdk/4_run_in_node.md)
- [Running app in browser](js-sdk/5_run_in_browser.md)
- [Api reference](js-sdk/6_reference.md)
- [Changelog](js-sdk/changelog.md)
- [Security](knowledge_security.md)
- [Tutorials](tutorials_tutorials/README.md)
- [Setting Up Your Environment](tutorials_tutorials/recipes_setting_up.md)
- [Deploy A Local Fluence Node](tutorials_tutorials/tutorial_run_local_node.md)
- [cUrl As A Service](tutorials_tutorials/curl-as-a-service.md)
- [Add Your Own Builtins](tutorials_tutorials/add-your-own-builtin.md)
- [Building a Frontend with JS-SDK](tutorials_tutorials/building-a-frontend-with-js-sdk.md)
- [Research, Papers And References](research-papers-and-references.md)

View File

@ -1,8 +0,0 @@
Table of contents
1. Description of the concept of Peer
2. Differences between js imlpementation and rust implementation
3. The lack of kademlia
4. The concept of relays
5. The connection between aqua ts compilation and JS SDK
6. High-level architecture (avm, particle queue etc)

37
js-sdk/1_concepts.md Normal file
View File

@ -0,0 +1,37 @@
# Basic concepts
The main export of the `@fluencelabs/fluence` package is the `FluencePeer` class. This class implements the Fluence protocol for javascript-based environments. It provides all the necessary features to communicate with Fluence network namely:
1. Connectivity with one or many Fluence Node which allows sending particles to and receiving from other Peers
2. The Peer Id identifying the node in the network
3. Aqua VM which allows the execution of air scripts inside particles
4. A set of builtin functions required by Fluence protocol
5. Support for the typescript code which is generated by Aqua compiler
Even though the js-based implementation closely resembles [node](node.md) there are some considerable differences to the latter.
`FluencePeer` does not host services composed of wasm modules. Instead it allows to register service call handlers directly in javascript. The Aqua language compiler creates a typed helpers for that task. Using Aqua compiler is strontly advised when working with JS SDK.
Due to the limitations of browser-based environment `FluencePeer` cannot be discovered by it's Peer Id on it's own. To overcome this `FluencePeer` must use an existing node which will act as a `relay`. When a peer is connected through a relay it is considered to be `client`. The `FluencePeer` routes all it's particle through it's relay thus taking advantage of the peer discovery implemented on the node. A particle sent to the connected client must be routed through it's relay.
The js-based peer does not implement the full set of builtin functions due the limitations described previously. E.g there is no builtins implementation for _kad_ or _srv_ services. However _op_ service is fully implemented. For the full descriptions of implemented builtins refer to [api reference?](js-sdk/5_reference.md)
In contrast with the node implementation `FluencePeer` can initiate new particles execution. Aqua compiler generates executable functions from `func` definitions in aqua code.
# Creating applications with Aqua language
The official way to write applications for Fluence is using Aqua programming language. Aqua compiler emits TypeScript or JavaScript which in turn can be called from a js-based environemt. The compiler outputs code for the following entities:
1. Exported `func` declarations are turned into callable async functiokns
2. Exported `service` declarations are turned into functions which register callback handler in a typed manner
To learn more about Aqua see [aqua book](https://doc.fluence.dev/aqua-book/)
The building block of the application are:
- Aqua code for peer-to-peer communication
- Compiler cli package for aqua to (java)typescript compilation
- Initialization of the `FluencePeer`
- Application specific code (java)typescript in the framework of your choice
In the next section we see it in action

View File

@ -1,7 +0,0 @@
Table of contents
1. Basics of JS SDK: FluencePeer class, establishing connection
1. What is generated for functions
2. What is generated for services
3. Instance and global api, how the compiled code extends FluencePeer class
4. Glueing all the parts together

143
js-sdk/2_basics.md Normal file
View File

@ -0,0 +1,143 @@
# Intro
In this section we will show you how JS SDK can be used to create a hello world application with Fluence stack.
# Aqua code
Let's start with the aqua code first:
```
service HelloWorld("hello-world"):
hello(str: string)
func sayHello():
HelloWorld.hello("Hello, world!")
```
This file has two definitions. The first one is a service named `HelloWorld`. A Service interfaces functions executable on a peer. We will register a handler for this interface in our typescript application. The second definition is the function `sayHello`. The only thing the function is doing is calling the `hello` method of `HelloWorld` service located on the current peer. We will shouw you how to call this function from the typescript application.
# Installing dependencies
Initialze an empty npm package:
```bash
npm init
```
We will need these two packages for the application runtime
```bash
npm install @fluencelabs/fluence @fluencelabs/fluence-network-environment
```
The first one is the SDK itself and the second is a maintained list of Fluence networks and nodes to connect to.
Aqua compiler cli has to be installed, but is not needed at runtime.
**Warning: the package requires java to be installed \(it will call "java -jar ... "\)**
```bash
npm install --save-dev @fluencelabs/aqua-cli
```
Also we might want to have aqua source files automatically recompiled on every save. We will take advantage of chokidar for that:
```bash
npm install --save-dev @fluencelabs/chokidar-cli
```
And last, but no least we will need TypeScript
```
npm install --save-dev typescript
npx tsc --init
```
# Setting up aqua compiler
Let's put aqua described earlier into `aqua\hello-world.aqua` file. You probably want to keep the generated TypeScript in the same directory with other typescript files, usually `src`. Let's create the `src\_aqua` directory for that.
The overall project structure looks like this:
```text
┣ aqua
┃ ┗ hello-world.aqua
┣ src
┃ ┣ _aqua
┃ ┃ ┗ hello-world.ts
┃ ┗ index.ts
┣ package-lock.json
┣ package.json
┗ tsconfig.json
```
The Aqua compiler can be run with `npm`:
```bash
npx aqua-cli -i ./aqua/ -o ./src/_aqua
```
We recommend to store this logic inside a script in `packages.json` file:
```json
{
...
"scripts": {
...
"compile-aqua": "aqua-cli -i ./aqua/ -o ./src/_aqua", // (1)
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\"" // (2)
},
...
}
```
`compile-aqua` (1) runs the compilation once, producing `src\_aqua\hello-world.ts` in our case
`watch-aqua` (2) starts watching for any changes in .aqua files recompiling them on the fly
# Using the compiled code in our application
Using the code generated by the compiler is as easy as calling a function. The compiler generates all the boilerplate needed to send a particle into the network and wraps it into a single call. It also generate a function for service callback registration. Note that all the type information and therefore type checking and code completion facilities are there!
Let's see how use generated code in our application. `index.ts`:
```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import { registerHelloWorld, sayHello } from "./_aqua/hello-world"; // (1)
async function main() {
await FluencePeer.default.init(); // (2)
registerHelloWorld({
// (3)
hello: async (str) => {
console.log(str);
},
});
await sayHello(); // (4)
await FluencePeer.default.uninit(); // (5)
}
main();
```
(1) Aqua compiler provides functions which can be directly imported like any normal typescript function.
(2) `FluencePeer` has to be initialized before running any application in Fluence Network. A peer represents the identity in the network, so most of the time you will only need a single peer per application. JS SDK provides a default instance which is accesible via `default` propery of the class. `init` method accepts a parameters object which will be covered in the next section. By default the peer is not get connected to the network and will only be able to execute air on the local machine only. Please keep in mind that the init function is asyncrhounous
For every exported `service XXX` definition in aqua code, the compiler provides a `registerXXX` counterpart. These funtions provide a type-safe way of registering callback handlers for the services. The callbacks are executed when the appropriate service is called in aqua on the current peer. The handlers take form of the object where keys are the name of functions and the values are async functions used as the corresponding callbacks. For example in (3) we are registering handler for `hello` function which outputs it's parameter to the console
For every exported `func XXX` definition in aqua code, the compiler provides an async function which can be directly called from typescripyt. In (4) we are calling the `sayHello` function with no arguments. Note that every function is asyncrhonous.
(5) You should call `uninit` method of `FluencePeer` when it is no longer needed. As a rule of thumb all the peers should be uninitilized before destroying the application.
Let's try running the example:
```bash
node -r ts-node/register src/index.ts
```
If everything has been done correctly yuo should see `Hello, world!` in the console.
The next secion will cover in-depth and advanced usage JS SDK

View File

@ -1 +0,0 @@
Tutorial explaining how to write a simple app for node-js

157
js-sdk/3_in_depth.md Normal file
View File

@ -0,0 +1,157 @@
# Intro
In this section we will cover the JS SDK in-depth.
# FluencePeer class
The overall workflow with the `FluencePeer` is the following:
1. Create an instance of the peer
2. Initializing the peer
3. Using the peer in the application
4. Uninitializing the peer
To create a new peer simple instantiate the `FluencePeer` class:
```typescript
const peer = new FluencePeer();
```
The constructor simply creates a new object and does not initialize any workflow. The `init` function starts the Aqua VM, initialized the default call service handlers and (optionally) connect to the Fluence network. The function takes an optional object specifying additonal peer configuration. On option you will be using a lot is `connectTo`. It tells the peer to connect to a relay. For example:
```typescript
await peer.init({
connectTo: krasnodar[0],
});
```
connects the first node of the Kranodar network. You can find the officially maintained list networks in the `@fluencelabs/fluence-network-environment` package. The full list of supported options is described in the [API reference](js-sdk/6_reference.md)
The reverse to
Most of the time a single peer is enough for the whole application. For these use cases`FluncePeer` class contains the default instance which can be accessed with the corresponding property:
```typescript
await FluencePeer.default.init();
```
The peer by itself does not do any useful work. You should take advantage of functions generated by the Aqua compiler. You can use them both with a single peer or in muliple peers scenario. If you are using the default peer for your application you don't need to explicitly pass it: the compiled functions will use the `default` instance in that case (see "Using multiple peers in one applicaton")
To uninitialize the peer simply call `uninit` method. It will disconnect from the network and stop the Aqua vm,
```typescript
await peer.unint();
```
# Using multiple peers in one applicaton
In most cases using a single peer is enough. However sometimes you might need to run multiple peers inside the same JS environment. When using a single peer you should initialize the `FluencePeer.default` and call Aqua compiler-generated functions without passing any peer. For example:
```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import {
registerSomeService,
someCallableFunction,
} from "./_aqua/someFunction";
async function main() {
await FluencePeer.default.init({
connectTo: relay,
});
// ... more application logic
registerSomeService({
handler: async (str) => {
console.log(str);
},
});
await someCallableFunction(arg1, arg2, arg3);
await FluencePeer.default.uninit();
}
// ... more application logic
```
If your application needs several peers, you should create a separate `FluncePeer` instance for each of them. The generated functions accept the peer as the first argument. For example:
```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import {
registerSomeService,
someCallableFunction,
} from "./_aqua/someFunction";
async function main() {
const peer1 = new FluencePeer();
const peer2 = new FluencePeer();
// Don't forget to initialize peers
await peer1.init({
connectTo: relay,
});
await peer2.init({
connectTo: relay,
});
// ... more application logic
// Pass the peer as the first agument
// ||
// \/
registerSomeService(peer1, {
handler: async (str) => {
console.log("Called service on peer 1: " str);
},
});
// Pass the peer as the first agument
// ||
// \/
registerSomeService(peer2, {
handler: async (str) => {
console.log("Called service on peer 2: " str);
},
});
// Pass the peer as the first agument
// ||
// \/
await someCallableFunction(peer1, arg1, arg2, arg3);
await peer1.uninit();
await peer2.uninit();
}
// ... more application logic
```
It is possible to combine usage of the default peer with another one. Pay close attention to which peer you are calling the functions against.
```typescript
// Registering handler for the default peer
registerSomeService({
handler: async (str) => {
console.log("Called agains the default peer: " str);
},
});
// Pay close attention to this
// ||
// \/
registerSomeService(someOthePeer, {
handler: async (str) => {
console.log("Called against the peer named someOtherPeer: " str);
},
});
```
# Understanding the Aqua compiler output
Aqua compiler emits TypeScript or JavaScript which in turn can be called from a js-based environemt. The compiler outputs code for the following entities:
1. Exported `func` declarations are turned into callable async functiokns
2. Exported `service` declarations are turned into functions which register callback handler in a typed manner

View File

@ -1 +0,0 @@
Tutorial explaining how to write a simple app for web (based on CRA)

View File

@ -0,0 +1 @@
You can use the JS SDK with any framework (or even without it). Just follow the steps from the previous sections. FluentPad is an example application written in React: https://github.com/fluencelabs/fluent-pad

View File

@ -1,3 +0,0 @@
Table of content
1. Auto-generated docs from jsdoc comments created with typedoc

143
js-sdk/5_run_in_node.md Normal file
View File

@ -0,0 +1,143 @@
# Intro
In this section we will show you how JS SDK can be used to create a hello world application with Fluence stack.
## Aqua code
Let's start with the aqua code first:
```
service HelloWorld("hello-world"):
hello(str: string)
func sayHello():
HelloWorld.hello("Hello, world!")
```
This file has two definitions. The first one is a service named `HelloWorld`. A Service interfaces functions executable on a peer. We will register a handler for this interface in our typescript application. The second definition is the function `sayHello`. The only thing the function is doing is calling the `hello` method of `HelloWorld` service located on the current peer. We will shouw you how to call this function from the typescript application.
## Installing dependencies
Initialze an empty npm package:
```bash
npm init
```
We will need these two packages for the application runtime
```bash
npm install @fluencelabs/fluence @fluencelabs/fluence-network-environment
```
The first one is the SDK itself and the second is a maintained list of Fluence networks and nodes to connect to.
Aqua compiler cli has to be installed, but is not needed at runtime.
**Warning: the package requires java to be installed \(it will call "java -jar ... "\)**
```bash
npm install --save-dev @fluencelabs/aqua-cli
```
Also we might want to have aqua source files automatically recompiled on every save. We will take advantage of chokidar for that:
```bash
npm install --save-dev @fluencelabs/chokidar-cli
```
And last, but no least we will need TypeScript
```
npm install --save-dev typescript
npx tsc --init
```
## Setting up aqua compiler
Let's put aqua described earlier into `aqua\hello-world.aqua` file. You probably want to keep the generated TypeScript in the same directory with other typescript files, usually `src`. Let's create the `src\_aqua` directory for that.
The overall project structure looks like this:
```text
┣ aqua
┃ ┗ hello-world.aqua
┣ src
┃ ┣ _aqua
┃ ┃ ┗ hello-world.ts
┃ ┗ index.ts
┣ package-lock.json
┣ package.json
┗ tsconfig.json
```
The Aqua compiler can be run with `npm`:
```bash
npx aqua-cli -i ./aqua/ -o ./src/_aqua
```
We recommend to store this logic inside a script in `packages.json` file:
```json
{
...
"scripts": {
...
"compile-aqua": "aqua-cli -i ./aqua/ -o ./src/_aqua", // (1)
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\"" // (2)
},
...
}
```
`compile-aqua` (1) runs the compilation once, producing `src\_aqua\hello-world.ts` in our case
`watch-aqua` (2) starts watching for any changes in .aqua files recompiling them on the fly
## Using the compiled code in our application
Using the code generated by the compiler is as easy as calling a function. The compiler generates all the boilerplate needed to send a particle into the network and wraps it into a single call. It also generate a function for service callback registration. Note that all the type information and therefore type checking and code completion facilities are there!
Let's see how use generated code in our application. `index.ts`:
```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import { registerHelloWorld, sayHello } from "./_aqua/hello-world"; // (1)
async function main() {
await FluencePeer.default.init(); // (2)
registerHelloWorld({
// (3)
hello: async (str) => {
console.log(str);
},
});
await sayHello(); // (4)
await FluencePeer.default.uninit(); // (5)
}
main();
```
(1) Aqua compiler provides functions which can be directly imported like any normal typescript function.
(2) `FluencePeer` has to be initialized before running any application in Fluence Network. A peer represents the identity in the network, so most of the time you will only need a single peer per application. JS SDK provides a default instance which is accesible via `default` propery of the class. `init` method accepts a parameters object which will be covered in the next section. By default the peer is not get connected to the network and will only be able to execute air on the local machine only. Please keep in mind that the init function is asyncrhounous
For every exported `service XXX` definition in aqua code, the compiler provides a `registerXXX` counterpart. These funtions provide a type-safe way of registering callback handlers for the services. The callbacks are executed when the appropriate service is called in aqua on the current peer. The handlers take form of the object where keys are the name of functions and the values are async functions used as the corresponding callbacks. For example in (3) we are registering handler for `hello` function which outputs it's parameter to the console
For every exported `func XXX` definition in aqua code, the compiler provides an async function which can be directly called from typescripyt. In (4) we are calling the `sayHello` function with no arguments. Note that every function is asyncrhonous.
(5) You should call `uninit` method of `FluencePeer` when it is no longer needed. As a rule of thumb all the peers should be uninitilized before destroying the application.
Let's try running the example:
```bash
node -r ts-node/register src/index.ts
```
If everything has been done correctly yuo should see `Hello, world!` in the console.
The next secion will cover in-depth and advanced usage JS SDK

1
js-sdk/6_reference.md Normal file
View File

@ -0,0 +1 @@
Auto-generated docs from jsdoc comments created with typedoc

View File

@ -1 +1,3 @@
Some preface for the section
JS SDK provides the implementation of the Fluence Protocol which can be hosted in js-based environment. Currently node.js 14+ and majority of the modern browsers are tested.
The JS SDK is just a library wich can be used with any framework of your choice (or even without frameworks).