Skip to content

Commit

Permalink
presence & no_std (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
Xavrax authored Aug 30, 2023
1 parent 3483fb6 commit 1e15d07
Show file tree
Hide file tree
Showing 13 changed files with 451 additions and 10 deletions.
15 changes: 14 additions & 1 deletion examples/no_std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
pubnub = { path = "../../", default_features = false, features = ["blocking", "serde", "publish", "subscribe"] }
pubnub = { path = "../../", default_features = false, features = ["blocking", "serde", "publish", "subscribe", "presence"] }
serde = { version = "1.0", default_features = false, features = ["derive"] }
getrandom = { version = "0.2", default_features = false, features = ["custom"] }

Expand All @@ -17,3 +17,16 @@ path = "src/publish.rs"
[[bin]]
name = "subscribe"
path = "src/subscribe.rs"

[[bin]]
name = "here_now"
path = "src/here_now.rs"

[[bin]]
name = "where_now"
path = "src/where_now.rs"

[[bin]]
name = "presence_state"
path = "src/presence_state.rs"

133 changes: 133 additions & 0 deletions examples/no_std/src/here_now.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Warning: This example is compiling for target `thumbv7m-none-eabi`
// but have never been tested for this target.
//
// Treat it as a reference only!

#![no_std]
#![no_main]

extern crate alloc;

use core::{
alloc::{GlobalAlloc, Layout},
panic::PanicInfo,
};

use pubnub::{
core::{
transport::{blocking::Transport, PUBNUB_DEFAULT_BASE_URL},
transport_request::TransportRequest,
transport_response::TransportResponse,
PubNubError,
},
Keyset, PubNubClientBuilder,
};

// As getrandom crate has limited support of targets, we need to provide custom
// implementation of `getrandom` function.
getrandom::register_custom_getrandom!(custom_random);
fn custom_random(buf: &mut [u8]) -> Result<(), getrandom::Error> {
// We're using `42` as a random number, because it's the answer
// to the Ultimate Question of Life, the Universe, and Everything.
// In your program, you should use proper random number generator that is supported by your target.
for i in buf.iter_mut() {
*i = 42;
}

Ok(())
}

// Many targets have very specific requirements for networking, so it's hard to
// provide a generic implementation.
// Depending on the target, you will probably need to implement `Transport` trait.
struct MyTransport;

impl Transport for MyTransport {
fn send(&self, _: TransportRequest) -> Result<TransportResponse, PubNubError> {
let _hostname = PUBNUB_DEFAULT_BASE_URL;

// Send your request here

Ok(TransportResponse::default())
}
}

// As our target does not have `std` library, we need to provide custom
// implementation of `GlobalAlloc` trait.
//
// In your program, you should use proper allocator that is supported by your target.
// Here you have dummy implementation that does nothing.
#[derive(Default)]
pub struct Allocator;

unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
core::ptr::null_mut()
}
unsafe fn dealloc(&self, _: *mut u8, _layout: Layout) {}
}

#[global_allocator]
static GLOBAL_ALLOCATOR: Allocator = Allocator;

// As our target does not have `std` library, we need to provide custom
// implementation of `panic_handler`.
//
// In your program, you should use proper panic handler that is supported by your target.
// Here you have dummy implementation that does nothing.
#[panic_handler]
fn panicking(_: &PanicInfo) -> ! {
loop {}
}

// As we're using `no_main` attribute, we need to define `main` function manually.
// For this example we're using `extern "C"` ABI to make it work.
#[no_mangle]
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> usize {
publish_example().map(|_| 0).unwrap()
}

// In standard subscribe examples we use `println` macro to print the result of the operation
// and it shows the idea of the example. `no_std` does not support `println` macro,
// so we're using `do_a_thing` function instead.
fn do_a_thing<T>(_: &T) {}

// As `no_std` does not support `Error` trait, we use `PubNubError` instead.
// In your program, you should handle the error properly for your use case.
fn publish_example() -> Result<(), PubNubError> {
// As `no_std` does not support `env::var`, you need to set the keys manually.
let publish_key = "SDK_PUB_KEY";
let subscribe_key = "SDK_SUB_KEY";

let client = PubNubClientBuilder::with_blocking_transport(MyTransport)
.with_keyset(Keyset {
subscribe_key,
publish_key: Some(publish_key),
secret_key: None,
})
.with_user_id("user_id")
.build()?;

let channels_now = client
.here_now()
.channels(["my_channel".into(), "other_channel".into()].to_vec())
.include_state(true)
.include_user_id(true)
.execute_blocking()?;

// As `no_std` does not support `println` macro, we're using `do_a_thing` function instead
// to show possible usage of the result.

channels_now.iter().for_each(|channel| {
do_a_thing(&channel.name);
do_a_thing(&channel.occupancy);
do_a_thing(&channel.occupants);

channel
.occupants
.iter()
.for_each(|occupant| do_a_thing(occupant));
});

Ok(())
}
143 changes: 143 additions & 0 deletions examples/no_std/src/presence_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Warning: This example is compiling for target `thumbv7m-none-eabi`
// but have never been tested for this target.
//
// Treat it as a reference only!

#![no_std]
#![no_main]

extern crate alloc;

use core::{
alloc::{GlobalAlloc, Layout},
panic::PanicInfo,
};

use alloc::string::String;
use pubnub::{
core::{
transport::{blocking::Transport, PUBNUB_DEFAULT_BASE_URL},
transport_request::TransportRequest,
transport_response::TransportResponse,
PubNubError,
},
Keyset, PubNubClientBuilder,
};
use serde::Serialize;

#[derive(Debug, Serialize)]
struct State {
is_doing: String,
}

// As getrandom crate has limited support of targets, we need to provide custom
// implementation of `getrandom` function.
getrandom::register_custom_getrandom!(custom_random);
fn custom_random(buf: &mut [u8]) -> Result<(), getrandom::Error> {
// We're using `42` as a random number, because it's the answer
// to the Ultimate Question of Life, the Universe, and Everything.
// In your program, you should use proper random number generator that is supported by your target.
for i in buf.iter_mut() {
*i = 42;
}

Ok(())
}

// Many targets have very specific requirements for networking, so it's hard to
// provide a generic implementation.
// Depending on the target, you will probably need to implement `Transport` trait.
struct MyTransport;

impl Transport for MyTransport {
fn send(&self, _: TransportRequest) -> Result<TransportResponse, PubNubError> {
let _hostname = PUBNUB_DEFAULT_BASE_URL;

// Send your request here

Ok(TransportResponse::default())
}
}

// As our target does not have `std` library, we need to provide custom
// implementation of `GlobalAlloc` trait.
//
// In your program, you should use proper allocator that is supported by your target.
// Here you have dummy implementation that does nothing.
#[derive(Default)]
pub struct Allocator;

unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
core::ptr::null_mut()
}
unsafe fn dealloc(&self, _: *mut u8, _layout: Layout) {}
}

#[global_allocator]
static GLOBAL_ALLOCATOR: Allocator = Allocator;

// As our target does not have `std` library, we need to provide custom
// implementation of `panic_handler`.
//
// In your program, you should use proper panic handler that is supported by your target.
// Here you have dummy implementation that does nothing.
#[panic_handler]
fn panicking(_: &PanicInfo) -> ! {
loop {}
}

// As we're using `no_main` attribute, we need to define `main` function manually.
// For this example we're using `extern "C"` ABI to make it work.
#[no_mangle]
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> usize {
publish_example().map(|_| 0).unwrap()
}

// In standard subscribe examples we use `println` macro to print the result of the operation
// and it shows the idea of the example. `no_std` does not support `println` macro,
// so we're using `do_a_thing` function instead.
fn do_a_thing<T>(_: &T) {}

// As `no_std` does not support `Error` trait, we use `PubNubError` instead.
// In your program, you should handle the error properly for your use case.
fn publish_example() -> Result<(), PubNubError> {
// As `no_std` does not support `env::var`, you need to set the keys manually.
let publish_key = "SDK_PUB_KEY";
let subscribe_key = "SDK_SUB_KEY";

let client = PubNubClientBuilder::with_blocking_transport(MyTransport)
.with_keyset(Keyset {
subscribe_key,
publish_key: Some(publish_key),
secret_key: None,
})
.with_user_id("user_id")
.build()?;

// As `no_std` does not support `println` macro, we're using `do_a_thing` function instead
// to show possible usage of the result.

client
.set_presence_state(State {
is_doing: "Nothing... Just hanging around...".into(),
})
.channels(["my_channel".into(), "other_channel".into()].to_vec())
.user_id("user_id")
.execute_blocking()?;

let states = client
.get_presence_state()
.channels(["my_channel".into(), "other_channel".into()].to_vec())
.user_id("user_id")
.execute_blocking()?;

do_a_thing(&states);

states.iter().for_each(|channel| {
do_a_thing(&channel.channel);
do_a_thing(&channel.state);
});

Ok(())
}
Loading

0 comments on commit 1e15d07

Please sign in to comment.