mirror of
https://github.com/Xevion/smart-rgb.git
synced 2025-12-06 11:16:29 -06:00
Finish basic profile loading logic
This commit is contained in:
@@ -5,6 +5,12 @@ edition = "2021"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = "z"
|
||||||
|
strip = true
|
||||||
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
# smart-rgb
|
# smart-rgb
|
||||||
|
|
||||||
A personal script solution to ensure my computer's RGB lights go off when I need them to be.
|
A personal solution to ensure my computer's RGB lights go off when I need them to be.
|
||||||
|
|
||||||
- Off
|
- Off
|
||||||
- After idling during the day for more than 3 hours.
|
- After idling during the day for more than 3 hours.
|
||||||
- After idling at night (past 11PM) for more than 25 minutes.
|
- After idling at night (past 11PM) for more than 25 minutes.
|
||||||
|
- Immediately once locked from 1:30 AM to 8:00 AM.
|
||||||
- Immediately once put into 'sleep' mode.
|
- Immediately once put into 'sleep' mode.
|
||||||
- On
|
- On
|
||||||
- Upon unlock.
|
- Upon unlock.
|
||||||
|
|||||||
116
src/main.rs
116
src/main.rs
@@ -1,7 +1,8 @@
|
|||||||
use std::ffi::OsString;
|
use std::{ffi::OsString};
|
||||||
|
|
||||||
use log::{info, debug};
|
use log::{info, debug};
|
||||||
use log4rs::Handle;
|
use log4rs::Handle;
|
||||||
|
use openrgb::OpenRGB;
|
||||||
use windows_service::{
|
use windows_service::{
|
||||||
service::{ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceType},
|
service::{ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceType},
|
||||||
service_control_handler::{self, ServiceControlHandlerResult},
|
service_control_handler::{self, ServiceControlHandlerResult},
|
||||||
@@ -9,36 +10,56 @@ use windows_service::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::{runtime::Runtime, sync::mpsc};
|
use tokio::{net::TcpStream, runtime::Runtime, sync::mpsc};
|
||||||
|
|
||||||
use tokio::sync::mpsc::UnboundedReceiver;
|
use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
use windows_service::{define_windows_service, service_dispatcher};
|
use windows_service::{define_windows_service, service_dispatcher};
|
||||||
|
|
||||||
const SERVICE_NAME: &str = "Easy RGB - Background Scheduler";
|
const SERVICE_NAME: &str = "RGBXevion";
|
||||||
const SERVICE_DESCRIPTION: &str = "Service to apply rules to background processes";
|
const SERVICE_DESCRIPTION: &str = "Custom service to toggle RGB lights based on lock/sleep events";
|
||||||
|
|
||||||
|
const PROFILE_ENABLE_NAME: &str = "On";
|
||||||
|
const PROFILE_DISABLE_NAME: &str = "Off";
|
||||||
|
|
||||||
define_windows_service!(ffi_service_main, service_main);
|
define_windows_service!(ffi_service_main, service_main);
|
||||||
|
|
||||||
pub(crate) async fn rule_applier(
|
pub async fn try_load_profile(client: &OpenRGB<TcpStream>, profile_name: &str) -> anyhow::Result<()> {
|
||||||
rule_file_path: &str,
|
let profiles = client.get_profiles().await?;
|
||||||
|
|
||||||
|
let profile_available: bool = profiles.iter().any(|profile| profile == profile_name);
|
||||||
|
if !profile_available {
|
||||||
|
info!("Profile not found: {}", profile_name);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
client.load_profile(profile_name).await?;
|
||||||
|
info!("Profile set to: {}", profile_name);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn profile_applier(
|
||||||
|
profile_recv: &mut UnboundedReceiver<bool>,
|
||||||
shutdown_recv: &mut UnboundedReceiver<()>,
|
shutdown_recv: &mut UnboundedReceiver<()>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// let wmi_con = WMIConnection::new(COMLibrary::new()?)?;
|
|
||||||
|
|
||||||
// Apply rules to all running processes
|
let client = OpenRGB::connect().await?;
|
||||||
// let running_process: Vec<WinProcess> = wmi_con.async_query().await?;
|
client.set_name(format!("{} v{}", SERVICE_NAME, env!("CARGO_PKG_VERSION"))).await?;
|
||||||
// running_process.into_iter().for_each(|process| {
|
|
||||||
// let process_info: ProcessInfo = process.into();
|
|
||||||
// rule_set.apply(&process_info)
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
// Apply rules to new processes
|
enable = profile_recv.recv() => {
|
||||||
// output = monitor_new_processes(&rule_set, &wmi_con) => output,
|
debug!("Received profile command: {:?}", enable);
|
||||||
// Or wait for shutdown signal
|
if enable.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_load_profile(&client, if enable.unwrap() { PROFILE_ENABLE_NAME } else { PROFILE_DISABLE_NAME }).await?;
|
||||||
|
}
|
||||||
_ = shutdown_recv.recv() => {
|
_ = shutdown_recv.recv() => {
|
||||||
info!("Shutting down process monitor");
|
info!("Service shutting down");
|
||||||
Ok(())
|
return Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,32 +67,47 @@ pub(crate) async fn rule_applier(
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn service_main(_: Vec<OsString>) {
|
fn service_main(_: Vec<OsString>) {
|
||||||
use windows_service::service::{
|
use windows_service::service::{
|
||||||
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
|
PowerEventParam, ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, SessionChangeReason
|
||||||
SessionChangeReason,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let rt = Runtime::new().unwrap();
|
let rt = Runtime::new().unwrap();
|
||||||
|
|
||||||
let (shutdown_send, mut shutdown_recv) = mpsc::unbounded_channel();
|
let (shutdown_send, mut shutdown_recv) = mpsc::unbounded_channel();
|
||||||
|
let (profile_send, mut profile_recv) = mpsc::unbounded_channel::<bool>();
|
||||||
|
|
||||||
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
||||||
match control_event {
|
match control_event {
|
||||||
ServiceControl::SessionChange(session) => {
|
ServiceControl::PowerEvent(event) =>
|
||||||
info!(
|
{
|
||||||
"Session Changed: {}",
|
debug!("Power event: {:?}", event);
|
||||||
match session.reason {
|
match event {
|
||||||
SessionChangeReason::ConsoleConnect => "Console Connect",
|
PowerEventParam::QuerySuspend => {
|
||||||
SessionChangeReason::ConsoleDisconnect => "Console Disconnect",
|
// Send false to disable RGB
|
||||||
SessionChangeReason::RemoteConnect => "Remote Connect",
|
profile_send.send(false).unwrap();
|
||||||
SessionChangeReason::RemoteDisconnect => "Remote Disconnect",
|
}
|
||||||
SessionChangeReason::SessionLogon => "Session Logon",
|
PowerEventParam::ResumeSuspend | PowerEventParam::QuerySuspendFailed => {
|
||||||
SessionChangeReason::SessionLogoff => "Session Logoff",
|
// Send true to enable RGB
|
||||||
SessionChangeReason::SessionLock => "Session Lock",
|
profile_send.send(true).unwrap();
|
||||||
SessionChangeReason::SessionUnlock => "Session Unlock",
|
}
|
||||||
SessionChangeReason::SessionRemoteControl => "Session Remote Control",
|
_ => {}
|
||||||
SessionChangeReason::SessionCreate => "Session Create",
|
}
|
||||||
SessionChangeReason::SessionTerminate => "Session Terminate",
|
|
||||||
|
ServiceControlHandlerResult::NoError
|
||||||
|
}
|
||||||
|
ServiceControl::SessionChange(change) => {
|
||||||
|
debug!("Session change: {:?}", change);
|
||||||
|
|
||||||
|
match change.reason {
|
||||||
|
SessionChangeReason::SessionLock => {
|
||||||
|
// Send false to disable RGB
|
||||||
|
profile_send.send(false).unwrap();
|
||||||
|
}
|
||||||
|
SessionChangeReason::SessionUnlock => {
|
||||||
|
// Send true to enable RGB
|
||||||
|
profile_send.send(true).unwrap();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
ServiceControlHandlerResult::NoError
|
ServiceControlHandlerResult::NoError
|
||||||
}
|
}
|
||||||
@@ -89,7 +125,7 @@ fn service_main(_: Vec<OsString>) {
|
|||||||
.set_service_status(ServiceStatus {
|
.set_service_status(ServiceStatus {
|
||||||
service_type: ServiceType::OWN_PROCESS,
|
service_type: ServiceType::OWN_PROCESS,
|
||||||
current_state: ServiceState::Running,
|
current_state: ServiceState::Running,
|
||||||
controls_accepted: ServiceControlAccept::STOP | ServiceControlAccept::SESSION_CHANGE,
|
controls_accepted: ServiceControlAccept::STOP | ServiceControlAccept::SESSION_CHANGE | ServiceControlAccept::POWER_EVENT,
|
||||||
exit_code: ServiceExitCode::Win32(0),
|
exit_code: ServiceExitCode::Win32(0),
|
||||||
checkpoint: 0,
|
checkpoint: 0,
|
||||||
wait_hint: Duration::default(),
|
wait_hint: Duration::default(),
|
||||||
@@ -101,7 +137,7 @@ fn service_main(_: Vec<OsString>) {
|
|||||||
let rules_path = args.get(2).map(|s| s.as_str()).unwrap_or("rules.json");
|
let rules_path = args.get(2).map(|s| s.as_str()).unwrap_or("rules.json");
|
||||||
|
|
||||||
let error_code = if rt
|
let error_code = if rt
|
||||||
.block_on(rule_applier(rules_path, &mut shutdown_recv))
|
.block_on(profile_applier(&mut profile_recv, &mut shutdown_recv))
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
1
|
1
|
||||||
@@ -170,7 +206,7 @@ fn main() -> anyhow::Result<(), windows_service::Error> {
|
|||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
match command.as_str() {
|
match command.as_str() {
|
||||||
"install" => {
|
"install" => {
|
||||||
install_service(args.get(2).map(|s| s.as_str()))?;
|
install_service()?;
|
||||||
info!("Service installed");
|
info!("Service installed");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -200,7 +236,7 @@ fn main() -> anyhow::Result<(), windows_service::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn install_service(rules_path: Option<&str>) -> windows_service::Result<()> {
|
fn install_service() -> windows_service::Result<()> {
|
||||||
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
||||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||||
let service_binary_path = ::std::env::current_exe().unwrap();
|
let service_binary_path = ::std::env::current_exe().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user