Skip to content

Commit

Permalink
New article about migration to sails (#159)
Browse files Browse the repository at this point in the history
Co-authored-by: AndrePanin <[email protected]>
  • Loading branch information
MedovTimur and AndrePanin authored Sep 17, 2024
1 parent 4bf9c5d commit b3b7229
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 19 deletions.
154 changes: 154 additions & 0 deletions docs/build/sails/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
sidebar_label: Migration
sidebar_position: 6
---

# Migration of `gstd` programs

[`Sails`](/docs/build/sails/sails.mdx) is a library for writing applications utilizing the Gear Protocol with simplicity and clarity. This powerful tool represents the next step in the evolution of the Gear Protocol.

Initially, Gear applications typically employ the less convenient [`gstd`](/docs/build/gstd/gstd.md) library for managing low-level operations and essential functionality. The `Sails` library builds programs on top of `gstd`, handling most low-level interactions under the hood. As projects grow, adopting the `Sails` framework allows developers to shift towards a more modular and service-oriented architecture. Existing dApps written with `gstd` can be effortlessly migrated to `Sails`.

This guide focuses on the key steps involved in transitioning existing gstd-based code to the `Sails` framework, outlining the necessary code transformations and architectural adjustments while leveraging the underlying `gstd` infrastructure.

## Setting Up Your Sails Project

To get started with the migration process, you can use a template to create a new project with Sails.

- First, install the sails-cli tool using the following command:

```bash
cargo install sails-cli
```

- After installation, you can generate a new project named "vara-app" by running:

```bash
cargo-sails new-program vara-app
```

## Migrating Action Handling

- In **gstd**-based projects, actions are typically defined using enums, which are processed within a `handle` function. This function decodes incoming messages and matches them to the corresponding action:

```rust
pub enum Action {
DoA,
DoB,
}
impl Metadata for ProgramMetadata {
type Handle = In<Action>;
}
#[no_mangle]
extern fn handle() {
let action: Action = msg::load().expect("Failed to decode `Action` message.");
match action {
Action::DoA => { /* Implementation for action A */ },
Action::DoB => { /* Implementation for action B */ },
}
}
```
- In **`Sails`**, this approach is restructured to leverage the framework’s service-oriented architecture. Rather than processing all actions through a single entry point, each action is encapsulated in its own service method. Here’s how the same functionality would look in `Sails`:
```rust
#[service]
impl Service {
pub fn do_a(&mut self) { /* Implementation for action A */ }
pub fn do_b(&mut self) { /* Implementation for action B */ }
}
```
This shift abstracts the message decoding and routing logic, with `Sails` automatically handling the dispatch of incoming messages to the appropriate service methods. The resulting code is more modular, with each action represented as a discrete method.
## Migrating Reply Messages
- In the case of low-level use of **`gstd`**, sending a reply message is done manually after the action has been processed. The reply should be sent using the `msg::reply` function:
```rust
#[no_mangle]
extern fn handle() {
let action: Action = msg::load().expect("Failed to decode `Action` message.");
match action {
Action::DoA => {
// Implementation for action A
msg::reply(reply, 0).expect("Failed to encode `reply`");
},
}
}
```
- When using **`Sails`**, replies are returned directly from the service function, and the framework manages the encoding and sending of the message:
```rust
#[service]
impl Service {
pub fn do_a(&mut self) -> TypeOfReply {
// Implementation for action A
reply
}
}
```
This reduces manual work, as the framework abstracts the reply handling, resulting in more concise code.
## Migrating State Queries
- State queries are often implemented through enums, which handle different state requests and responses manually within a `state` function:
```rust
pub enum StateQuery {
State1,
State2,
}
pub enum StateReply {
State1(...),
State2(...),
}
impl Metadata for ProgramMetadata {
type State = InOut<StateQuery, StateReply>;
}
#[no_mangle]
extern fn state() {
let query: StateQuery = msg::load().expect("Unable to load the state query");
match query {
StateQuery::State1 => {
msg::reply(StateReply::State1(state), 0).expect("Unable to share the state");
},
StateQuery::State2 => {
msg::reply(StateReply::State2(state), 0).expect("Unable to share the state");
},
}
}
```
- When migrating to **`Sails`**, state-related functions are methods that take `&self` as a parameter, since they don’t modify the state but only query it:
```rust
#[service]
impl Service {
pub fn state_1(&self) -> TypeOfReply {
// Implementation for State1
state
}
pub fn state_2(&self) -> TypeOfReply {
// Implementation for State2
state
}
}
```
## Conclusion
Migrating a project from the `gstd` library to the `Sails` framework is a straightforward process that primarily involves adapting the code to a more modular and service-oriented structure. Since `Sails` operates on top of `gstd`, the core functionality remains the same, but the framework provides a more organized and maintainable approach to handling actions, replies, and state queries.
By following the steps outlined in this guide, you can easily refactor your project to take advantage of the abstractions and efficiency offered by `Sails`. This migration not only simplifies code management but also enhances the long-term scalability.
With just a few adjustments to your existing codebase, such as reorganizing action handling into service methods and streamlining state queries, your project can seamlessly transition to `Sails` without sacrificing any of the functionality provided by `gstd`.
22 changes: 3 additions & 19 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"

"@babel/parser@^7.24.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6":
"@babel/parser@^7.25.0", "@babel/parser@^7.25.6":
version "7.25.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f"
integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==
Expand Down Expand Up @@ -10165,16 +10165,7 @@ std-env@^3.0.1:
resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2"
integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==

"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0, string-width@^4.2.0:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -10223,14 +10214,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down

0 comments on commit b3b7229

Please sign in to comment.