-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of github.com:foxglove/foxglove-sdk into adrian/t…
…s-package
- Loading branch information
Showing
29 changed files
with
481 additions
and
486 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Foxglove Rust SDK | ||
|
||
## Development | ||
|
||
### Generate Protobuf schemas | ||
|
||
```bash | ||
cargo run --bin foxglove-proto-gen | ||
``` | ||
|
||
### Run the example server | ||
|
||
1. `cargo run --features unstable --example ws-server` | ||
2. Open the Foxglove desktop app | ||
3. From the dashboard, click "Open connection..." | ||
4. Confirm the WebSocket URL and click "Open" | ||
5. Create a Raw Messages panel and enter "topic" in the message path field at the top |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,31 @@ | ||
# Foxglove Rust SDK | ||
# Foxglove | ||
|
||
## Development | ||
The official [Foxglove] SDK. | ||
|
||
### Generate Protobuf schemas | ||
This crate provides support for integrating with the Foxglove platform. It can be used to log | ||
events to local [MCAP] files or a local visualization server that communicates with the | ||
Foxglove app. | ||
|
||
```bash | ||
cargo run --bin foxglove-proto-gen | ||
``` | ||
[Foxglove]: https://docs.foxglove.dev/ | ||
[MCAP]: https://mcap.dev/ | ||
|
||
### Run the example server | ||
# Overview | ||
|
||
1. `cargo run --features unstable --example ws-server` | ||
2. Open the Foxglove desktop app | ||
3. From the dashboard, click "Open connection..." | ||
4. Confirm the WebSocket URL and click "Open" | ||
5. Create a Raw Messages panel and enter "topic" in the message path field at the top | ||
To record messages, you need at least one sink and at least one channel. | ||
|
||
A "sink" is a destination for logged messages — either an MCAP file or a live visualization server. Use `McapWriter::new()` to register a new MCAP sink. Use `WebSocketServer::new` to create a new live visualization server. | ||
|
||
A "channel" gives a way to log related messages which have the same schema. Each channel is instantiated with a unique topic name. | ||
|
||
The SDK provides structs for well-known schemas. These can be used in conjunction with | ||
`TypedChannel` for type-safe logging, which ensures at compile time that | ||
messages logged to a channel all share a common schema. | ||
|
||
You can also define your own custom data types by implementing the `Encode` trait. This | ||
allows you to log arbitrary custom data types. Notably, the `Encode` trait is | ||
automatically implemented for types that implement `serde::Serialize` and | ||
`schemars::JsonSchema`. This makes it easy to define new custom messages. | ||
|
||
# Get Started | ||
|
||
For more information and examples, see [docs.rs](https://docs.rs/foxglove). |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
//! Example websocket server with client publsih | ||
//! | ||
//! This example uses the 'unstable' feature to expose capabilities. | ||
//! | ||
//! Usage: | ||
//! ```text | ||
//! cargo run --features unstable --example client-publish | ||
//! ``` | ||
use clap::Parser; | ||
use foxglove::schemas::log::Level; | ||
use foxglove::schemas::Log; | ||
use foxglove::{ | ||
Capability, ClientChannelId, PartialMetadata, ServerListener, TypedChannel, WebSocketServer, | ||
}; | ||
use std::sync::Arc; | ||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; | ||
use tokio_util::sync::CancellationToken; | ||
|
||
#[derive(Debug, Parser)] | ||
struct Cli { | ||
#[arg(short, long, default_value_t = 8765)] | ||
port: u16, | ||
#[arg(long, default_value = "127.0.0.1")] | ||
host: String, | ||
#[arg(long, default_value = "example-json-server")] | ||
server_name: String, | ||
} | ||
|
||
struct ExampleCallbackHandler; | ||
impl ServerListener for ExampleCallbackHandler { | ||
fn on_message_data(&self, channel_id: ClientChannelId, message: &[u8]) { | ||
let json: serde_json::Value = | ||
serde_json::from_slice(message).expect("Failed to parse message"); | ||
println!("Received message on channel {channel_id}: {json}"); | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let env = env_logger::Env::default().default_filter_or("info"); | ||
env_logger::init_from_env(env); | ||
|
||
let args = Cli::parse(); | ||
|
||
let server = WebSocketServer::new() | ||
.name("client-publish") | ||
.bind(args.host, args.port) | ||
.capabilities([Capability::ClientPublish]) | ||
.listener(Arc::new(ExampleCallbackHandler)) | ||
.start() | ||
.await | ||
.expect("Failed to start server"); | ||
|
||
let shutdown = watch_ctrl_c(); | ||
tokio::select! { | ||
() = shutdown.cancelled() => (), | ||
() = log_forever() => (), | ||
}; | ||
|
||
server.stop().await; | ||
} | ||
|
||
async fn log_forever() { | ||
let channel = TypedChannel::new("/log").expect("Failed to create channel"); | ||
let start = Instant::now(); | ||
let mut sequence = 0; | ||
let mut interval = tokio::time::interval(Duration::from_secs(1)); | ||
loop { | ||
interval.tick().await; | ||
let msg = Log { | ||
timestamp: Some(SystemTime::now().into()), | ||
message: format!("It's been {:?}", start.elapsed()), | ||
level: Level::Info.into(), | ||
..Default::default() | ||
}; | ||
let meta = PartialMetadata { | ||
sequence: Some(sequence), | ||
publish_time: Some(nanoseconds_since_epoch()), | ||
..Default::default() | ||
}; | ||
channel.log_with_meta(&msg, meta); | ||
sequence += 1; | ||
} | ||
} | ||
|
||
fn watch_ctrl_c() -> CancellationToken { | ||
let token = CancellationToken::new(); | ||
tokio::spawn({ | ||
let token = token.clone(); | ||
async move { | ||
tokio::signal::ctrl_c().await.ok(); | ||
token.cancel(); | ||
} | ||
}); | ||
token | ||
} | ||
|
||
pub(crate) fn nanoseconds_since_epoch() -> u64 { | ||
let now = SystemTime::now(); | ||
if let Ok(duration) = now.duration_since(UNIX_EPOCH) { | ||
return duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; | ||
} | ||
0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
//! Example of a parameter server using the Foxglove SDK. | ||
//! | ||
//! This example uses the 'unstable' feature to expose capabilities. | ||
//! | ||
//! Usage: | ||
//! ```text | ||
//! cargo run --features unstable --example param-server | ||
//! ``` | ||
use std::time::{Duration, Instant}; | ||
|
||
use clap::Parser; | ||
use foxglove::{ | ||
Capability, Parameter, ParameterType, ParameterValue, WebSocketServer, WebSocketServerHandle, | ||
}; | ||
use tokio_util::sync::CancellationToken; | ||
|
||
#[derive(Debug, Parser)] | ||
struct Cli { | ||
#[arg(short, long, default_value_t = 8765)] | ||
port: u16, | ||
#[arg(long, default_value = "127.0.0.1")] | ||
host: String, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let env = env_logger::Env::default().default_filter_or("debug"); | ||
env_logger::init_from_env(env); | ||
|
||
let args = Cli::parse(); | ||
|
||
let server = WebSocketServer::new() | ||
.name("param server") | ||
.capabilities([Capability::Parameters]) | ||
.bind(args.host, args.port) | ||
.start() | ||
.await | ||
.expect("Failed to start server"); | ||
|
||
let shutdown = watch_ctrl_c(); | ||
tokio::select! { | ||
() = shutdown.cancelled() => (), | ||
() = update_parameters(&server) => (), | ||
}; | ||
|
||
server.stop().await; | ||
} | ||
|
||
async fn update_parameters(server: &WebSocketServerHandle) { | ||
let start = Instant::now(); | ||
let mut interval = tokio::time::interval(Duration::from_secs(1)); | ||
loop { | ||
interval.tick().await; | ||
let parameter = Parameter { | ||
name: "elapsed".to_string(), | ||
value: Some(ParameterValue::Number(start.elapsed().as_secs_f64())), | ||
r#type: Some(ParameterType::Float64), | ||
}; | ||
server.publish_parameter_values(vec![parameter]).await; | ||
} | ||
} | ||
|
||
fn watch_ctrl_c() -> CancellationToken { | ||
let token = CancellationToken::new(); | ||
tokio::spawn({ | ||
let token = token.clone(); | ||
async move { | ||
tokio::signal::ctrl_c().await.ok(); | ||
token.cancel(); | ||
} | ||
}); | ||
token | ||
} |
Oops, something went wrong.