Created comprehensive VPN setup tooling for Peaceful Spirit L2TP/IPsec connection and enhanced agent documentation framework. VPN Configuration (PST-NW-VPN): - Setup-PST-L2TP-VPN.ps1: Automated L2TP/IPsec setup with split-tunnel and DNS - Connect-PST-VPN.ps1: Connection helper with PPP adapter detection, DNS (192.168.0.2), and route config (192.168.0.0/24) - Connect-PST-VPN-Standalone.ps1: Self-contained connection script for remote deployment - Fix-PST-VPN-Auth.ps1: Authentication troubleshooting for CHAP/MSChapv2 - Diagnose-VPN-Interface.ps1: Comprehensive VPN interface and routing diagnostic - Quick-Test-VPN.ps1: Fast connectivity verification (DNS/router/routes) - Add-PST-VPN-Route-Manual.ps1: Manual route configuration helper - vpn-connect.bat, vpn-disconnect.bat: Simple batch file shortcuts - OpenVPN config files (Windows-compatible, abandoned for L2TP) Key VPN Implementation Details: - L2TP creates PPP adapter with connection name as interface description - UniFi auto-configures DNS (192.168.0.2) but requires manual route to 192.168.0.0/24 - Split-tunnel enabled (only remote traffic through VPN) - All-user connection for pre-login auto-connect via scheduled task - Authentication: CHAP + MSChapv2 for UniFi compatibility Agent Documentation: - AGENT_QUICK_REFERENCE.md: Quick reference for all specialized agents - documentation-squire.md: Documentation and task management specialist agent - Updated all agent markdown files with standardized formatting Project Organization: - Moved conversation logs to dedicated directories (guru-connect-conversation-logs, guru-rmm-conversation-logs) - Cleaned up old session JSONL files from projects/msp-tools/ - Added guru-connect infrastructure (agent, dashboard, proto, scripts, .gitea workflows) - Added guru-rmm server components and deployment configs Technical Notes: - VPN IP pool: 192.168.4.x (client gets 192.168.4.6) - Remote network: 192.168.0.0/24 (router at 192.168.0.10) - PSK: rrClvnmUeXEFo90Ol+z7tfsAZHeSK6w7 - Credentials: pst-admin / 24Hearts$ Files: 15 VPN scripts, 2 agent docs, conversation log reorganization, guru-connect/guru-rmm infrastructure additions Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
173 lines
4.7 KiB
Rust
173 lines
4.7 KiB
Rust
//! Chat window for the agent
|
|
//!
|
|
//! Provides a simple chat interface for communication between
|
|
//! the technician and the end user.
|
|
|
|
use std::sync::mpsc::{self, Receiver, Sender};
|
|
use std::sync::{Arc, Mutex};
|
|
use std::thread;
|
|
use tracing::{info, warn, error};
|
|
|
|
#[cfg(windows)]
|
|
use windows::Win32::UI::WindowsAndMessaging::*;
|
|
#[cfg(windows)]
|
|
use windows::Win32::Foundation::*;
|
|
#[cfg(windows)]
|
|
use windows::Win32::Graphics::Gdi::*;
|
|
#[cfg(windows)]
|
|
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
|
|
#[cfg(windows)]
|
|
use windows::core::PCWSTR;
|
|
|
|
/// A chat message
|
|
#[derive(Debug, Clone)]
|
|
pub struct ChatMessage {
|
|
pub id: String,
|
|
pub sender: String,
|
|
pub content: String,
|
|
pub timestamp: i64,
|
|
}
|
|
|
|
/// Commands that can be sent to the chat window
|
|
#[derive(Debug)]
|
|
pub enum ChatCommand {
|
|
Show,
|
|
Hide,
|
|
AddMessage(ChatMessage),
|
|
Close,
|
|
}
|
|
|
|
/// Controller for the chat window
|
|
pub struct ChatController {
|
|
command_tx: Sender<ChatCommand>,
|
|
message_rx: Arc<Mutex<Receiver<ChatMessage>>>,
|
|
_handle: thread::JoinHandle<()>,
|
|
}
|
|
|
|
impl ChatController {
|
|
/// Create a new chat controller (spawns chat window thread)
|
|
#[cfg(windows)]
|
|
pub fn new() -> Option<Self> {
|
|
let (command_tx, command_rx) = mpsc::channel::<ChatCommand>();
|
|
let (message_tx, message_rx) = mpsc::channel::<ChatMessage>();
|
|
|
|
let handle = thread::spawn(move || {
|
|
run_chat_window(command_rx, message_tx);
|
|
});
|
|
|
|
Some(Self {
|
|
command_tx,
|
|
message_rx: Arc::new(Mutex::new(message_rx)),
|
|
_handle: handle,
|
|
})
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
pub fn new() -> Option<Self> {
|
|
warn!("Chat window not supported on this platform");
|
|
None
|
|
}
|
|
|
|
/// Show the chat window
|
|
pub fn show(&self) {
|
|
let _ = self.command_tx.send(ChatCommand::Show);
|
|
}
|
|
|
|
/// Hide the chat window
|
|
pub fn hide(&self) {
|
|
let _ = self.command_tx.send(ChatCommand::Hide);
|
|
}
|
|
|
|
/// Add a message to the chat window
|
|
pub fn add_message(&self, msg: ChatMessage) {
|
|
let _ = self.command_tx.send(ChatCommand::AddMessage(msg));
|
|
}
|
|
|
|
/// Check for outgoing messages from the user
|
|
pub fn poll_outgoing(&self) -> Option<ChatMessage> {
|
|
if let Ok(rx) = self.message_rx.lock() {
|
|
rx.try_recv().ok()
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Close the chat window
|
|
pub fn close(&self) {
|
|
let _ = self.command_tx.send(ChatCommand::Close);
|
|
}
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
fn run_chat_window(command_rx: Receiver<ChatCommand>, message_tx: Sender<ChatMessage>) {
|
|
use std::ffi::OsStr;
|
|
use std::os::windows::ffi::OsStrExt;
|
|
|
|
info!("Starting chat window thread");
|
|
|
|
// For now, we'll use a simple message box approach
|
|
// A full implementation would create a proper window with a text input
|
|
|
|
// Process commands
|
|
loop {
|
|
match command_rx.recv() {
|
|
Ok(ChatCommand::Show) => {
|
|
info!("Chat window: Show requested");
|
|
// Show a simple notification that chat is available
|
|
}
|
|
Ok(ChatCommand::Hide) => {
|
|
info!("Chat window: Hide requested");
|
|
}
|
|
Ok(ChatCommand::AddMessage(msg)) => {
|
|
info!("Chat message received: {} - {}", msg.sender, msg.content);
|
|
|
|
// Show the message to the user via a message box (simple implementation)
|
|
let title = format!("Message from {}", msg.sender);
|
|
let content = msg.content.clone();
|
|
|
|
// Spawn a thread to show the message box (non-blocking)
|
|
thread::spawn(move || {
|
|
show_message_box_internal(&title, &content);
|
|
});
|
|
}
|
|
Ok(ChatCommand::Close) => {
|
|
info!("Chat window: Close requested");
|
|
break;
|
|
}
|
|
Err(_) => {
|
|
// Channel closed
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
fn show_message_box_internal(title: &str, message: &str) {
|
|
use std::ffi::OsStr;
|
|
use std::os::windows::ffi::OsStrExt;
|
|
|
|
let title_wide: Vec<u16> = OsStr::new(title)
|
|
.encode_wide()
|
|
.chain(std::iter::once(0))
|
|
.collect();
|
|
let message_wide: Vec<u16> = OsStr::new(message)
|
|
.encode_wide()
|
|
.chain(std::iter::once(0))
|
|
.collect();
|
|
|
|
unsafe {
|
|
MessageBoxW(
|
|
None,
|
|
PCWSTR(message_wide.as_ptr()),
|
|
PCWSTR(title_wide.as_ptr()),
|
|
MB_OK | MB_ICONINFORMATION | MB_TOPMOST | MB_SETFOREGROUND,
|
|
);
|
|
}
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
fn run_chat_window(_command_rx: Receiver<ChatCommand>, _message_tx: Sender<ChatMessage>) {
|
|
// No-op on non-Windows
|
|
}
|