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>
This commit is contained in:
159
projects/msp-tools/guru-connect/agent/src/capture/display.rs
Normal file
159
projects/msp-tools/guru-connect/agent/src/capture/display.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
//! Display enumeration and information
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// Information about a display/monitor
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Display {
|
||||
/// Unique display ID
|
||||
pub id: u32,
|
||||
|
||||
/// Display name (e.g., "\\\\.\\DISPLAY1")
|
||||
pub name: String,
|
||||
|
||||
/// X position in virtual screen coordinates
|
||||
pub x: i32,
|
||||
|
||||
/// Y position in virtual screen coordinates
|
||||
pub y: i32,
|
||||
|
||||
/// Width in pixels
|
||||
pub width: u32,
|
||||
|
||||
/// Height in pixels
|
||||
pub height: u32,
|
||||
|
||||
/// Whether this is the primary display
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Platform-specific handle (HMONITOR on Windows)
|
||||
#[cfg(windows)]
|
||||
pub handle: isize,
|
||||
}
|
||||
|
||||
/// Display info for protocol messages
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DisplayInfo {
|
||||
pub displays: Vec<Display>,
|
||||
pub primary_id: u32,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
/// Total pixels in the display
|
||||
pub fn pixel_count(&self) -> u32 {
|
||||
self.width * self.height
|
||||
}
|
||||
|
||||
/// Bytes needed for BGRA frame buffer
|
||||
pub fn buffer_size(&self) -> usize {
|
||||
(self.width * self.height * 4) as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerate all connected displays
|
||||
#[cfg(windows)]
|
||||
pub fn enumerate_displays() -> Result<Vec<Display>> {
|
||||
use windows::Win32::Graphics::Gdi::{
|
||||
EnumDisplayMonitors, GetMonitorInfoW, HMONITOR, MONITORINFOEXW,
|
||||
};
|
||||
use windows::Win32::Foundation::{BOOL, LPARAM, RECT};
|
||||
use std::mem;
|
||||
|
||||
let mut displays = Vec::new();
|
||||
let mut display_id = 0u32;
|
||||
|
||||
// Callback for EnumDisplayMonitors
|
||||
unsafe extern "system" fn enum_callback(
|
||||
hmonitor: HMONITOR,
|
||||
_hdc: windows::Win32::Graphics::Gdi::HDC,
|
||||
_rect: *mut RECT,
|
||||
lparam: LPARAM,
|
||||
) -> BOOL {
|
||||
let displays = &mut *(lparam.0 as *mut Vec<(HMONITOR, u32)>);
|
||||
let id = displays.len() as u32;
|
||||
displays.push((hmonitor, id));
|
||||
BOOL(1) // Continue enumeration
|
||||
}
|
||||
|
||||
// Collect all monitor handles
|
||||
let mut monitors: Vec<(windows::Win32::Graphics::Gdi::HMONITOR, u32)> = Vec::new();
|
||||
unsafe {
|
||||
let result = EnumDisplayMonitors(
|
||||
None,
|
||||
None,
|
||||
Some(enum_callback),
|
||||
LPARAM(&mut monitors as *mut _ as isize),
|
||||
);
|
||||
if !result.as_bool() {
|
||||
anyhow::bail!("EnumDisplayMonitors failed");
|
||||
}
|
||||
}
|
||||
|
||||
// Get detailed info for each monitor
|
||||
for (hmonitor, id) in monitors {
|
||||
let mut info: MONITORINFOEXW = unsafe { mem::zeroed() };
|
||||
info.monitorInfo.cbSize = mem::size_of::<MONITORINFOEXW>() as u32;
|
||||
|
||||
unsafe {
|
||||
if GetMonitorInfoW(hmonitor, &mut info.monitorInfo as *mut _ as *mut _).as_bool() {
|
||||
let rect = info.monitorInfo.rcMonitor;
|
||||
let name = String::from_utf16_lossy(
|
||||
&info.szDevice[..info.szDevice.iter().position(|&c| c == 0).unwrap_or(info.szDevice.len())]
|
||||
);
|
||||
|
||||
let is_primary = (info.monitorInfo.dwFlags & 1) != 0; // MONITORINFOF_PRIMARY
|
||||
|
||||
displays.push(Display {
|
||||
id,
|
||||
name,
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
width: (rect.right - rect.left) as u32,
|
||||
height: (rect.bottom - rect.top) as u32,
|
||||
is_primary,
|
||||
handle: hmonitor.0 as isize,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by position (left to right, top to bottom)
|
||||
displays.sort_by(|a, b| {
|
||||
if a.y != b.y {
|
||||
a.y.cmp(&b.y)
|
||||
} else {
|
||||
a.x.cmp(&b.x)
|
||||
}
|
||||
});
|
||||
|
||||
// Reassign IDs after sorting
|
||||
for (i, display) in displays.iter_mut().enumerate() {
|
||||
display.id = i as u32;
|
||||
}
|
||||
|
||||
if displays.is_empty() {
|
||||
anyhow::bail!("No displays found");
|
||||
}
|
||||
|
||||
Ok(displays)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn enumerate_displays() -> Result<Vec<Display>> {
|
||||
anyhow::bail!("Display enumeration only supported on Windows")
|
||||
}
|
||||
|
||||
/// Get display info for protocol
|
||||
pub fn get_display_info() -> Result<DisplayInfo> {
|
||||
let displays = enumerate_displays()?;
|
||||
let primary_id = displays
|
||||
.iter()
|
||||
.find(|d| d.is_primary)
|
||||
.map(|d| d.id)
|
||||
.unwrap_or(0);
|
||||
|
||||
Ok(DisplayInfo {
|
||||
displays,
|
||||
primary_id,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user