Add Rust build code instead of Python, add dummy Renderer and "render" using it, add Tab new function, fix tls/tcp enum not working and bunch of other borrowing/owning issues in connection, and remove the thread for html cache parsing

This commit is contained in:
csd4ni3l
2026-02-22 17:14:41 +01:00
parent 0b2e9c12ad
commit 82ecd8cf8f
5 changed files with 142 additions and 88 deletions

3
.cargo/config.toml Normal file
View File

@@ -0,0 +1,3 @@
[target.'cfg(target_os = "linux")']
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]

View File

@@ -11,79 +11,56 @@ jobs:
include:
- os: ubuntu-22.04
platform: linux
python-version: "3.11"
- os: windows-latest
platform: windows
python-version: "3.11"
steps:
- name: Check-out repository
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
- name: Cache
uses: actions/cache@v4
with:
python-version: "3.11"
architecture: "x64"
cache: "pip"
cache-dependency-path: |
**/requirements*.txt
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Dependencies
run: pip install -r requirements.txt
- name: Build Executable
uses: Nuitka/Nuitka-Action@main
with:
nuitka-version: main
script-name: run.py
nofollow-import-to: "*tk*,_codecs,encodings,multiprocessing,gi"
disable-plugins: tk-inter,dill-compat,eventlet,gevent,pyqt5,pyqt6,pyside2,pyside6,delvewheel,pywebview,matplotlib,spacy,enum-compat,pbr-compat,gevent,pmw-freezer,transformers,upx,kivy,options-nanny,multiprocessing,gi
include-data-dir: assets=assets
include-data-files: CREDITS=CREDITS
mode: onefile
output-file: csd4ni3lBrowser
- name: Locate and rename executable (Linux)
- name: Install mold, clang, Wayland, ALSA and x11 headers and dependencies (Linux)
if: matrix.os == 'ubuntu-22.04'
run: |
set -euo pipefail
echo "Searching for built Linux binary..."
# List to help debugging when paths change
ls -laR . | head -n 500 || true
BIN=$(find . -maxdepth 4 -type f -name 'csd4ni3lBrowser*' -perm -u+x | head -n1 || true)
if [ -z "${BIN}" ]; then
echo "ERROR: No Linux binary found after build"
exit 1
fi
echo "Found: ${BIN}"
mkdir -p build_output
cp "${BIN}" build_output/csd4ni3lBrowser.bin
chmod +x build_output/csd4ni3lBrowser.bin
echo "Executable ready: build_output/csd4ni3lBrowser.bin"
sudo apt update
sudo apt install -y build-essential clang cmake pkg-config mold \
libwayland-dev libxkbcommon-dev libegl1-mesa-dev \
libwayland-egl-backend-dev \
libx11-dev libxext-dev libxrandr-dev libxinerama-dev libxcursor-dev \
libxi-dev libxfixes-dev libxrender-dev \
libfreetype6-dev libfontconfig1-dev libgl1-mesa-dev \
libasound2-dev libudev-dev
shell: bash
- name: Locate and rename executable (Windows)
- name: Build
run: cargo build --release --verbose
- name: Verify executable (Linux)
if: matrix.os == 'ubuntu-22.04'
run: test target/release/soundboard
shell: bash
- name: Verify executable (Windows)
if: matrix.os == 'windows-latest'
run: |
Write-Host "Searching for built Windows binary..."
Get-ChildItem -Recurse -File -Filter 'csd4ni3lBrowser*.exe' | Select-Object -First 1 | ForEach-Object {
Write-Host ("Found: " + $_.FullName)
New-Item -ItemType Directory -Force -Path build_output | Out-Null
Copy-Item $_.FullName "build_output\csd4ni3lBrowser.exe"
Write-Host "Executable ready: build_output\csd4ni3lBrowser.exe"
}
if (!(Test-Path build_output\csd4ni3lBrowser.exe)) {
Write-Error "ERROR: No Windows binary found after build"
exit 1
}
run: Test-Path target\release\soundboard.exe
shell: pwsh
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}
path: build_output/csd4ni3lBrowser.*
path: |
target/release/soundboard
target/release/soundboard.exe
release:
runs-on: ubuntu-latest
@@ -114,5 +91,5 @@ jobs:
--notes "Automated build for $TAG"
fi
# Upload the executables directly (no zip files)
gh release upload "$TAG" downloads/linux/csd4ni3lBrowser.bin --clobber
gh release upload "$TAG" downloads/windows/csd4ni3lBrowser.exe --clobber
gh release upload "$TAG" downloads/linux/soundboard --clobber
gh release upload "$TAG" downloads/windows/soundboard.exe --clobber

View File

@@ -1,6 +1,36 @@
use std::{collections::HashMap, net::TcpStream, io::{Read, Write}, fs, thread};
use native_tls::TlsConnector;
use crate::html_parser::{Node, Rule};
use std::{collections::HashMap, net::TcpStream, io::{Read, Write}, fs};
use native_tls::{TlsConnector, TlsStream};
use crate::http_client::html_parser::{Node, Rule};
enum Connection {
Plain(TcpStream),
Tls(TlsStream<TcpStream>),
}
impl Read for Connection {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
Connection::Plain(s) => s.read(buf),
Connection::Tls(s) => s.read(buf),
}
}
}
impl Write for Connection {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match self {
Connection::Plain(s) => s.write(buf),
Connection::Tls(s) => s.write(buf),
}
}
fn flush(&mut self) -> std::io::Result<()> {
match self {
Connection::Plain(s) => s.flush(),
Connection::Tls(s) => s.flush(),
}
}
}
pub fn resolve_url(scheme: &str, host: &str, port: u16, path: &str, mut url: &str) -> String {
if url.contains("://") {
@@ -29,7 +59,6 @@ pub fn resolve_url(scheme: &str, host: &str, port: u16, path: &str, mut url: &st
format!("{}://{}:{}{}", scheme, host, port, resolved_path)
}
}
pub struct HTTPClient {
pub scheme: String,
pub host: String,
@@ -46,16 +75,16 @@ pub struct HTTPClient {
pub view_source: bool,
pub redirect_count: u32,
pub needs_render: bool,
pub tcp_stream: Option<Box<dyn Read + Write>>
pub tcp_stream: Option<Connection>
}
impl HTTPClient {
pub fn new(scheme: String, host: String, path: String, port: u32) -> HTTPClient {
pub fn new() -> HTTPClient {
HTTPClient {
scheme,
host,
path,
port,
scheme: String::new(),
host: String::new(),
path: String::new(),
port: 0,
request_headers: HashMap::new(),
response_explanation: None,
response_headers: HashMap::new(),
@@ -76,9 +105,9 @@ impl HTTPClient {
}
pub fn get_request(&mut self, url: &String, headers: HashMap<String, String>, css: bool) {
let mut parsed_url = url;
let mut parsed_url = url.clone();
if parsed_url.starts_with("view-source:") {
parsed_url = parsed_url.split_once("view-source:")[1];
parsed_url = parsed_url.split_once("view-source:").unwrap().1.to_string();
self.view_source = true;
}
else {
@@ -98,7 +127,8 @@ impl HTTPClient {
}
if self.host.contains(":") {
let (host_str, port_str) = self.host.split_once(":").unwrap();
let temp_host = self.host.clone();
let (host_str, port_str) = temp_host.split_once(":").unwrap();
self.host = host_str.to_string();
self.port = port_str.parse().unwrap();
@@ -121,15 +151,12 @@ impl HTTPClient {
self.tcp_stream = None;
if !self.request_headers.contains_key("Host") {
self.request_headers["Host"] = self.host;
self.request_headers.insert("Host".to_string(), self.host.clone());
}
let cache_filename = format!("{}_{}_{}_{}.html", self.scheme, self.host, self.port, self.path.replace("/", "_"));
if std::fs::exists(format!("html_cache/{}", cache_filename)).unwrap() {
std::thread(move || {
self.parse()
});
self.parse();
return;
}
@@ -137,10 +164,10 @@ impl HTTPClient {
if self.scheme == "https" {
let connector = TlsConnector::new().unwrap();
self.tcp_stream = Some(Box::new(connector.connect(self.host.as_str(), stream).unwrap()));
self.tcp_stream = Some(Connection::Tls(connector.connect(self.host.as_str(), tcp).unwrap()));
}
else {
self.tcp_stream = Some(Box::new(tcp));
self.tcp_stream = Some(Connection::Plain(tcp));
}
}
@@ -179,7 +206,7 @@ impl HTTPClient {
self.response_headers = headers;
}
pub fn parse(self) {
pub fn parse(&mut self) {
}
}

View File

@@ -0,0 +1,37 @@
use crate::http_client::connection::HTTPClient;
use bevy_egui::egui::Ui;
enum Widget {
}
struct DocumentLayout {
}
pub struct Renderer {
content: String,
request_scheme: String,
scroll_y: f64,
scroll_y_speed: f64,
smallest_y: f64,
document: Option<DocumentLayout>,
widgets: Vec<Widget>
}
impl Renderer {
pub fn new() -> Renderer {
Renderer {
content: String::new(),
request_scheme: String::new(),
scroll_y: 0.0,
scroll_y_speed: 50.0,
smallest_y: 0.0,
document: None,
widgets: Vec::new()
}
}
pub fn render(&mut self, http_client: &HTTPClient, ui: &mut Ui) {
}
}

View File

@@ -5,15 +5,27 @@ use bevy_egui::{EguiContextSettings, EguiContexts, EguiPrimaryContextPass, EguiS
pub mod constants;
pub mod http_client;
use crate::constants::DEFAULT_HEADERS;
use crate::http_client::{connection::HTTPClient, *};
use crate::http_client::{connection::HTTPClient, renderer::Renderer};
struct Tab {
url: String,
title: String,
http_client: HTTPClient
http_client: HTTPClient,
renderer: Renderer
}
impl Tab {
fn new(url: &str) -> Tab {
let http_client = HTTPClient::new();
Tab {
url: url.to_string(),
title: url.to_string(),
http_client,
renderer: Renderer::new()
}
}
fn request(&mut self, url: String) {
self.url = url;
if self.url.starts_with("http://") || self.url.starts_with("https://") || self.url.starts_with("view-source:") {
@@ -40,11 +52,7 @@ struct AppState {
}
fn main() {
let new_tab = Tab {
url: "about:blank".to_string(),
title: "about:blank".to_string(),
http_client: HTTPClient::new("about".to_string(), "blank".to_string(), "".to_string(), 0)
};
let new_tab = Tab::new("about:blank");
let mut tabs = Vec::new();
tabs.push(new_tab);
@@ -122,11 +130,7 @@ fn draw(mut contexts: EguiContexts, mut app_state: ResMut<AppState>) -> Result {
}
if ui.button("+" ).clicked() {
let new_tab = Tab {
url: "about:blank".to_string(),
title: "about:blank".to_string(),
http_client: HTTPClient::new("about".to_string(), "blank".to_string(), "".to_string(), 0)
};
let new_tab = Tab::new("about:blank");
app_state.tabs.push(new_tab);
}
@@ -137,6 +141,12 @@ fn draw(mut contexts: EguiContexts, mut app_state: ResMut<AppState>) -> Result {
ui.add_sized([available_width, available_height / 20.0], egui::TextEdit::singleline(&mut app_state.current_url)).request_focus();
});
egui::CentralPanel::default().show(ctx, |ui| {
let active_tab_index = app_state.active_tab.clone();
let tab = &mut app_state.tabs[active_tab_index];
tab.renderer.render(&tab.http_client, ui);
});
Ok(())
}