boxmux_lib/socket_loop.rs
1use crate::thread_manager::Runnable;
2use crate::{AppContext, FieldUpdate};
3use crate::model::common::{run_socket_function, SocketFunction};
4use std::fs;
5use std::io::{Read, Write};
6use std::os::unix::net::UnixListener;
7use std::sync::mpsc;
8
9use crate::thread_manager::*;
10
11use uuid::Uuid;
12
13create_runnable!(
14 SocketLoop,
15 |_inner: &mut RunnableImpl, _app_context: AppContext, _messages: Vec<Message>| -> bool { true },
16 |inner: &mut RunnableImpl,
17 app_context: AppContext,
18 _messages: Vec<Message>|
19 -> (bool, AppContext) {
20 let socket_path = "/tmp/boxmux.sock";
21 // Remove the stale socket file if it exists
22 if std::path::Path::new(socket_path).exists() {
23 let _ = fs::remove_file(socket_path);
24 }
25
26 let listener = match UnixListener::bind(socket_path) {
27 Ok(listener) => {
28 log::info!("Listening on socket: {}", socket_path);
29 listener
30 }
31 Err(err) => {
32 log::error!("Failed to bind to socket {}: {}", socket_path, err);
33 return (false, app_context);
34 }
35 };
36
37 for stream in listener.incoming() {
38 match stream {
39 Ok(mut stream) => {
40 let mut buffer = String::new();
41 match stream.read_to_string(&mut buffer) {
42 Ok(_size) => {
43 let trimmed_message = buffer.trim();
44 log::debug!("Received socket message: {}", trimmed_message);
45
46 // Parse JSON message as SocketFunction and execute directly
47 if !trimmed_message.is_empty() {
48 match serde_json::from_str::<SocketFunction>(trimmed_message) {
49 Ok(socket_function) => {
50 log::debug!("Parsed socket function: {:?}", socket_function);
51
52 // Execute socket function and send resulting messages
53 match run_socket_function(socket_function, &app_context) {
54 Ok((updated_context, messages)) => {
55 // Update app_context if it was modified
56 // Note: app_context is typically not modified by socket functions
57 // but we maintain the pattern for consistency
58
59 // Send all resulting messages to the thread manager
60 for message in messages {
61 inner.send_message(message);
62 }
63
64 // Send success acknowledgment
65 if let Err(err) = stream.write_all(b"Socket function executed successfully.") {
66 log::error!("Error sending success response: {}", err);
67 }
68 }
69 Err(err) => {
70 let error_msg = format!("Socket function execution failed: {}", err);
71 log::error!("{}", error_msg);
72
73 // Send error response to client
74 if let Err(write_err) = stream.write_all(error_msg.as_bytes()) {
75 log::error!("Error sending error response: {}", write_err);
76 }
77 }
78 }
79 }
80 Err(parse_err) => {
81 let error_msg = format!("Invalid socket function JSON: {}", parse_err);
82 log::error!("{}", error_msg);
83
84 // Send parse error response to client
85 if let Err(write_err) = stream.write_all(error_msg.as_bytes()) {
86 log::error!("Error sending parse error response: {}", write_err);
87 }
88 }
89 }
90 }
91 }
92 Err(err) => {
93 log::error!("Error receiving message: {}", err);
94 }
95 }
96 }
97 Err(err) => {
98 log::error!("Error accepting connection: {}", err);
99 }
100 }
101 }
102
103 (true, app_context)
104 }
105);