Commands

Overview
This example demonstrates how to use Turbo Genesis command and document APIs to build a simple counter program with two commands: add and reset.
Creating Commands (Server)
The Counter document
#[turbo::os::document(program = "counter")]
pub struct Counter {
/// Current counter value
pub value: i32,
}The add command
The add command reads the counter program file (creating it if it doesn't exist), updates the stored Counter, increments its value, and writes it back.
use turbo::os::server::*;
#[turbo::os::command(program = "counter", name = "add")]
pub struct Add {
/// Amount to add to the counter
amount: i32,
}
impl CommandHandler for Add {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Read existing counter or default to 0
let mut counter = fs::read("counter")
.unwrap_or(Counter { value: 0 });
// Apply increment
counter.value += self.amount;
log!("Incremented = {:?}", counter);
// Persist updated counter
fs::write("counter", &counter)?;
Ok(())
}
}The reset command
The reset command overwrites the counter file with a Counter initialized to 0.
#[turbo::os::command(program = "counter", name = "reset")]
pub struct Reset;
impl CommandHandler for Reset {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Overwrite the counter file with a Counter set to 0
fs::write("counter", &Counter { value: 0 })?;
Ok(())
}
}Using Commands (Client)
Now let's use the commands to update the counter document and display its value in the game.
Watch the Counter document
The counter data is stored in a program file named counter.
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
}
}Send some commands
Let's allow the player to add a random value or reset the counter file.
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
// When the "a" button (Z on keyboard) is pressed, send an Add command
if gamepad::get(0).a.just_pressed() {
let cmd = Add { amount: random::between(-100, 100) };
cmd.exec();
}
// When the "b" button (X on keyboard) is pressed, send a Reset command
if gamepad::get(0).b.just_pressed() {
let cmd = Reset;
cmd.exec();
}
}
}Running your game
Review Your Code
Ensure that your src/lib.rs file is correct:
See full src/lib.rs source code
use turbo::*;
use turbo::os::server::*;
#[turbo::os::document(program = "counter")]
pub struct Counter {
/// Current counter value
pub value: i32,
}
#[turbo::os::command(program = "counter", name = "add")]
pub struct Add {
/// Amount to add to the counter
amount: i32,
}
impl CommandHandler for Add {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Read existing counter or default to 0
let mut counter = fs::read("counter")
.unwrap_or(Counter { value: 0 });
// Apply increment
counter.value += self.amount;
log!("Incremented = {:?}", counter);
// Persist updated counter
fs::write("counter", &counter)?;
Ok(())
}
}
#[turbo::os::command(program = "counter", name = "reset")]
pub struct Reset;
impl CommandHandler for Reset {
fn run(&mut self, user_id: &str) -> Result<(), std::io::Error> {
// Overwrite the counter file with a Counter set to 0
fs::write("counter", &Counter { value: 0 })?;
Ok(())
}
}
#[turbo::game]
struct GameState;
impl GameState {
fn update(&mut self) {
// Watch the counter file and parse its contents when it loads
let counter = Counter::watch("counter")
.parse()
.unwrap_or(Counter { value: 0 });
// Draw the counter data
text!("{:#?}", counter);
// When the "a" button (Z on keyboard) is pressed, send an Add command
if gamepad::get(0).a.just_pressed() {
let cmd = Add { amount: random::between(-100, 100) };
cmd.exec();
}
// When the "b" button (X on keyboard) is pressed, send a Reset command
if gamepad::get(0).b.just_pressed() {
let cmd = Reset;
cmd.exec();
}
}
}Update your config
Update your turbo.toml file to include the following section:
[turbo-os]
api-url = "https://os.turbo.computer"Run with a user ID
Next, create a free dev account at https://os.turbo.computer. Your dashboard will display your user ID.
Run your game with:
turbo run -w --user <YOUR_USER_ID>It will prompt you for a one-time password, which you'll find on your Turbo OS dashboard.
When your game launches, it will upload the program:
[turbo] Uploading "counter" (YOUR_PROGRAM_ID)...
[turbo] Uploaded "counter" (YOUR_PROGRAM_ID) β¨Check your dashboard
On your Turbo OS Dashboard, scroll to the bottom to see uploaded programs. The counter program will appear there.
Click the blue arrow to view the program analytics page:

As you send add and reset commands, you can inspect the live activity feed to see logs and how the commands were processed:
