Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 17 additions & 16 deletions .justfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,46 @@
# default and it tests every subcrate.

test-all: format test-api _test-drivers test-drmemd
@echo "All tests passed successfuly!"
@echo "🎉 All tests passed successfuly!"

test-api:
@echo "Running units tests for drmem-api"; \
@echo "Running units tests for drmem-api"; \
nice cargo test -p drmem-api

_test-drivers: test-drv-ntp test-drv-sump test-drv-wu test-drv-tplink

test-drv-ntp: test-api
@echo "Running units tests for drmem-driver-ntp"; \
@echo "Running units tests for drmem-driver-ntp"; \
nice cargo test -p drmem-drv-ntp

test-drv-sump: test-api
@echo "Running units tests for drmem-driver-sump"; \
@echo "Running units tests for drmem-driver-sump"; \
nice cargo test -p drmem-drv-sump

test-drv-tplink: test-api
@echo "Running units tests for drmem-driver-tplink"; \
@echo "Running units tests for drmem-driver-tplink"; \
nice cargo test -p drmem-drv-tplink

test-drv-wu: test-api
@echo "Running units tests for drmem-driver-weather-wu"; \
@echo "Running units tests for drmem-driver-weather-wu"; \
nice cargo test -p drmem-drv-weather-wu

_test-simple: test-api
@echo "Running units tests for simple-backend, no-client"; \
@echo "Running units tests for simple-backend, no-client"; \
nice cargo test --features simple-backend,no-client

_test-simple-graphql: test-api
@echo "Running units tests for simple-backend, with GraphQL"; \
@echo "Running units tests for simple-backend, with GraphQL"; \
nice cargo test --features simple-backend,graphql

_test-redis-graphql: test-api
@echo "Running units tests for redis-backend, with GraphQL"; \
@echo "Running units tests for redis-backend, with GraphQL"; \
nice cargo test --features redis-backend,graphql

test-drmemd: _test-simple _test-simple-graphql _test-redis-graphql

build mode="dev":
@echo "Building {{ mode }}"
@echo "🔧 Building {{ mode }}"
nice cargo build \
{{ if mode == "rel" { "--release" } else { "" } }} \
--features simple-backend,graphql,all-drivers
Expand All @@ -51,29 +51,30 @@ build mode="dev":
# don't generate object files and it doesn't link anything together.

_check-simple:
@echo "Checking simple-backend, no-client"; \
@echo "🤔 Checking simple-backend, no-client"; \
nice cargo check --features simple-backend,no-client,all-drivers

_check-simple-graphql:
@echo "Checking simple-backend, with GraphQL"; \
@echo "🤔 Checking simple-backend, with GraphQL"; \
nice cargo check --features simple-backend,graphql,all-drivers

_check-redis-graphql:
@echo "Checking redis-backend, with GraphQL"; \
@echo "🤔 Checking redis-backend, with GraphQL"; \
nice cargo check --features redis-backend,graphql,all-drivers

check: _check-simple _check-simple-graphql _check-redis-graphql
@echo "DrMem source was checked successfully!"
@echo "🎉 DrMem source was checked successfully!"

# This section helps publish the project to crates.io.

publish: test-all
@echo "DrMem Project published successfully!"
@echo "🎉 DrMem Project published successfully!"

# Formats the project.

format:
nice cargo fmt --all
@echo "🎨 Formatting code ..."
@nice cargo fmt --all

# Local variables:
# mode: makefile
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ tracing = { version = "0.1", default-features = false, features = ["attributes"]
tracing-subscriber = { version = "0.3", default-features = false }
serde = { version = "1", default-features = false, features = ["rc"] }
serde_json = { version = "1", default-features = false }
serde_derive = { version = "1", default-features = false }
palette = { version = "0.7", default-features = false }

# Profiles used by all binaries and packages.
Expand Down
4 changes: 4 additions & 0 deletions drivers/drmem-drv-ntp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ keywords = ["control-system", "automation"]
doctest = false

[dependencies]
serde.workspace = true
serde.default-features = false
serde.features = ["derive"]

toml.workspace = true
toml.default-features = false

Expand Down
125 changes: 53 additions & 72 deletions drivers/drmem-drv-ntp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use drmem_api::{
device,
driver::{self, DriverConfig, ResettableState},
Error, Result,
};
use std::convert::Infallible;
use std::future::Future;
use std::{
net::{SocketAddr, SocketAddrV4},
str,
Expand Down Expand Up @@ -103,6 +101,11 @@ mod server {
}
}

#[derive(serde::Deserialize)]
struct InstanceConfig {
addr: SocketAddrV4,
}

pub struct Instance {
sock: UdpSocket,
seq: u16,
Expand All @@ -116,28 +119,6 @@ impl Instance {

pub const DESCRIPTION: &'static str = include_str!("../README.md");

// Attempts to pull the hostname/port for the remote process.

fn get_cfg_address(cfg: &DriverConfig) -> Result<SocketAddrV4> {
match cfg.get("addr") {
Some(toml::value::Value::String(addr)) => {
if let Ok(addr) = addr.parse::<SocketAddrV4>() {
Ok(addr)
} else {
Err(Error::ConfigError(String::from(
"'addr' not in hostname:port format",
)))
}
}
Some(_) => Err(Error::ConfigError(String::from(
"'addr' config parameter should be a string",
))),
None => Err(Error::ConfigError(String::from(
"missing 'addr' parameter in config",
))),
}
}

// Combines and returns the first two bytes from a buffer as a
// big-endian, 16-bit value.

Expand Down Expand Up @@ -363,68 +344,46 @@ pub struct Devices {
}

impl driver::Registrator for Devices {
fn register_devices<'a>(
core: &'a mut driver::RequestChan,
async fn register_devices(
core: &mut driver::RequestChan,
_: &DriverConfig,
_override_timeout: Option<Duration>,
max_history: Option<usize>,
) -> impl Future<Output = Result<Self>> + Send + 'a {
// It's safe to use `.unwrap()` for these names because, in a
// fully-tested, released version of this driver, we would
// have seen and fixed any panics.

let state_name = "state".parse::<device::Base>().unwrap();
let source_name = "source".parse::<device::Base>().unwrap();
let offset_name = "offset".parse::<device::Base>().unwrap();
let delay_name = "delay".parse::<device::Base>().unwrap();

Box::pin(async move {
// Define the devices managed by this driver.

let d_state =
core.add_ro_device(state_name, None, max_history).await?;
let d_source =
core.add_ro_device(source_name, None, max_history).await?;
let d_offset = core
.add_ro_device(offset_name, Some("ms"), max_history)
.await?;
let d_delay = core
.add_ro_device(delay_name, Some("ms"), max_history)
.await?;

Ok(Devices {
d_state,
d_source,
d_offset,
d_delay,
})
) -> Result<Self> {
// Define the devices managed by this driver.

let d_state = core.add_ro_device("state", None, max_history).await?;
let d_source = core.add_ro_device("source", None, max_history).await?;
let d_offset = core
.add_ro_device("offset", Some("ms"), max_history)
.await?;
let d_delay =
core.add_ro_device("delay", Some("ms"), max_history).await?;

Ok(Devices {
d_state,
d_source,
d_offset,
d_delay,
})
}
}

impl driver::API for Instance {
type HardwareType = Devices;

fn create_instance(
cfg: &DriverConfig,
) -> impl Future<Output = Result<Box<Self>>> + Send {
let addr = Instance::get_cfg_address(cfg);

async move {
// Validate the configuration.

let addr = addr?;
let loc_if = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
async fn create_instance(cfg: &DriverConfig) -> Result<Box<Self>> {
let cfg: InstanceConfig = cfg.parse_into()?;
let loc_if = "0.0.0.0:0".parse::<SocketAddr>().unwrap();

Span::current().record("cfg", addr.to_string());
Span::current().record("cfg", cfg.addr.to_string());

if let Ok(sock) = UdpSocket::bind(loc_if).await {
if sock.connect(addr).await.is_ok() {
return Ok(Box::new(Instance { sock, seq: 1 }));
}
if let Ok(sock) = UdpSocket::bind(loc_if).await {
if sock.connect(cfg.addr).await.is_ok() {
return Ok(Box::new(Instance { sock, seq: 1 }));
}
Err(Error::OperationError("couldn't create socket".to_owned()))
}
Err(Error::OperationError("couldn't create socket".to_owned()))
}

async fn run<'a>(
Expand Down Expand Up @@ -504,6 +463,28 @@ impl driver::API for Instance {
#[cfg(test)]
mod tests {
use super::*;
use drmem_api::{driver::DriverConfig, Result};

// Helper function to build a config from a string view.

fn mk_cfg(text: &str) -> Result<InstanceConfig> {
Into::<DriverConfig>::into(
toml::from_str::<toml::value::Table>(text)
.map_err(|e| Error::ConfigError(format!("{}", e)))?,
)
.parse_into()
}

#[test]
fn test_config() {
assert!(mk_cfg("addr = 5").is_err());
assert!(mk_cfg("addr = true").is_err());
assert!(mk_cfg("addr = \"hello\"").is_err());

let cfg = mk_cfg("addr = \"192.168.1.100:50\"").unwrap();

assert_eq!(cfg.addr, SocketAddrV4::new([192, 168, 1, 100].into(), 50));
}

#[test]
fn test_decoding() {
Expand Down
4 changes: 4 additions & 0 deletions drivers/drmem-drv-sump/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ keywords = ["control-system", "automation"]
doctest = false

[dependencies]
serde.workspace = true
serde.default-features = false
serde.features = ["derive"]

socket2.version = "0.5"
socket2.default-features = false

Expand Down
Loading