Skip to content

Commit

Permalink
refactor: rethinking the way to work with async-graphql library
Browse files Browse the repository at this point in the history
changes the way to specify async-graphql root query and mutation

the old way to use sdk in async-graphql is not working anymore and should be rewritten
  • Loading branch information
meskill committed Aug 6, 2022
1 parent 4f37a44 commit dfea16e
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 13 deletions.
4 changes: 2 additions & 2 deletions examples/serde_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ const LIB_PATH: &str = if cfg!(target_arch = "x86_64") {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let sdk = MysticLightSDK::new(LIB_PATH)?;

let devices = sdk.get_devices()?;
let devices: Vec<_> = sdk.devices_iter().collect();

println!("devices json: {}", serde_json::to_string_pretty(&devices)?);

let keyboard_leds = devices[2].leds()?;
let keyboard_leds: Vec<_> = devices[2].leds_iter().collect();

println!(
"keyboard_leds json: {}",
Expand Down
10 changes: 5 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@
//!
//! Enables [async-graphql](https://crates.io/crates/async-graphql) support for sdk entities
//!
//! When this feature is enabled you can use [MysticLightSDK] as async_graphql::Query and [MysticLightSDKMutation] as async_graphql::Mutation
//! When this feature is enabled you can use [MysticLightGraphqlQuery] as async_graphql::Query and [MysticLightGraphqlMutation] as async_graphql::Mutation
//!
//! ```
//! use async_graphql::{EmptySubscription, Schema};
//! use mystic_light_sdk::{MysticLightSDK, MysticLightSDKMutation};
//! use mystic_light_sdk::{build_graphql_schema, MysticLightSDK, MysticLightGraphqlMutation, MysticLightGraphqlQuery};
//!
//! pub type MysticLightSchema = Schema<MysticLightSDK, MysticLightSDKMutation, EmptySubscription>;
//! pub type MysticLightSchema = Schema<MysticLightGraphqlQuery, MysticLightGraphqlMutation, EmptySubscription>;
//!
//! pub fn create_qraphql_schema(sdk: MysticLightSDK) -> MysticLightSchema {
//! let mutation = MysticLightSDKMutation(sdk.clone());
//! let (query, mutation) = build_graphql_schema(sdk);
//!
//! Schema::build(sdk, mutation, EmptySubscription).finish()
//! Schema::build(query, mutation, EmptySubscription).finish()
//! }
//!
//! ```
Expand Down
5 changes: 5 additions & 0 deletions src/sdk/device.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "async-graphql")]
use either::Either;
use libloading::Library;
use std::collections::HashMap;
Expand Down Expand Up @@ -66,6 +67,7 @@ impl Device {
self.name()
}

/// returns device's leds
async fn leds(&self, #[graphql(default)] filter: DeviceLedFilter) -> Vec<&DeviceLed> {
filter_leds(&self.leds, filter).collect()
}
Expand All @@ -80,6 +82,7 @@ pub struct DeviceMutation<'a>(pub &'a Device);
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl<'a> DeviceMutation<'a> {
/// returns device's leds wrapped in mutation wrapper
async fn leds(&self, #[graphql(default)] filter: DeviceLedFilter) -> Vec<DeviceLedMutation> {
filter_leds(&self.0.leds, filter)
.map(DeviceLedMutation)
Expand Down Expand Up @@ -118,10 +121,12 @@ impl Device {
})
}

/// returns iterator over device's leds
pub fn leds_iter(&self) -> impl Iterator<Item = &DeviceLed> {
self.leds.values()
}

/// reload cached leds info
pub fn reload(&mut self) -> Result<()> {
log::debug!("fn:reload call");

Expand Down
2 changes: 2 additions & 0 deletions src/sdk/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::clone::Clone;
use std::sync::PoisonError;

use custom_error::custom_error;
Expand Down Expand Up @@ -37,6 +38,7 @@ custom_error! {

custom_error! {
/// Errors with multithreading
#[derive(Clone)]
#[non_exhaustive]
pub SyncError
Poison = "Shared object (Mutex or RwLock) is poisoned"
Expand Down
1 change: 1 addition & 0 deletions src/sdk/led.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub struct DeviceLedMutation<'a>(pub &'a DeviceLed);
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl<'a> DeviceLedMutation<'a> {
/// updates state for the device led
pub async fn set_state(&self, state: DeviceLedStateInput) -> Result<bool> {
self.0.merge_with_state(&state)?;

Expand Down
99 changes: 93 additions & 6 deletions src/sdk/mystic_light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ use std::{
sync::{Arc, Mutex},
};

#[cfg(feature = "async-graphql")]
use either::Either;
use libloading::{Library, Symbol};

#[cfg(feature = "async-graphql")]
use crate::DeviceMutation;
use crate::{winapi::FromSafeArray, DeviceTypes, LedCounts, MysticLightSdkResult};
#[cfg(feature = "async-graphql")]
use crate::{DeviceMutation, SyncError};

use super::{
device::Device,
Expand Down Expand Up @@ -59,12 +60,15 @@ fn filter_devices(
pub struct MysticLightSDK {
library: Arc<Mutex<Library>>,
devices: HashMap<String, Device>,
#[cfg(feature = "async-graphql")]
lib_path: String,
}

/// Rust Wrapper for the underlying Mystic Light SDK
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl MysticLightSDK {
/// returns Mystic Light devices
async fn devices(&self, #[graphql(default)] filter: DeviceFilter) -> Vec<&Device> {
filter_devices(&self.devices, filter).collect()
}
Expand All @@ -79,13 +83,89 @@ pub struct MysticLightSDKMutation(pub Arc<MysticLightSDK>);
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl MysticLightSDKMutation {
async fn devices(&self, #[graphql(default)] filter: DeviceFilter) -> Vec<DeviceMutation> {
filter_devices(&self.0.devices, filter)
/// returns Mystic Light devices wrapped in mutation wrapper
async fn devices(
&self,
#[graphql(default)] filter: DeviceFilter,
) -> Result<Vec<DeviceMutation>> {
let devices = filter_devices(&self.0.devices, filter)
.map(DeviceMutation)
.collect()
.collect();

Ok(devices)
}
}

#[cfg(feature = "async-graphql")]
struct MysticLightGraphqlWrapper(pub Mutex<Arc<MysticLightSDK>>);

#[cfg(feature = "async-graphql")]
impl MysticLightGraphqlWrapper {
fn sdk(&self) -> std::result::Result<Arc<MysticLightSDK>, SyncError> {
let sdk = self.0.lock()?;

Ok(Arc::clone(&sdk))
}

fn reload(&self) -> Result<()> {
let mut sdk = self.0.lock()?;

*sdk = Arc::new(MysticLightSDK::new(&sdk.lib_path)?);

Ok(())
}
}

/// Graphql query for MysticLightSDK
#[cfg(feature = "async-graphql")]
pub struct MysticLightGraphqlQuery(Arc<MysticLightGraphqlWrapper>);

/// Graphql query for MysticLightSDK
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl MysticLightGraphqlQuery {
#[graphql(flatten)]
async fn sdk(&self) -> std::result::Result<Arc<MysticLightSDK>, SyncError> {
self.0.sdk()
}
}

/// Graphql mutation for MysticLightSDK
#[cfg(feature = "async-graphql")]
pub struct MysticLightGraphqlMutation(Arc<MysticLightGraphqlWrapper>);

/// Graphql mutation for MysticLightSDK
#[cfg(feature = "async-graphql")]
#[async_graphql::Object]
impl MysticLightGraphqlMutation {
#[graphql(flatten)]
async fn sdk(&self) -> std::result::Result<MysticLightSDKMutation, SyncError> {
let sdk = self.0.sdk()?;

Ok(MysticLightSDKMutation(sdk))
}

/// Full reload of Mystic Light SDK to get most-fresh hardware data
async fn reload(&self) -> Result<bool> {
self.0.reload()?;

Ok(true)
}
}

#[cfg(feature = "async-graphql")]
pub fn build_graphql_schema(
sdk: MysticLightSDK,
) -> (MysticLightGraphqlQuery, MysticLightGraphqlMutation) {
let sdk = Arc::new(sdk);
let wrapper = Arc::new(MysticLightGraphqlWrapper(Mutex::new(sdk)));

(
MysticLightGraphqlQuery(Arc::clone(&wrapper)),
MysticLightGraphqlMutation(Arc::clone(&wrapper)),
)
}

impl MysticLightSDK {
/// Parse the result of the underlying dll call and convert to the Rust's Result
pub fn parse_result(
Expand Down Expand Up @@ -123,13 +203,20 @@ impl MysticLightSDK {
let library = Arc::new(Mutex::new(library));
let devices = Self::resolve_devices(&library)?;

Ok(MysticLightSDK { library, devices })
Ok(MysticLightSDK {
library,
devices,
#[cfg(feature = "async-graphql")]
lib_path: lib_path.to_owned(),
})
}

/// returns Iterator iver Mystic Light devices
pub fn devices_iter(&self) -> impl Iterator<Item = &Device> {
self.devices.values()
}

/// reload cached devices info
pub fn reload(&mut self) -> Result<()> {
log::debug!("fn:reload call");

Expand Down

0 comments on commit dfea16e

Please sign in to comment.