Add native self-hosted instance connection to fluxer_desktop

Trimmed monorepo checkout (fluxer_desktop + packages/voice_engine_v2 +
tools/ci) with a "Connect to a Different Server" menu item and popout
that lets the desktop app switch to any self-hosted Fluxer instance,
plus fixes for well-known discovery on single-domain self-hosted
deployments and a false-positive ERR_ABORTED on same-origin client
redirects during the switch. Defaults to chat.fluxr.chat and uses an
isolated userData directory from the official build.
This commit is contained in:
2026-07-01 18:22:43 -04:00
commit 682afacd30
1763 changed files with 613720 additions and 0 deletions
@@ -0,0 +1,156 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "d3d9-present-fixture"
version = "0.0.0"
dependencies = [
"windows",
"windows-core",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "windows"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
dependencies = [
"windows-core",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-numerics"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
dependencies = [
"windows-core",
"windows-link",
]
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-threading"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
dependencies = [
"windows-link",
]
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
[package]
name = "d3d9-present-fixture"
version = "0.0.0"
edition = "2024"
license = "AGPL-3.0-or-later"
publish = false
# Empty workspace table keeps this fixture out of any parent Cargo workspace,
# matching the sibling crates (hook/, vulkan-layer/) in this package.
[workspace]
resolver = "2"
[[bin]]
name = "d3d9-present-fixture"
path = "src/main.rs"
[target.'cfg(target_os = "windows")'.dependencies]
windows = {version = "0.62.2", features = [
"Win32_Foundation",
"Win32_Graphics_Direct3D9",
"Win32_Graphics_Gdi",
"Win32_System_LibraryLoader",
"Win32_UI_WindowsAndMessaging",
]}
windows-core = "0.62.2"
@@ -0,0 +1,417 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#[cfg(not(windows))]
fn main() {
eprintln!("d3d9-present-fixture is only functional on Windows");
}
#[cfg(windows)]
fn main() -> windows_core::Result<()> {
windows_impl::run()
}
#[cfg_attr(not(windows), allow(dead_code))]
mod pattern {
pub const BARS: [(u8, u8, u8); 8] = [
(255, 255, 255),
(255, 255, 0),
(0, 255, 255),
(0, 255, 0),
(255, 0, 255),
(255, 0, 0),
(0, 0, 255),
(0, 0, 0),
];
pub const COUNTER_BLOCK: u32 = 16;
pub fn bar_colour(x: u32, width: u32) -> (u8, u8, u8) {
let width = width.max(1);
let index = ((x as u64 * BARS.len() as u64) / width as u64) as usize;
BARS[index.min(BARS.len() - 1)]
}
pub fn counter_colour(frame_index: u64) -> (u8, u8, u8) {
let low = (frame_index & 0x00FF_FFFF) as u32;
(
(low & 0xFF) as u8,
((low >> 8) & 0xFF) as u8,
((low >> 16) & 0xFF) as u8,
)
}
}
#[cfg(windows)]
mod cli {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PresentMode {
Device,
SwapChain,
}
pub struct Options {
pub frames: Option<u64>,
pub width: u32,
pub height: u32,
pub borderless: bool,
pub multisample: bool,
pub present_mode: PresentMode,
}
impl Default for Options {
fn default() -> Self {
Self {
frames: None,
width: 1280,
height: 720,
borderless: false,
multisample: false,
present_mode: PresentMode::Device,
}
}
}
impl Options {
pub fn from_env() -> Self {
let mut options = Options::default();
let mut args = std::env::args().skip(1);
while let Some(arg) = args.next() {
match arg.as_str() {
"--frames" => {
if let Some(value) = args.next().and_then(|v| v.parse().ok()) {
options.frames = Some(value);
}
}
"--width" => {
if let Some(value) = args.next().and_then(|v| v.parse().ok()) {
options.width = value;
}
}
"--height" => {
if let Some(value) = args.next().and_then(|v| v.parse().ok()) {
options.height = value;
}
}
"--borderless" => options.borderless = true,
"--windowed" => options.borderless = false,
"--multisample" => options.multisample = true,
"--no-multisample" => options.multisample = false,
"--swapchain-present" => options.present_mode = PresentMode::SwapChain,
"--device-present" => options.present_mode = PresentMode::Device,
_ => {}
}
}
options
}
}
}
#[cfg(windows)]
mod windows_impl {
use super::{
cli::{Options, PresentMode},
pattern,
};
use std::ptr::null;
use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM};
use windows::Win32::Graphics::Direct3D9::{
D3D_SDK_VERSION, D3DADAPTER_DEFAULT, D3DCLEAR_TARGET, D3DCREATE_HARDWARE_VERTEXPROCESSING,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
D3DMULTISAMPLE_2_SAMPLES, D3DMULTISAMPLE_NONE, D3DPRESENT_PARAMETERS, D3DRECT,
D3DSWAPEFFECT_DISCARD, Direct3DCreate9, IDirect3D9, IDirect3DDevice9,
};
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::UI::WindowsAndMessaging::{
CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, CreateWindowExW, DefWindowProcW, DispatchMessageW,
GetClientRect, MSG, PM_REMOVE, PeekMessageW, PostQuitMessage, RegisterClassExW, SW_SHOW,
ShowWindow, TranslateMessage, WM_DESTROY, WM_QUIT, WNDCLASSEXW, WS_OVERLAPPEDWINDOW,
WS_POPUP, WS_VISIBLE,
};
use windows_core::{BOOL, Result, w};
const D3DERR_DEVICELOST: i32 = 0x8876_0868u32 as i32;
fn d3dcolor_xrgb(r: u8, g: u8, b: u8) -> u32 {
0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}
extern "system" fn wnd_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
unsafe {
match msg {
WM_DESTROY => {
PostQuitMessage(0);
LRESULT(0)
}
_ => DefWindowProcW(hwnd, msg, wparam, lparam),
}
}
}
unsafe fn create_window(width: u32, height: u32, borderless: bool) -> Result<HWND> {
unsafe {
let instance = GetModuleHandleW(None)?;
let class_name = w!("FluxerD3D9Fixture");
let wc = WNDCLASSEXW {
cbSize: size_of::<WNDCLASSEXW>() as u32,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wnd_proc),
hInstance: instance.into(),
lpszClassName: class_name,
..Default::default()
};
RegisterClassExW(&wc);
let style = if borderless {
WS_POPUP | WS_VISIBLE
} else {
WS_OVERLAPPEDWINDOW | WS_VISIBLE
};
let hwnd = CreateWindowExW(
Default::default(),
class_name,
w!("Fluxer D3D9 Present Fixture"),
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
width as i32,
height as i32,
None,
None,
Some(instance.into()),
None,
)?;
let _ = ShowWindow(hwnd, SW_SHOW);
Ok(hwnd)
}
}
fn present_params(
hwnd: HWND,
width: u32,
height: u32,
multisample: bool,
) -> D3DPRESENT_PARAMETERS {
D3DPRESENT_PARAMETERS {
BackBufferWidth: width,
BackBufferHeight: height,
BackBufferFormat: D3DFMT_X8R8G8B8,
BackBufferCount: 1,
MultiSampleType: if multisample {
D3DMULTISAMPLE_2_SAMPLES
} else {
D3DMULTISAMPLE_NONE
},
MultiSampleQuality: 0,
SwapEffect: D3DSWAPEFFECT_DISCARD,
hDeviceWindow: hwnd,
Windowed: BOOL(1),
EnableAutoDepthStencil: BOOL(0),
..Default::default()
}
}
struct Renderer {
_d3d9: IDirect3D9,
device: IDirect3DDevice9,
hwnd: HWND,
width: u32,
height: u32,
device_lost: bool,
multisample: bool,
present_mode: PresentMode,
}
impl Renderer {
unsafe fn new(
hwnd: HWND,
width: u32,
height: u32,
multisample: bool,
present_mode: PresentMode,
) -> Result<Self> {
unsafe {
let d3d9 = Direct3DCreate9(D3D_SDK_VERSION)
.ok_or_else(|| windows_core::Error::from_thread())?;
let mut params = present_params(hwnd, width, height, multisample);
let mut device: Option<IDirect3DDevice9> = None;
let mut created = d3d9
.CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING as u32,
&mut params,
&mut device,
)
.is_ok();
if !created {
created = d3d9
.CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING as u32,
&mut params,
&mut device,
)
.is_ok();
}
let device = if created {
device.ok_or_else(|| windows_core::Error::from_thread())?
} else {
return Err(windows_core::Error::from_thread());
};
Ok(Self {
_d3d9: d3d9,
device,
hwnd,
width,
height,
device_lost: false,
multisample,
present_mode,
})
}
}
unsafe fn try_reset(&mut self) {
unsafe {
let mut params =
present_params(self.hwnd, self.width, self.height, self.multisample);
if self.device.Reset(&mut params).is_ok() {
self.device_lost = false;
}
}
}
unsafe fn render_frame(&mut self, frame_index: u64) -> Result<()> {
unsafe {
if self.device_lost {
self.try_reset();
if self.device_lost {
return self.present();
}
}
let width = self.width.max(1);
let height = self.height as i32;
let bars = pattern::BARS.len() as u32;
for bar in 0..bars {
let x1 = ((bar as u64 * width as u64) / bars as u64) as i32;
let x2 = (((bar + 1) as u64 * width as u64) / bars as u64) as i32;
if x2 <= x1 {
continue;
}
let mid = ((x1 + x2) / 2).max(0) as u32;
let (r, g, b) = pattern::bar_colour(mid, width);
let rect = D3DRECT {
x1,
y1: 0,
x2,
y2: height,
};
self.device.Clear(
1,
&rect,
D3DCLEAR_TARGET as u32,
d3dcolor_xrgb(r, g, b),
1.0,
0,
)?;
}
let block = pattern::COUNTER_BLOCK as i32;
let block_x2 = block.min(width as i32);
let block_y2 = block.min(height);
if block_x2 > 0 && block_y2 > 0 {
let (r, g, b) = pattern::counter_colour(frame_index);
let rect = D3DRECT {
x1: 0,
y1: 0,
x2: block_x2,
y2: block_y2,
};
self.device.Clear(
1,
&rect,
D3DCLEAR_TARGET as u32,
d3dcolor_xrgb(r, g, b),
1.0,
0,
)?;
}
self.present()
}
}
unsafe fn present(&mut self) -> Result<()> {
unsafe {
let result = match self.present_mode {
PresentMode::Device => {
self.device.Present(null(), null(), HWND::default(), null())
}
PresentMode::SwapChain => self.device.GetSwapChain(0).and_then(|swap_chain| {
swap_chain.Present(null(), null(), HWND::default(), null(), 0)
}),
};
match result {
Ok(()) => Ok(()),
Err(err) if err.code().0 == D3DERR_DEVICELOST => {
self.device_lost = true;
Ok(())
}
Err(err) => Err(err),
}
}
}
}
pub fn run() -> Result<()> {
let options = Options::from_env();
unsafe {
let hwnd = create_window(options.width, options.height, options.borderless)?;
let mut rect = Default::default();
let _ = GetClientRect(hwnd, &mut rect);
let width = ((rect.right - rect.left).max(1)) as u32;
let height = ((rect.bottom - rect.top).max(1)) as u32;
let mut renderer = Renderer::new(
hwnd,
width,
height,
options.multisample,
options.present_mode,
)?;
println!("HWND={}", hwnd.0 as isize);
use std::io::Write;
let _ = std::io::stdout().flush();
let mut frame_index: u64 = 0;
let mut msg = MSG::default();
loop {
while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
if msg.message == WM_QUIT {
return Ok(());
}
let _ = TranslateMessage(&msg);
DispatchMessageW(&msg);
}
renderer.render_frame(frame_index)?;
frame_index += 1;
if let Some(limit) = options.frames {
if frame_index >= limit {
return Ok(());
}
}
}
}
}
}