Ely Office: six offline-first desktop apps in Rust and GPUI

ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-08 21:20:08 -04:00
commit b7fca0146d
817 files changed
+143101

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
use ely_platform::{AppId, logging};
#[test]
fn log_lines_reach_the_app_file_and_a_second_init_fails() {
let dir = tempfile::tempdir().unwrap();
logging::init_in(AppId::Doc, dir.path()).unwrap();
log::info!("hello from the test");
log::logger().flush();
let text = std::fs::read_to_string(dir.path().join("ely.log")).unwrap();
assert!(text.contains("ElyDoc 0.1.0 started"), "{text}");
assert!(text.contains("hello from the test"), "{text}");
let error = logging::init_in(AppId::Mail, dir.path()).unwrap_err();
assert!(
format!("{error:#}").contains("a logger is already set"),
"{error:#}"
);
}
+62
View File
@@ -0,0 +1,62 @@
//! The system player against a small H.264/AAC clip.
#[cfg(target_os = "macos")]
fn main() {
use std::time::{Duration, Instant};
use ely_platform::media::{Player, State};
use objc2_foundation::{NSDate, NSRunLoop};
// The player works through the main run loop.
let pump = |until: &dyn Fn() -> bool| {
let end = Instant::now() + Duration::from_secs(10);
while !until() {
assert!(Instant::now() < end, "the player never got there");
let soon = NSDate::dateWithTimeIntervalSinceNow(0.02);
NSRunLoop::currentRunLoop().runUntilDate(&soon);
}
};
let clip = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../tests/fixtures/media/clip.mp4");
let player = Player::open(&clip).expect("opens");
pump(&|| player.state() != State::Loading);
let State::Ready { seconds, video } = player.state() else {
panic!("not ready: {:?}", player.state());
};
assert!((seconds - 1.0).abs() < 0.2, "{seconds}");
assert_eq!(video, Some((160, 90)));
player.play();
let frames = std::cell::Cell::new(0);
pump(&|| {
frames.set(frames.get() + usize::from(player.frame().is_some()));
player.position() > 0.3 && frames.get() > 0
});
assert!(player.playing());
// At its end it stops; a loop starts over.
pump(&|| player.ended());
assert_eq!(player.tick(false), Ok(false), "done, nothing to draw");
assert_eq!(player.tick(true), Ok(true), "the loop goes on");
pump(&|| player.playing() && player.position() < seconds - 0.2);
// A pause near the end holds, loop or not.
player.pause();
player.seek(seconds - 0.02);
pump(&|| player.position() >= seconds - 0.05);
assert!(!player.ended());
assert_eq!(player.tick(true), Ok(false));
assert!(!player.playing(), "the pause holds");
player.play();
player.pause();
assert!(Player::open(std::path::Path::new("/no/such/clip.mp4")).is_err());
let dir = tempfile::tempdir().expect("a temp dir");
let junk = dir.path().join("junk.mp4");
std::fs::write(&junk, b"not a video at all").expect("writes");
let broken = Player::open(&junk).expect("opens the file");
pump(&|| broken.tick(false) != Ok(true));
assert!(matches!(broken.tick(false), Err(reason) if !reason.is_empty()));
println!("media: plays, shows frames, and fails with reasons");
}
#[cfg(not(target_os = "macos"))]
fn main() {
println!("SKIP: no system player is built on this platform");
}
+24
View File
@@ -0,0 +1,24 @@
use ely_platform::AppId::{self, *};
#[test]
fn packaging_table_lists_the_apps_in_prd_order() {
let apps: [AppId; 8] = [Doc, Table, Show, Pdf, Mail, Tree, Mark, Agent];
let table = include_str!("../../../packaging/apps.tsv");
let rows: Vec<Vec<&str>> = table
.lines()
.map(|line| line.split('\t').collect())
.collect();
assert_eq!(rows.len(), apps.len());
for (row, app) in rows.iter().zip(apps) {
assert_eq!(row[..2], [app.slug(), app.name()]);
assert!(
row[2].ends_with(';'),
"{} has no desktop categories",
app.slug()
);
// Mail and Agent ship in the second batch.
let batch = if matches!(app, Mail | Agent) { "2" } else { "1" };
assert_eq!(row[3], batch, "{} is in the wrong batch", app.slug());
}
}
+60
View File
@@ -0,0 +1,60 @@
use std::{fs, path::PathBuf, process::Command};
use ely_platform::{AppId, logging, startup};
const CHILD: &str = "ELY_STARTUP_TEST_DIR";
const NO_LOG: &str = "ELY_STARTUP_TEST_NO_LOG";
fn rerun(test: &str, dir: &std::path::Path, no_log: bool) -> std::process::Output {
let mut command = Command::new(std::env::current_exe().unwrap());
command
.args(["--exact", test, "--nocapture"])
.env(CHILD, dir)
.env("ELY_NO_DIALOG", "1");
if no_log {
command.env(NO_LOG, "1");
}
command.output().unwrap()
}
#[test]
fn a_startup_failure_is_logged_printed_and_exits_with_one() {
const TEST: &str = "a_startup_failure_is_logged_printed_and_exits_with_one";
if let Some(dir) = std::env::var_os(CHILD) {
logging::init_in(AppId::Doc, &PathBuf::from(dir)).unwrap();
startup::fail(AppId::Doc, "no usable GPU");
}
let dir = tempfile::tempdir().unwrap();
let output = rerun(TEST, dir.path(), false);
assert_eq!(output.status.code(), Some(1));
let stderr = String::from_utf8_lossy(&output.stderr);
let log_path = dir.path().join("ely.log");
assert!(
stderr.contains("ElyDoc could not start") && stderr.contains("no usable GPU"),
"{stderr}"
);
assert!(
stderr.contains(&log_path.display().to_string()),
"the message does not name the real log: {stderr}"
);
let log = fs::read_to_string(log_path).unwrap();
assert!(log.contains("ElyDoc cannot start: no usable GPU"), "{log}");
}
#[test]
fn without_a_logger_the_message_says_there_is_no_log() {
const TEST: &str = "without_a_logger_the_message_says_there_is_no_log";
if std::env::var_os(NO_LOG).is_some() {
startup::fail(AppId::Doc, "logging did not start: read-only home");
}
let dir = tempfile::tempdir().unwrap();
let output = rerun(TEST, dir.path(), true);
assert_eq!(output.status.code(), Some(1));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("none, logging did not start"), "{stderr}");
assert!(!stderr.contains("ely.log"), "{stderr}");
}
+425
View File
@@ -0,0 +1,425 @@
use std::{
fs,
io::{Read, Write},
net::{TcpListener, TcpStream},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
thread,
time::{Duration, Instant},
};
use ely_platform::{
AppId, logging,
update::{Check, IDLE_TIMEOUT, Release, check, download, platform, verify_file},
};
use semver::Version;
use sha2::{Digest, Sha256};
#[derive(Clone)]
enum Reply {
Body(Vec<u8>),
Redirect(String),
Stall(Arc<AtomicBool>),
}
fn hex_of(bytes: &[u8]) -> String {
Sha256::digest(bytes)
.iter()
.map(|b| format!("{b:02x}"))
.collect()
}
fn payload() -> Vec<u8> {
(0..300_000u32).map(|n| (n % 251) as u8).collect()
}
fn respond(mut stream: TcpStream, routes: &[(String, Reply)]) {
let mut request = Vec::new();
let mut byte = [0u8; 1];
while !request.ends_with(b"\r\n\r\n") {
if stream.read(&mut byte).unwrap() == 0 {
return;
}
request.push(byte[0]);
}
let line = String::from_utf8_lossy(&request);
let path = line.split_whitespace().nth(1).unwrap_or("/").to_string();
let reply = routes
.iter()
.find(|(route, _)| *route == path)
.map(|(_, reply)| reply.clone());
let bytes = match reply {
Some(Reply::Body(body)) => {
let head = format!(
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
body.len()
);
[head.into_bytes(), body].concat()
}
Some(Reply::Redirect(to)) => format!(
"HTTP/1.1 302 Found\r\nLocation: {to}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
)
.into_bytes(),
Some(Reply::Stall(closed)) => {
let _ = stream.write_all(
b"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\nConnection: close\r\n\r\n",
);
let _ = stream.write_all(&[7u8; 1000]);
stream
.set_read_timeout(Some(Duration::from_secs(20)))
.unwrap();
let seen = stream.read(&mut [0u8; 1]);
if matches!(seen, Ok(0))
|| seen.is_err_and(|error| error.kind() == std::io::ErrorKind::ConnectionReset)
{
closed.store(true, Ordering::Relaxed);
}
return;
}
None => {
b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\nConnection: close\r\n\r\n".to_vec()
}
};
let _ = stream.write_all(&bytes);
}
/// Serves routes locally; `make` gets the base URL.
fn serve(make: impl FnOnce(&str) -> Vec<(String, Reply)>) -> String {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let base = format!("http://127.0.0.1:{}", listener.local_addr().unwrap().port());
let routes = make(&base);
thread::spawn(move || {
for stream in listener.incoming() {
let routes = routes.clone();
let stream = stream.unwrap();
thread::spawn(move || respond(stream, &routes));
}
});
base
}
fn manifest(version: &str, key: &str, base: &str, sha: &str) -> Reply {
Reply::Body(
format!(r#"{{"version":"{version}","assets":{{"{key}":{{"url":"{base}/ElyDoc.bin","sha256":"{sha}"}}}}}}"#)
.into_bytes(),
)
}
fn release(base: &str, sha: String) -> Release {
Release {
version: Version::new(0, 2, 0),
url: format!("{base}/ElyDoc.bin"),
sha256: sha,
}
}
fn error_text<T>(result: anyhow::Result<T>) -> String {
format!("{:#}", result.err().expect("an error"))
}
#[test]
fn a_newer_release_for_this_platform_is_offered_and_an_equal_or_older_one_is_not() {
let sha = hex_of(&payload()).to_uppercase();
let base = serve(|base| {
vec![(
"/latest.json".into(),
manifest("0.2.0", &platform(), base, &sha),
)]
});
let url = format!("{base}/latest.json");
let found = check(&Version::new(0, 1, 0), &url).unwrap();
assert_eq!(found, Check::Available(release(&base, sha.to_lowercase())));
assert_eq!(check(&Version::new(0, 2, 0), &url).unwrap(), Check::Current);
assert_eq!(check(&Version::new(0, 3, 0), &url).unwrap(), Check::Current);
}
#[test]
fn a_manifest_without_this_platform_a_bad_manifest_and_a_missing_one_all_fail_loudly() {
let base = serve(|base| {
vec![
(
"/other.json".into(),
manifest("0.2.0", "plan9-mips", base, "00"),
),
("/bad.json".into(), Reply::Body(b"{not json".to_vec())),
]
});
let current = Version::new(0, 1, 0);
assert!(
error_text(check(&current, &format!("{base}/other.json"))).contains("has no build for")
);
assert!(error_text(check(&current, &format!("{base}/bad.json"))).contains("not valid"));
assert!(error_text(check(&current, &format!("{base}/none.json"))).contains("cannot fetch"));
}
#[test]
fn plain_http_to_other_hosts_and_credentials_in_the_url_are_refused_before_any_request() {
let current = Version::new(0, 1, 0);
assert!(error_text(check(&current, "http://example.com/latest.json")).contains("not https"));
let sneaky = "http://127.0.0.1:1@192.168.31.221:9/latest.json";
assert!(error_text(check(&current, sneaky)).contains("carries credentials"));
}
#[test]
fn a_redirect_is_followed_on_this_machine_and_refused_when_it_leaves_for_plain_http() {
let sha = hex_of(&payload());
let base = serve(|base| {
vec![
(
"/latest.json".into(),
manifest("0.2.0", &platform(), base, &sha),
),
("/first".into(), Reply::Redirect("/second".into())),
("/second".into(), Reply::Redirect("/latest.json".into())),
(
"/leave".into(),
Reply::Redirect("http://example.com/latest.json".into()),
),
]
});
let current = Version::new(0, 1, 0);
let followed = check(&current, &format!("{base}/first")).unwrap();
assert!(matches!(followed, Check::Available(_)), "{followed:?}");
assert!(error_text(check(&current, &format!("{base}/leave"))).contains("not https"));
}
#[test]
fn a_download_is_verified_reported_and_moved_into_place() {
let body = payload();
let base = serve(|_| vec![("/ElyDoc.bin".into(), Reply::Body(body.clone()))]);
let dir = tempfile::tempdir().unwrap();
let mut seen = Vec::new();
let path = download(
&release(&base, hex_of(&body)),
dir.path(),
&AtomicBool::new(false),
IDLE_TIMEOUT,
&mut |done, total| {
seen.push((done, total));
},
)
.unwrap()
.expect("not cancelled");
assert_eq!(path, dir.path().join("ElyDoc.bin"));
assert_eq!(fs::read(&path).unwrap(), body);
assert!(!dir.path().join("ElyDoc.bin.part").exists());
assert_eq!(
seen.last().copied(),
Some((body.len() as u64, Some(body.len() as u64)))
);
assert!(
seen.windows(2).all(|pair| pair[0].0 < pair[1].0),
"progress went backwards"
);
verify_file(&path, &hex_of(&body)).unwrap();
}
#[test]
fn a_wrong_hash_leaves_no_file_behind() {
let body = payload();
let base = serve(|_| vec![("/ElyDoc.bin".into(), Reply::Body(body.clone()))]);
let dir = tempfile::tempdir().unwrap();
let result = download(
&release(&base, hex_of(b"other")),
dir.path(),
&AtomicBool::new(false),
IDLE_TIMEOUT,
&mut |_, _| {},
);
assert!(error_text(result).contains("the release says"));
assert_eq!(fs::read_dir(dir.path()).unwrap().count(), 0);
}
#[cfg(unix)]
#[test]
fn the_download_error_survives_a_failed_cleanup() {
use std::os::unix::fs::PermissionsExt;
let body = payload();
let base = serve(|_| vec![("/ElyDoc.bin".into(), Reply::Body(body.clone()))]);
let dir = tempfile::tempdir().unwrap();
let lock = |mode| fs::set_permissions(dir.path(), fs::Permissions::from_mode(mode)).unwrap();
let mut locked = false;
let result = download(
&release(&base, hex_of(b"other")),
dir.path(),
&AtomicBool::new(false),
IDLE_TIMEOUT,
&mut |_, _| {
if !locked {
lock(0o555);
locked = true;
}
},
);
let still_writable = fs::File::create(dir.path().join("probe")).is_ok();
lock(0o755);
if still_writable {
println!("SKIP: permissions do not bind this user");
return;
}
assert!(error_text(result).contains("the release says"));
}
fn closed_within(flag: &AtomicBool, limit: Duration) -> bool {
let started = Instant::now();
while started.elapsed() < limit {
if flag.load(Ordering::Relaxed) {
return true;
}
thread::sleep(Duration::from_millis(50));
}
false
}
#[test]
fn a_stalled_download_fails_and_frees_its_socket() {
let closed = Arc::new(AtomicBool::new(false));
let base = serve({
let closed = closed.clone();
move |_| vec![("/ElyDoc.bin".into(), Reply::Stall(closed))]
});
let dir = tempfile::tempdir().unwrap();
let stalled = download(
&release(&base, hex_of(b"x")),
dir.path(),
&AtomicBool::new(false),
Duration::from_millis(600),
&mut |_, _| {},
);
let text = error_text(stalled);
assert!(text.contains("stalled"), "{text}");
assert!(
closed_within(&closed, Duration::from_secs(5)),
"the client kept the socket open"
);
assert_eq!(fs::read_dir(dir.path()).unwrap().count(), 0);
}
#[test]
fn a_cancel_is_answered_at_once_and_the_socket_is_freed_within_the_idle_time() {
let closed = Arc::new(AtomicBool::new(false));
let base = serve({
let closed = closed.clone();
move |_| vec![("/ElyDoc.bin".into(), Reply::Stall(closed))]
});
let dir = tempfile::tempdir().unwrap();
let cancel = AtomicBool::new(false);
let started = Instant::now();
let outcome = thread::scope(|scope| {
scope.spawn(|| {
thread::sleep(Duration::from_millis(300));
cancel.store(true, Ordering::Relaxed);
});
download(
&release(&base, hex_of(b"x")),
dir.path(),
&cancel,
Duration::from_secs(1),
&mut |_, _| {},
)
});
assert_eq!(outcome.unwrap(), None);
assert!(
started.elapsed() < Duration::from_secs(1),
"the cancel waited for the socket"
);
assert!(
closed_within(&closed, Duration::from_secs(5)),
"the client kept the socket open"
);
assert_eq!(fs::read_dir(dir.path()).unwrap().count(), 0);
}
#[test]
fn a_cancelled_download_returns_none_and_leaves_no_file_behind() {
let body = payload();
let base = serve(|_| vec![("/ElyDoc.bin".into(), Reply::Body(body.clone()))]);
let dir = tempfile::tempdir().unwrap();
let cancel = AtomicBool::new(false);
let outcome = download(
&release(&base, hex_of(&body)),
dir.path(),
&cancel,
IDLE_TIMEOUT,
&mut |_, _| {
cancel.store(true, Ordering::Relaxed);
},
)
.unwrap();
assert_eq!(outcome, None);
assert_eq!(fs::read_dir(dir.path()).unwrap().count(), 0);
}
#[test]
fn a_file_the_user_brought_is_checked_against_its_published_hash() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("ElyDoc.dmg");
fs::write(&file, b"installer bytes").unwrap();
verify_file(&file, &hex_of(b"installer bytes").to_uppercase()).unwrap();
assert!(
error_text(verify_file(&file, &hex_of(b"tampered bytes"))).contains("the release says")
);
assert!(error_text(verify_file(&dir.path().join("none"), "00")).contains("cannot open"));
}
#[test]
fn checks_and_downloads_are_logged_with_their_outcome() {
let logs = tempfile::tempdir().unwrap();
logging::init_in(AppId::Doc, logs.path()).unwrap();
let body = payload();
let sha = hex_of(&body);
let base = serve(|base| {
vec![
(
"/latest.json".into(),
manifest("0.2.0", &platform(), base, &sha),
),
("/ElyDoc.bin".into(), Reply::Body(body.clone())),
]
});
let dir = tempfile::tempdir().unwrap();
let cancel = AtomicBool::new(false);
check(&Version::new(0, 1, 0), &format!("{base}/latest.json")).unwrap();
check(&Version::new(0, 1, 0), &format!("{base}/none.json")).unwrap_err();
download(
&release(&base, sha),
dir.path(),
&cancel,
IDLE_TIMEOUT,
&mut |_, _| {
cancel.store(true, Ordering::Relaxed);
},
)
.unwrap();
log::logger().flush();
let text = fs::read_to_string(logs.path().join("ely.log")).unwrap();
for line in [
"update check: 127.0.0.1 offers 0.2.0",
"update check: 127.0.0.1 failed",
"update download: 0.2.0 cancelled",
] {
assert!(text.contains(line), "no '{line}' in:\n{text}");
}
}