Files
claudetools/projects/msp-tools/guru-connect/agent/src/chat/mod.rs
Mike Swanson a602118f6d Add VPN configuration tools and agent documentation
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>
2026-01-18 11:51:47 -07:00

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
}