use crate::ha::HARole;
use crate::ha::Result;
use crate::pubsub;
use core::sync::atomic::{AtomicU8, Ordering};
#[cfg(feature = "log")]
use crate::log::{debug, error};
const ROLE_CHANGE_TOPIC: u16 = 4;
static mut ROLE_CHANGE_CALLBACK: Option<fn(HARole) -> bool> = None;
fn handle_role_change(topic_id: u16, data: &[u8]) -> bool {
if topic_id != ROLE_CHANGE_TOPIC {
return false;
}
if data.is_empty() {
return false;
}
let role = match data[0] {
0 => HARole::Master,
1 => HARole::Slave,
2 => HARole::Auto,
_ => HARole::Auto,
};
#[cfg(feature = "log")]
debug!("Role change notification received: {:?}", role);
unsafe {
if let Some(callback) = ROLE_CHANGE_CALLBACK {
callback(role)
} else {
true
}
}
}
pub struct RoleManager {
current_role: AtomicU8,
lock: u32,
is_initialized: bool,
}
impl RoleManager {
pub fn new(initial_role: HARole) -> Result<Self> {
Ok(Self {
current_role: AtomicU8::new(initial_role as u8),
lock: 0,
is_initialized: false,
})
}
pub fn init(&self) -> Result<()> {
self.init_pubsub()?;
self.subscribe_to_role_changes()?;
Ok(())
}
fn init_pubsub(&self) -> Result<()> {
#[cfg(feature = "log")]
debug!("Role manager using existing pubsub system");
Ok(())
}
fn subscribe_to_role_changes(&self) -> Result<()> {
match pubsub::subscribe(ROLE_CHANGE_TOPIC, handle_role_change) {
Ok(_) => {
#[cfg(feature = "log")]
debug!("Successfully subscribed to role change notifications");
Ok(())
}
Err(e) => {
#[cfg(feature = "log")]
error!("Failed to subscribe to role change notifications: {:?}", e);
Ok(())
}
}
}
pub fn get_role(&self) -> HARole {
match self.current_role.load(Ordering::Relaxed) {
0 => HARole::Master,
1 => HARole::Slave,
2 => HARole::Auto,
_ => HARole::Auto, }
}
pub fn set_role(&self, role: HARole) -> Result<()> {
let current_role = self.get_role();
if current_role == role {
return Ok(());
}
#[cfg(feature = "log")]
debug!("Role changing from {:?} to {:?}", current_role, role);
self.current_role.store(role as u8, Ordering::Relaxed);
self.publish_role_change(role)?;
Ok(())
}
fn publish_role_change(&self, role: HARole) -> Result<()> {
let role_data = [role as u8; 1];
match pubsub::publish(ROLE_CHANGE_TOPIC, &role_data) {
Ok(_) => {
#[cfg(feature = "log")]
debug!("Role change notification published: {:?}", role);
Ok(())
}
Err(e) => {
#[cfg(feature = "log")]
error!("Failed to publish role change notification: {:?}", e);
Ok(())
}
}
}
pub fn subscribe_role_change(&self, callback: fn(HARole) -> bool) -> Result<()> {
unsafe {
ROLE_CHANGE_CALLBACK = Some(callback);
}
Ok(())
}
pub fn shutdown(&self) -> Result<()> {
#[cfg(feature = "log")]
debug!("Role manager shutdown");
Ok(())
}
}