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);