Keep private sidecar profile data transient
This commit is contained in:
@@ -6,6 +6,9 @@ pub mod plugin_signatures;
|
|||||||
mod servo_profile_data;
|
mod servo_profile_data;
|
||||||
pub mod servo_sidecar;
|
pub mod servo_sidecar;
|
||||||
mod servo_sidecar_command;
|
mod servo_sidecar_command;
|
||||||
|
mod servo_sidecar_request;
|
||||||
|
|
||||||
|
pub(crate) use servo_profile_data::ProfileDataMode;
|
||||||
|
|
||||||
#[cfg(all(test, feature = "live-site-smoke"))]
|
#[cfg(all(test, feature = "live-site-smoke"))]
|
||||||
pub(crate) mod prd_live_sites;
|
pub(crate) mod prd_live_sites;
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::{
|
||||||
|
env,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::{SystemTime, SystemTimeError, UNIX_EPOCH},
|
||||||
|
};
|
||||||
|
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use ely_domain::ProfileId;
|
use ely_domain::ProfileId;
|
||||||
@@ -15,3 +19,20 @@ pub(super) fn default_profile_data_root() -> Option<PathBuf> {
|
|||||||
pub(super) fn profile_data_dir(profile_data_root: &Path, profile_id: &ProfileId) -> PathBuf {
|
pub(super) fn profile_data_dir(profile_data_root: &Path, profile_id: &ProfileId) -> PathBuf {
|
||||||
profile_data_root.join(profile_id.as_str()).join("servo")
|
profile_data_root.join(profile_id.as_str()).join("servo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn transient_profile_data_dir(
|
||||||
|
profile_id: &ProfileId,
|
||||||
|
) -> Result<PathBuf, SystemTimeError> {
|
||||||
|
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos();
|
||||||
|
Ok(env::temp_dir().join("ely-browser-servo-profiles").join(format!(
|
||||||
|
"{}-{}-{timestamp}",
|
||||||
|
std::process::id(),
|
||||||
|
profile_id.as_str()
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub(crate) enum ProfileDataMode {
|
||||||
|
Persistent,
|
||||||
|
Transient,
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,12 +6,16 @@ use std::{
|
|||||||
time::{Duration, Instant, SystemTime, SystemTimeError, UNIX_EPOCH},
|
time::{Duration, Instant, SystemTime, SystemTimeError, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ely_domain::{ProfileId, UrlText};
|
use ely_domain::ProfileId;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub use super::servo_sidecar_request::SidecarSnapshotRequest;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
servo_profile_data::{default_profile_data_root, profile_data_dir},
|
servo_profile_data::{
|
||||||
|
ProfileDataMode, default_profile_data_root, profile_data_dir, transient_profile_data_dir,
|
||||||
|
},
|
||||||
servo_sidecar_command::{SidecarCommandTarget, default_sidecar_command},
|
servo_sidecar_command::{SidecarCommandTarget, default_sidecar_command},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,29 +67,30 @@ impl ServoSidecarClient {
|
|||||||
request: &SidecarSnapshotRequest,
|
request: &SidecarSnapshotRequest,
|
||||||
) -> Result<SidecarSnapshot, ServoSidecarError> {
|
) -> Result<SidecarSnapshot, ServoSidecarError> {
|
||||||
let rgba_path = temporary_rgba_path()?;
|
let rgba_path = temporary_rgba_path()?;
|
||||||
let profile_data_dir = profile_data_dir(&self.profile_data_root, &request.profile_id);
|
let profile_data_dir = request.profile_data_dir(&self.profile_data_root)?;
|
||||||
let output = match self.run_snapshot_command(request, &rgba_path, &profile_data_dir) {
|
let output = match self.run_snapshot_command(request, &rgba_path, &profile_data_dir) {
|
||||||
Ok(output) => output,
|
Ok(output) => output,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
remove_temporary_file(&rgba_path)?;
|
return cleanup_failed_snapshot(request, &rgba_path, &profile_data_dir, error);
|
||||||
return Err(error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
remove_temporary_file(&rgba_path)?;
|
let error = ServoSidecarError::SidecarFailed {
|
||||||
return Err(ServoSidecarError::SidecarFailed {
|
|
||||||
status: output.status.to_string(),
|
status: output.status.to_string(),
|
||||||
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
|
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
|
||||||
});
|
};
|
||||||
|
return cleanup_failed_snapshot(request, &rgba_path, &profile_data_dir, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = read_sidecar_snapshot(&output.stdout, &rgba_path, &request.profile_id);
|
let snapshot = read_sidecar_snapshot(&output.stdout, &rgba_path, &request.profile_id);
|
||||||
let cleanup = remove_temporary_file(&rgba_path);
|
let cleanup = remove_temporary_file(&rgba_path);
|
||||||
match (snapshot, cleanup) {
|
let profile_cleanup = request.cleanup_profile_data_dir(&profile_data_dir);
|
||||||
(Ok(snapshot), Ok(())) => Ok(snapshot),
|
match (snapshot, cleanup, profile_cleanup) {
|
||||||
(Err(error), Ok(())) => Err(error),
|
(Ok(snapshot), Ok(()), Ok(())) => Ok(snapshot),
|
||||||
(Ok(_), Err(error)) | (Err(_), Err(error)) => Err(error),
|
(Err(error), Ok(()), Ok(())) => Err(error),
|
||||||
|
(Ok(_), Err(error), _) | (Err(_), Err(error), _) => Err(error),
|
||||||
|
(Ok(_), Ok(()), Err(error)) | (Err(_), Ok(()), Err(error)) => Err(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,60 +165,24 @@ fn append_snapshot_args(
|
|||||||
.arg(request.scroll_y.to_string());
|
.arg(request.scroll_y.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct SidecarSnapshotRequest {
|
|
||||||
url: UrlText,
|
|
||||||
profile_id: ProfileId,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
scroll_x: i32,
|
|
||||||
scroll_y: i32,
|
|
||||||
click_point: Option<SidecarClickPoint>,
|
|
||||||
typed_text: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SidecarSnapshotRequest {
|
impl SidecarSnapshotRequest {
|
||||||
#[must_use]
|
fn profile_data_dir(&self, profile_data_root: &Path) -> Result<PathBuf, ServoSidecarError> {
|
||||||
pub fn new(url: UrlText, profile_id: ProfileId, width: u32, height: u32) -> Self {
|
match self.profile_data_mode {
|
||||||
Self {
|
ProfileDataMode::Persistent => {
|
||||||
url,
|
Ok(profile_data_dir(profile_data_root, &self.profile_id))
|
||||||
profile_id,
|
}
|
||||||
width,
|
ProfileDataMode::Transient => {
|
||||||
height,
|
transient_profile_data_dir(&self.profile_id).map_err(ServoSidecarError::SystemClock)
|
||||||
scroll_x: 0,
|
}
|
||||||
scroll_y: 0,
|
|
||||||
click_point: None,
|
|
||||||
typed_text: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
fn cleanup_profile_data_dir(&self, profile_data_dir: &Path) -> Result<(), ServoSidecarError> {
|
||||||
pub fn with_scroll_offset(mut self, scroll_x: i32, scroll_y: i32) -> Self {
|
if self.profile_data_mode == ProfileDataMode::Persistent {
|
||||||
self.scroll_x = scroll_x;
|
return Ok(());
|
||||||
self.scroll_y = scroll_y;
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
remove_temporary_directory(profile_data_dir)
|
||||||
pub fn with_click_point(mut self, x: u32, y: u32) -> Self {
|
|
||||||
self.click_point = Some(SidecarClickPoint { x, y });
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn with_typed_text(mut self, typed_text: String) -> Self {
|
|
||||||
self.typed_text = Some(typed_text);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn typed_text_for_test(&self) -> Option<&str> {
|
|
||||||
self.typed_text.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn profile_id_for_test(&self) -> &ProfileId {
|
|
||||||
&self.profile_id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_attempts(&self) -> usize {
|
fn max_attempts(&self) -> usize {
|
||||||
@@ -225,12 +194,6 @@ impl SidecarSnapshotRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
struct SidecarClickPoint {
|
|
||||||
x: u32,
|
|
||||||
y: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SidecarSnapshot {
|
pub struct SidecarSnapshot {
|
||||||
loaded_url: Option<String>,
|
loaded_url: Option<String>,
|
||||||
@@ -360,6 +323,9 @@ pub enum ServoSidecarError {
|
|||||||
#[error("failed to remove servo frame file: {0}")]
|
#[error("failed to remove servo frame file: {0}")]
|
||||||
FrameCleanup(#[source] io::Error),
|
FrameCleanup(#[source] io::Error),
|
||||||
|
|
||||||
|
#[error("failed to remove transient servo profile data at {path}: {source}")]
|
||||||
|
ProfileDataCleanup { path: PathBuf, source: io::Error },
|
||||||
|
|
||||||
#[error("servo sidecar returned incomplete render state: {state}")]
|
#[error("servo sidecar returned incomplete render state: {state}")]
|
||||||
IncompleteRender { state: String },
|
IncompleteRender { state: String },
|
||||||
|
|
||||||
@@ -416,6 +382,31 @@ fn remove_temporary_file(path: &Path) -> Result<(), ServoSidecarError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_temporary_directory(path: &Path) -> Result<(), ServoSidecarError> {
|
||||||
|
match fs::remove_dir_all(path) {
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(()),
|
||||||
|
Err(error) => {
|
||||||
|
Err(ServoSidecarError::ProfileDataCleanup { path: path.to_path_buf(), source: error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup_failed_snapshot(
|
||||||
|
request: &SidecarSnapshotRequest,
|
||||||
|
rgba_path: &Path,
|
||||||
|
profile_data_dir: &Path,
|
||||||
|
snapshot_error: ServoSidecarError,
|
||||||
|
) -> Result<SidecarSnapshot, ServoSidecarError> {
|
||||||
|
let frame_cleanup = remove_temporary_file(rgba_path);
|
||||||
|
let profile_cleanup = request.cleanup_profile_data_dir(profile_data_dir);
|
||||||
|
match (frame_cleanup, profile_cleanup) {
|
||||||
|
(Ok(()), Ok(())) => Err(snapshot_error),
|
||||||
|
(Err(error), _) => Err(error),
|
||||||
|
(Ok(()), Err(error)) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn terminate_child(mut child: std::process::Child) -> Result<(), ServoSidecarError> {
|
fn terminate_child(mut child: std::process::Child) -> Result<(), ServoSidecarError> {
|
||||||
match child.kill() {
|
match child.kill() {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
use ely_domain::{ProfileId, UrlText};
|
||||||
|
|
||||||
|
use super::ProfileDataMode;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SidecarSnapshotRequest {
|
||||||
|
pub(in crate::services) url: UrlText,
|
||||||
|
pub(in crate::services) profile_id: ProfileId,
|
||||||
|
pub(in crate::services) profile_data_mode: ProfileDataMode,
|
||||||
|
pub(in crate::services) width: u32,
|
||||||
|
pub(in crate::services) height: u32,
|
||||||
|
pub(in crate::services) scroll_x: i32,
|
||||||
|
pub(in crate::services) scroll_y: i32,
|
||||||
|
pub(in crate::services) click_point: Option<SidecarClickPoint>,
|
||||||
|
pub(in crate::services) typed_text: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SidecarSnapshotRequest {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(url: UrlText, profile_id: ProfileId, width: u32, height: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
url,
|
||||||
|
profile_id,
|
||||||
|
profile_data_mode: ProfileDataMode::Persistent,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
scroll_x: 0,
|
||||||
|
scroll_y: 0,
|
||||||
|
click_point: None,
|
||||||
|
typed_text: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_profile_data_mode(mut self, profile_data_mode: ProfileDataMode) -> Self {
|
||||||
|
self.profile_data_mode = profile_data_mode;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_scroll_offset(mut self, scroll_x: i32, scroll_y: i32) -> Self {
|
||||||
|
self.scroll_x = scroll_x;
|
||||||
|
self.scroll_y = scroll_y;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_click_point(mut self, x: u32, y: u32) -> Self {
|
||||||
|
self.click_point = Some(SidecarClickPoint { x, y });
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_typed_text(mut self, typed_text: String) -> Self {
|
||||||
|
self.typed_text = Some(typed_text);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) fn typed_text_for_test(&self) -> Option<&str> {
|
||||||
|
self.typed_text.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) fn profile_id_for_test(&self) -> &ProfileId {
|
||||||
|
&self.profile_id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) fn profile_data_mode_for_test(&self) -> ProfileDataMode {
|
||||||
|
self.profile_data_mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub(in crate::services) struct SidecarClickPoint {
|
||||||
|
pub(in crate::services) x: u32,
|
||||||
|
pub(in crate::services) y: u32,
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use ely_domain::UrlText;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[cfg(feature = "live-site-smoke")]
|
#[cfg(feature = "live-site-smoke")]
|
||||||
@@ -82,6 +84,46 @@ fn keeps_page_interactions_single_attempt() -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn persistent_profile_data_uses_profile_root() -> Result<(), Box<dyn Error>> {
|
||||||
|
let profile_id = ProfileId::new();
|
||||||
|
let request = SidecarSnapshotRequest::new(
|
||||||
|
UrlText::parse("https://example.com")?,
|
||||||
|
profile_id.clone(),
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
let root = std::env::temp_dir().join("ely-browser-profile-root-test");
|
||||||
|
|
||||||
|
assert_eq!(request.profile_data_mode_for_test(), ProfileDataMode::Persistent);
|
||||||
|
assert_eq!(request.profile_data_dir(&root)?, root.join(profile_id.as_str()).join("servo"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transient_profile_data_uses_temporary_directory_and_cleans_up() -> Result<(), Box<dyn Error>> {
|
||||||
|
let profile_id = ProfileId::new();
|
||||||
|
let request = SidecarSnapshotRequest::new(
|
||||||
|
UrlText::parse("https://example.com")?,
|
||||||
|
profile_id.clone(),
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
.with_profile_data_mode(ProfileDataMode::Transient);
|
||||||
|
let root = std::env::temp_dir().join("ely-browser-profile-root-test");
|
||||||
|
let profile_data_dir = request.profile_data_dir(&root)?;
|
||||||
|
|
||||||
|
assert!(profile_data_dir.starts_with(std::env::temp_dir().join("ely-browser-servo-profiles")));
|
||||||
|
assert!(profile_data_dir.to_string_lossy().contains(profile_id.as_str()));
|
||||||
|
std::fs::create_dir_all(&profile_data_dir)?;
|
||||||
|
std::fs::write(profile_data_dir.join("probe"), b"private")?;
|
||||||
|
|
||||||
|
request.cleanup_profile_data_dir(&profile_data_dir)?;
|
||||||
|
|
||||||
|
assert!(!profile_data_dir.exists());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "live-site-smoke")]
|
#[cfg(feature = "live-site-smoke")]
|
||||||
#[test]
|
#[test]
|
||||||
fn desktop_sidecar_opens_prd_top_sites() -> Result<(), Box<dyn Error>> {
|
fn desktop_sidecar_opens_prd_top_sites() -> Result<(), Box<dyn Error>> {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ impl ElyShell {
|
|||||||
"ely://settings/updates" => self.render_updates_page(snapshot),
|
"ely://settings/updates" => self.render_updates_page(snapshot),
|
||||||
"ely://sync/status" => self.render_sync_page(snapshot, cx),
|
"ely://sync/status" => self.render_sync_page(snapshot, cx),
|
||||||
url if super::web_surface::is_external_web_url(url) => {
|
url if super::web_surface::is_external_web_url(url) => {
|
||||||
self.render_external_web_canvas(tab, cx)
|
self.render_external_web_canvas(tab, snapshot, cx)
|
||||||
}
|
}
|
||||||
_ => render_default_page(tab),
|
_ => render_default_page(tab),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
|||||||
use ely_domain::{BrowserTab, TabId};
|
use ely_domain::{BrowserTab, TabId};
|
||||||
use gpui::{Bounds, Pixels, Point};
|
use gpui::{Bounds, Pixels, Point};
|
||||||
|
|
||||||
use crate::services::servo_sidecar::SidecarSnapshotRequest;
|
use crate::services::{ProfileDataMode, servo_sidecar::SidecarSnapshotRequest};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
web_surface_frame::WebSurfaceFrame,
|
web_surface_frame::WebSurfaceFrame,
|
||||||
@@ -47,7 +47,11 @@ impl WebSurfaceStore {
|
|||||||
self.states.get(tab_id)
|
self.states.get(tab_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn prepare_request(&mut self, tab: &BrowserTab) -> Option<WebSurfaceRequest> {
|
pub(super) fn prepare_request(
|
||||||
|
&mut self,
|
||||||
|
tab: &BrowserTab,
|
||||||
|
profile_data_mode: ProfileDataMode,
|
||||||
|
) -> Option<WebSurfaceRequest> {
|
||||||
if !is_external_web_url(tab.url().as_str()) {
|
if !is_external_web_url(tab.url().as_str()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -108,6 +112,7 @@ impl WebSurfaceStore {
|
|||||||
size.width,
|
size.width,
|
||||||
size.height,
|
size.height,
|
||||||
)
|
)
|
||||||
|
.with_profile_data_mode(profile_data_mode)
|
||||||
.with_scroll_offset(scroll_offset.x(), scroll_offset.y());
|
.with_scroll_offset(scroll_offset.x(), scroll_offset.y());
|
||||||
if let Some(click_point) = click_point {
|
if let Some(click_point) = click_point {
|
||||||
snapshot_request = snapshot_request.with_click_point(click_point.x(), click_point.y());
|
snapshot_request = snapshot_request.with_click_point(click_point.x(), click_point.y());
|
||||||
@@ -410,7 +415,7 @@ mod tests {
|
|||||||
use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
||||||
use gpui::{Bounds, point, px, size};
|
use gpui::{Bounds, point, px, size};
|
||||||
|
|
||||||
use super::WebSurfaceStore;
|
use super::{ProfileDataMode, WebSurfaceStore};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typed_text_enters_snapshot_request_after_clicked_viewport() -> Result<(), Box<dyn Error>> {
|
fn typed_text_enters_snapshot_request_after_clicked_viewport() -> Result<(), Box<dyn Error>> {
|
||||||
@@ -427,7 +432,9 @@ mod tests {
|
|||||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "e"));
|
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "e"));
|
||||||
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "l"));
|
assert!(store.record_typed_text(tab.id(), tab.url().as_str(), "l"));
|
||||||
|
|
||||||
let request = store.prepare_request(&tab).ok_or("missing web surface request")?;
|
let request = store
|
||||||
|
.prepare_request(&tab, ProfileDataMode::Persistent)
|
||||||
|
.ok_or("missing web surface request")?;
|
||||||
|
|
||||||
assert_eq!(request.typed_text.as_deref(), Some("el"));
|
assert_eq!(request.typed_text.as_deref(), Some("el"));
|
||||||
assert_eq!(request.snapshot_request.typed_text_for_test(), Some("el"));
|
assert_eq!(request.snapshot_request.typed_text_for_test(), Some("el"));
|
||||||
@@ -435,6 +442,25 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn private_profile_enters_transient_snapshot_request() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut store = WebSurfaceStore::new();
|
||||||
|
let tab = web_tab("https://example.com/private")?;
|
||||||
|
|
||||||
|
let bounds = Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)));
|
||||||
|
assert!(store.record_viewport_size(tab.id(), bounds));
|
||||||
|
|
||||||
|
let request = store
|
||||||
|
.prepare_request(&tab, ProfileDataMode::Transient)
|
||||||
|
.ok_or("missing web surface request")?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
request.snapshot_request.profile_data_mode_for_test(),
|
||||||
|
ProfileDataMode::Transient
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn web_tab(url: &str) -> Result<BrowserTab, Box<dyn Error>> {
|
fn web_tab(url: &str) -> Result<BrowserTab, Box<dyn Error>> {
|
||||||
Ok(BrowserTab::new(
|
Ok(BrowserTab::new(
|
||||||
TabId::new(),
|
TabId::new(),
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use ely_domain::{BrowserTab, TabId};
|
use ely_browser_core::BrowserSnapshot;
|
||||||
|
use ely_domain::{BrowserTab, ProfileKind, TabId};
|
||||||
use gpui::{AnyElement, Bounds, Context, Pixels, Point};
|
use gpui::{AnyElement, Bounds, Context, Pixels, Point};
|
||||||
|
|
||||||
use crate::services::servo_sidecar::{ServoSidecarError, SidecarSnapshot};
|
use crate::services::{
|
||||||
|
ProfileDataMode,
|
||||||
|
servo_sidecar::{ServoSidecarError, SidecarSnapshot},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ElyShell,
|
ElyShell,
|
||||||
@@ -26,11 +30,16 @@ impl ElyShell {
|
|||||||
pub(super) fn render_external_web_canvas(
|
pub(super) fn render_external_web_canvas(
|
||||||
&mut self,
|
&mut self,
|
||||||
tab: &BrowserTab,
|
tab: &BrowserTab,
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
self.ensure_external_web_frame(tab, cx);
|
|
||||||
|
|
||||||
let state_entity = cx.entity().clone();
|
let state_entity = cx.entity().clone();
|
||||||
|
let Some(profile_data_mode) = profile_data_mode_for(tab, snapshot) else {
|
||||||
|
return render_failed_web_surface(tab, "Profile context is unavailable.", state_entity);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ensure_external_web_frame(tab, profile_data_mode, cx);
|
||||||
|
|
||||||
match self.web_surfaces.state(tab.id()) {
|
match self.web_surfaces.state(tab.id()) {
|
||||||
Some(WebSurfaceState::Ready(frame)) => {
|
Some(WebSurfaceState::Ready(frame)) => {
|
||||||
render_ready_web_surface(frame, tab, state_entity)
|
render_ready_web_surface(frame, tab, state_entity)
|
||||||
@@ -47,8 +56,13 @@ impl ElyShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_external_web_frame(&mut self, tab: &BrowserTab, cx: &mut Context<Self>) {
|
fn ensure_external_web_frame(
|
||||||
let Some(request) = self.web_surfaces.prepare_request(tab) else {
|
&mut self,
|
||||||
|
tab: &BrowserTab,
|
||||||
|
profile_data_mode: ProfileDataMode,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
let Some(request) = self.web_surfaces.prepare_request(tab, profile_data_mode) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -190,3 +204,12 @@ impl ElyShell {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn profile_data_mode_for(tab: &BrowserTab, snapshot: &BrowserSnapshot) -> Option<ProfileDataMode> {
|
||||||
|
snapshot.profiles.iter().find(|profile| profile.id() == tab.profile_id()).map(|profile| {
|
||||||
|
match profile.kind() {
|
||||||
|
ProfileKind::Standard => ProfileDataMode::Persistent,
|
||||||
|
ProfileKind::Private => ProfileDataMode::Transient,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use ely_domain::{BrowserTab, ProfileId, SpaceId, TabId, UrlText};
|
|||||||
use gpui::{Bounds, point, px, size};
|
use gpui::{Bounds, point, px, size};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
services::ProfileDataMode,
|
||||||
services::prd_live_sites::{
|
services::prd_live_sites::{
|
||||||
LiveSiteCase, PRD_REFERENCE_SITE_CASES, PRD_TOP_SITE_CASES,
|
LiveSiteCase, PRD_REFERENCE_SITE_CASES, PRD_TOP_SITE_CASES,
|
||||||
assert_prd_reference_urls_are_covered,
|
assert_prd_reference_urls_are_covered,
|
||||||
@@ -42,7 +43,7 @@ fn assert_web_surfaces_render(cases: &[LiveSiteCase]) -> Result<(), Box<dyn Erro
|
|||||||
|
|
||||||
assert!(store.record_viewport_size(tab.id(), bounds), "{}", case.url);
|
assert!(store.record_viewport_size(tab.id(), bounds), "{}", case.url);
|
||||||
let request = store
|
let request = store
|
||||||
.prepare_request(&tab)
|
.prepare_request(&tab, ProfileDataMode::Persistent)
|
||||||
.ok_or_else(|| format!("missing web surface request for {}", case.url))?;
|
.ok_or_else(|| format!("missing web surface request for {}", case.url))?;
|
||||||
let snapshot = request.client.snapshot(request.snapshot_request)?;
|
let snapshot = request.client.snapshot(request.snapshot_request)?;
|
||||||
let frame = WebSurfaceFrame::from_snapshot(
|
let frame = WebSurfaceFrame::from_snapshot(
|
||||||
|
|||||||
Reference in New Issue
Block a user