Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"packages/blitz-dom",
"packages/blitz-html",
"packages/blitz-net",
"packages/blitz-devtools-server",
"packages/blitz-paint",
"packages/blitz-shell",
"packages/blitz",
Expand Down Expand Up @@ -40,6 +41,7 @@ blitz-net = { version = "0.2.0", path = "./packages/blitz-net", default-features
blitz-paint = { version = "0.2.0", path = "./packages/blitz-paint", default-features = false }
blitz-shell = { version = "0.2.0", path = "./packages/blitz-shell", default-features = false }
blitz-traits = { version = "0.2.0", path = "./packages/blitz-traits", default-features = false }
blitz-devtools-server = { version = "0.2.0", path = "./packages/blitz-devtools-server", default-features = false }
stylo_taffy = { version = "0.2.0", path = "./packages/stylo_taffy", default-features = false }
dioxus-native = { version = "0.7.0", path = "./packages/dioxus-native", default-features = false }
dioxus-native-dom = { version = "0.7.0", path = "./packages/dioxus-native-dom", default-features = false }
Expand Down Expand Up @@ -125,6 +127,7 @@ url = "2.5.0"
http = "1.1.0"
data-url = "0.3.1"
tokio = "1.42"
tokio-util = "0.7"
reqwest = "0.12"
reqwest-middleware = { version = "0.4.2", default-features = false }
http-cache-reqwest = { version = "=1.0.0-alpha.2", default-features = false }
Expand All @@ -138,13 +141,16 @@ html-escape = "0.2.13"
percent-encoding = "2.3.1"
png = "0.17"
serde = "1"
serde_json = "1"
serde_derive = "1"

# Dioxus Native
webbrowser = "1.0"

# Other dependencies
rustc-hash = "1.1.0"
bytes = "1.7.1"
bytestring = "1.4"
slab = "0.4.9"
tracing = "0.1.40"
tracing-subscriber = "0.3"
Expand Down
4 changes: 2 additions & 2 deletions apps/readme/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use markdown::{BLITZ_MD_STYLES, GITHUB_MD_STYLES, markdown_to_html};
use notify::{Error as NotifyError, Event as NotifyEvent, RecursiveMode, Watcher as _};
use readme_application::{ReadmeApplication, ReadmeEvent};

use blitz_shell::{BlitzShellEvent, BlitzShellNetWaker, WindowConfig, create_default_event_loop};
use blitz_shell::{BlitzShellEvent, BlitzShellWaker, WindowConfig, create_default_event_loop};
use std::env::current_dir;
use std::fs;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -76,7 +76,7 @@ fn main() {
let event_loop = create_default_event_loop();
let proxy = event_loop.create_proxy();

let net_waker = Some(BlitzShellNetWaker::shared(proxy.clone()));
let net_waker = Some(BlitzShellWaker::net_waker(proxy.clone()));
let net_provider = Arc::new(Provider::new(net_waker));

let (base_url, contents, is_md, file_path) =
Expand Down
25 changes: 25 additions & 0 deletions packages/blitz-devtools-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "blitz-devtools-server"
description = "(Firefox) devtools protocol server implementation"
documentation = "https://docs.rs/blitz-devtools-server"
version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
categories.workspace = true
edition.workspace = true

[dependencies]
# Blitz dependencies
blitz-traits = { workspace = true }

# Networking dependencies
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tokio-util = { workspace = true }
bytes = { workspace = true }
bytestring = { workspace = true }
tokio-stream = "0.1.17"
colored = "3.0.0"
139 changes: 139 additions & 0 deletions packages/blitz-devtools-server/src/actors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
pub mod device;
pub mod preference;
pub mod process;
pub mod root;
use std::any::Any;
use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering as Ao};

pub(crate) use device::DeviceActor;
pub(crate) use preference::PreferenceActor;
pub(crate) use process::ProcessActor;
pub(crate) use root::RootActor;

use crate::{Connection, DevtoolsServer, GenericClientMessage, JsonValue, MessageWriter};

pub(crate) type ActorId = String;

pub(crate) fn generate_name(base: &str) -> String {
static ACTOR_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
let id = ACTOR_ID_COUNTER.fetch_add(1, Ao::Relaxed);
format!("{base}-{id}")
}

// #[derive(Copy, Clone, PartialEq, Eq, Hash)]
// pub(crate) struct ActorId {
// kind: &'static str,
// id: Option<u32>,
// }

// impl Display for ActorId {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// match self.id {
// Some(id) => write!(f, "{}-{}", self.kind, id),
// None => write!(f, "{}", self.kind),
// }
// }
// }

// impl Display for ActorId {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "{}-{}", self.kind, self.id)
// }
// }

// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets
pub(crate) enum ActorMessageErr {
NoSuchActor,
UnrecognizedPacketType,
MissingParameter,
BadParameterType,
}

impl ActorMessageErr {
pub(crate) fn as_str(&self) -> &'static str {
match self {
ActorMessageErr::NoSuchActor => "noSuchActor",
ActorMessageErr::UnrecognizedPacketType => "unrecognizedPacketType",
ActorMessageErr::MissingParameter => "missingParameter",
ActorMessageErr::BadParameterType => "badParameterType",
}
}
}

pub(crate) trait Actor: Any + Send + 'static {
fn name(&self) -> String;

fn handle_message<'a>(
&self,
ctx: &mut DevtoolContext<'a>,
message: GenericClientMessage,
) -> Result<(), ActorMessageErr>;
}

impl Connection {
pub(crate) fn init(&mut self) {
let pref = PreferenceActor::new();
let device = DeviceActor::new();
let process = ProcessActor::new();
let root = RootActor::new(pref.name(), device.name(), process.name());
self.insert_actor(Box::new(pref));
self.insert_actor(Box::new(device));
self.insert_actor(Box::new(process));
self.insert_actor(Box::new(root));
}

pub(crate) fn insert_actor(&mut self, actor: Box<dyn Actor>) {
self.actors.insert(actor.name(), actor);
}

pub(crate) fn context(&mut self) -> DevtoolContext<'_> {
DevtoolContext {
writer: &mut self.writer,
actors: &mut self.actors,
actors_to_create: Vec::new(),
}
}

pub(crate) fn handle_message(&mut self, msg: GenericClientMessage) {
let mut ctx = self.context();
let Some(actor) = ctx.actors.get(&msg.to) else {
self.writer.write_err(msg.to, ActorMessageErr::NoSuchActor);
return;
};

let result = actor.handle_message(&mut ctx, msg);
if let Err(err) = result {
ctx.write_err(actor.name(), err);
}

// Handle errors
let actors_to_create = std::mem::take(&mut ctx.actors_to_create);
for actor in actors_to_create {
self.insert_actor(actor);
}
}
}

pub(crate) struct DevtoolContext<'a> {
pub(crate) writer: &'a mut MessageWriter,
pub(crate) actors: &'a HashMap<ActorId, Box<dyn Actor>>,
pub(crate) actors_to_create: Vec<Box<dyn Actor>>,
}

impl DevtoolContext<'_> {
fn push_actor(&mut self, actor: Box<dyn Actor>) {
self.actors_to_create.push(actor);
}

fn write_msg(&mut self, from: String, data: JsonValue) {
self.writer.write_msg(from, data);
}
fn write_err(&mut self, from: String, err: ActorMessageErr) {
self.writer.write_err(from, err);
}

fn actor<T: Actor>(&self, name: &str) -> &T {
(&*self.actors[name] as &dyn Any).downcast_ref().unwrap()
}
}
52 changes: 52 additions & 0 deletions packages/blitz-devtools-server/src/actors/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use serde_json::json;

use crate::GenericClientMessage;
use crate::actors::{Actor, ActorId, ActorMessageErr, DevtoolContext};

use super::generate_name;

pub(crate) struct DeviceActor {
name: String,
}

impl DeviceActor {
pub(crate) fn new() -> Self {
Self {
name: generate_name("device"),
}
}
}

impl Actor for DeviceActor {
fn name(&self) -> ActorId {
self.name.clone()
}

fn handle_message(
&self,
ctx: &mut DevtoolContext<'_>,
message: GenericClientMessage,
) -> Result<(), ActorMessageErr> {
match &*message.type_ {
"getDescription" => {
ctx.write_msg(
self.name(),
json!({ "value": {
"apptype":"blitz",
"name":"Blitz",
"brandName":"Blitz",
"version": env!("CARGO_PKG_VERSION").to_string(),
"appbuildid": format!("Version {}", env!("CARGO_PKG_VERSION").to_string()),
"platformversion":"135.0",
// "platformbuildid":"Version 1.0",
// "useragent":"Mozilla/5.0 (macOS; AArch64) Ladybird/1.0",
// "os":"macOS",
// "arch":"AArch64"
}}),
);
Ok(())
}
_ => Err(ActorMessageErr::UnrecognizedPacketType),
}
}
}
Loading
Loading