Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

presence & no_std #172

Merged
merged 5 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading