diff --git a/examples/no_std/Cargo.toml b/examples/no_std/Cargo.toml index 9b5b2c5c..28a5e316 100644 --- a/examples/no_std/Cargo.toml +++ b/examples/no_std/Cargo.toml @@ -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"] } @@ -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" + diff --git a/examples/no_std/src/here_now.rs b/examples/no_std/src/here_now.rs new file mode 100644 index 00000000..0750b8d9 --- /dev/null +++ b/examples/no_std/src/here_now.rs @@ -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 { + 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) {} + +// 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(()) +} diff --git a/examples/no_std/src/presence_state.rs b/examples/no_std/src/presence_state.rs new file mode 100644 index 00000000..b2129252 --- /dev/null +++ b/examples/no_std/src/presence_state.rs @@ -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 { + 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) {} + +// 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(()) +} diff --git a/examples/no_std/src/where_now.rs b/examples/no_std/src/where_now.rs new file mode 100644 index 00000000..b2c0490c --- /dev/null +++ b/examples/no_std/src/where_now.rs @@ -0,0 +1,121 @@ +// 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 { + 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) {} + +// 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. + + let where_user = client.where_now().user_id("user_id").execute_blocking()?; + + where_user.iter().for_each(|channel| { + do_a_thing(&channel); + }); + + Ok(()) +} diff --git a/src/dx/presence/builders/get_presence_state.rs b/src/dx/presence/builders/get_presence_state.rs index e509e13c..e90d88c9 100644 --- a/src/dx/presence/builders/get_presence_state.rs +++ b/src/dx/presence/builders/get_presence_state.rs @@ -26,8 +26,10 @@ use crate::{ }, lib::{ alloc::{ + format, string::{String, ToString}, vec, + vec::Vec, }, collections::HashMap, }, diff --git a/src/dx/presence/builders/heartbeat.rs b/src/dx/presence/builders/heartbeat.rs index 855e4eb2..32d96dac 100644 --- a/src/dx/presence/builders/heartbeat.rs +++ b/src/dx/presence/builders/heartbeat.rs @@ -26,8 +26,10 @@ use crate::{ }, lib::{ alloc::{ + format, string::{String, ToString}, vec, + vec::Vec, }, collections::HashMap, }, diff --git a/src/dx/presence/builders/here_now.rs b/src/dx/presence/builders/here_now.rs index 9b2fc9eb..cc6b4a7c 100644 --- a/src/dx/presence/builders/here_now.rs +++ b/src/dx/presence/builders/here_now.rs @@ -14,7 +14,15 @@ use crate::{ Deserializer, PubNubError, Transport, TransportMethod, TransportRequest, }, dx::{presence::builders, pubnub_client::PubNubClientInstance}, - lib::collections::HashMap, + lib::{ + alloc::{ + format, + string::{String, ToString}, + vec, + vec::Vec, + }, + collections::HashMap, + }, presence::result::{HereNowResponseBody, HereNowResult}, }; diff --git a/src/dx/presence/builders/leave.rs b/src/dx/presence/builders/leave.rs index 642ca698..3c46140d 100644 --- a/src/dx/presence/builders/leave.rs +++ b/src/dx/presence/builders/leave.rs @@ -5,13 +5,14 @@ use derive_builder::Builder; +use crate::core::Transport; use crate::{ core::{ utils::{ encoding::{url_encoded_channel_groups, url_encoded_channels}, headers::{APPLICATION_JSON, CONTENT_TYPE}, }, - Deserializer, PubNubError, Transport, TransportMethod, TransportRequest, + Deserializer, PubNubError, TransportMethod, TransportRequest, }, dx::{ presence::{ @@ -22,8 +23,10 @@ use crate::{ }, lib::{ alloc::{ + format, string::{String, ToString}, vec, + vec::Vec, }, collections::HashMap, }, diff --git a/src/dx/presence/builders/set_presence_state.rs b/src/dx/presence/builders/set_presence_state.rs index a10d0f02..bf81041b 100644 --- a/src/dx/presence/builders/set_presence_state.rs +++ b/src/dx/presence/builders/set_presence_state.rs @@ -26,8 +26,10 @@ use crate::{ }, lib::{ alloc::{ + format, string::{String, ToString}, vec, + vec::Vec, }, collections::HashMap, }, diff --git a/src/dx/presence/builders/where_now.rs b/src/dx/presence/builders/where_now.rs index 64e31aba..1c2201df 100644 --- a/src/dx/presence/builders/where_now.rs +++ b/src/dx/presence/builders/where_now.rs @@ -14,7 +14,13 @@ use crate::{ Deserializer, PubNubError, Transport, TransportMethod, TransportRequest, }, dx::{presence::builders, pubnub_client::PubNubClientInstance}, - lib::collections::HashMap, + lib::{ + alloc::{ + format, + string::{String, ToString}, + }, + collections::HashMap, + }, presence::result::{WhereNowResponseBody, WhereNowResult}, }; diff --git a/src/dx/presence/mod.rs b/src/dx/presence/mod.rs index decbddf0..33758b99 100644 --- a/src/dx/presence/mod.rs +++ b/src/dx/presence/mod.rs @@ -9,11 +9,14 @@ use futures::{ future::{ready, BoxFuture}, {select_biased, FutureExt}, }; + +#[cfg(feature = "std")] use spin::RwLock; use crate::{ - core::{Deserializer, PubNubError, Serialize, Transport}, + core::{Deserializer, Serialize, Transport}, dx::pubnub_client::PubNubClientInstance, + lib::alloc::string::ToString, }; #[doc(inline)] @@ -40,7 +43,7 @@ pub(crate) mod event_engine; use crate::{ core::{ event_engine::{cancel::CancellationTask, EventEngine}, - Runtime, + PubNubError, Runtime, }, lib::alloc::sync::Arc, }; @@ -101,7 +104,7 @@ impl PubNubClientInstance { /// `user_id` on channels. /// /// Instance of [`LeaveRequestBuilder`] returned. - pub(crate) fn leave(&self) -> LeaveRequestBuilder { + pub fn leave(&self) -> LeaveRequestBuilder { LeaveRequestBuilder { pubnub_client: Some(self.clone()), user_id: Some(self.config.user_id.clone().to_string()), @@ -494,6 +497,7 @@ where .boxed() } + #[cfg(feature = "std")] /// Call to update `state` associated with `user_id`. #[allow(dead_code)] pub(crate) fn set_heartbeat_call(client: Self, _params: PresenceParameters, state: U) @@ -501,7 +505,6 @@ where U: Serialize + Send + Sync + 'static, { // TODO: This is still under development and will be part of EE. - #[cfg(feature = "std")] { client.configure_presence(); @@ -512,6 +515,7 @@ where } } + #[cfg(feature = "std")] pub(crate) fn heartbeat_request( &self, params: PresenceParameters, diff --git a/src/dx/presence/presence_manager.rs b/src/dx/presence/presence_manager.rs index 9e094034..8b05d72b 100644 --- a/src/dx/presence/presence_manager.rs +++ b/src/dx/presence/presence_manager.rs @@ -6,7 +6,7 @@ use crate::{ dx::presence::event_engine::PresenceEventEngine, lib::{ - alloc::sync::Arc, + alloc::{string::String, sync::Arc, vec::Vec}, core::{ fmt::{Debug, Formatter, Result}, ops::{Deref, DerefMut}, diff --git a/src/dx/presence/result.rs b/src/dx/presence/result.rs index 3b8f4444..c67b4294 100644 --- a/src/dx/presence/result.rs +++ b/src/dx/presence/result.rs @@ -10,7 +10,11 @@ use crate::{ }, PubNubError, }, - lib::{collections::HashMap, core::ops::Deref}, + lib::{ + alloc::{string::String, vec, vec::Vec}, + collections::HashMap, + core::ops::Deref, + }, }; /// The result of a heartbeat announcement operation.