Skip to content

Commit

Permalink
Beta channel updates
Browse files Browse the repository at this point in the history
  • Loading branch information
gschier committed Nov 14, 2023
1 parent 11f5541 commit da414de
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 45 deletions.
105 changes: 72 additions & 33 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -32,16 +32,16 @@ use window_ext::TrafficLightWindowExt;
use crate::analytics::{AnalyticsAction, AnalyticsResource, track_event};
use crate::plugin::{ImportResources, ImportResult};
use crate::send::actually_send_request;
use crate::updates::YaakUpdater;
use crate::updates::{update_mode_from_str, UpdateMode, YaakUpdater};

mod analytics;
mod models;
mod plugin;
mod render;
mod send;
mod updates;
mod window_ext;
mod window_menu;
mod updates;
mod send;

#[derive(serde::Serialize)]
pub struct CustomResponse {
Expand Down Expand Up @@ -100,7 +100,7 @@ async fn import_data(
plugin_name,
file_paths.first().unwrap(),
)
.await
.await
{
result = Some(r);
break;
Expand Down Expand Up @@ -196,8 +196,12 @@ async fn send_request(
let pool2 = pool.clone();

tokio::spawn(async move {
if let Err(e) = actually_send_request(req, &response2, &environment_id2, &app_handle2, &pool2).await {
response_err(&response2, e, &app_handle2, &pool2).await.expect("Failed to update response");
if let Err(e) =
actually_send_request(req, &response2, &environment_id2, &app_handle2, &pool2).await
{
response_err(&response2, e, &app_handle2, &pool2)
.await
.expect("Failed to update response");
}
});

Expand All @@ -220,6 +224,15 @@ async fn response_err(
Ok(response)
}

#[tauri::command]
async fn set_update_mode(
update_mode: &str,
window: Window<Wry>,
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<models::KeyValue, String> {
set_key_value("app", "update_mode", update_mode, window, db_instance).await
}

#[tauri::command]
async fn get_key_value(
namespace: &str,
Expand Down Expand Up @@ -263,8 +276,8 @@ async fn create_workspace(
..Default::default()
},
)
.await
.expect("Failed to create Workspace");
.await
.expect("Failed to create Workspace");

emit_and_return(&window, "created_model", created_workspace)
}
Expand All @@ -287,8 +300,8 @@ async fn create_environment(
..Default::default()
},
)
.await
.expect("Failed to create environment");
.await
.expect("Failed to create environment");

emit_and_return(&window, "created_model", created_environment)
}
Expand All @@ -314,8 +327,8 @@ async fn create_request(
..Default::default()
},
)
.await
.expect("Failed to create request");
.await
.expect("Failed to create request");

emit_and_return(&window, "created_model", created_request)
}
Expand Down Expand Up @@ -420,8 +433,8 @@ async fn create_folder(
..Default::default()
},
)
.await
.expect("Failed to create folder");
.await
.expect("Failed to create folder");

emit_and_return(&window, "created_model", created_request)
}
Expand Down Expand Up @@ -586,8 +599,8 @@ async fn list_workspaces(
..Default::default()
},
)
.await
.expect("Failed to create Workspace");
.await
.expect("Failed to create Workspace");
Ok(vec![workspace])
} else {
Ok(workspaces)
Expand All @@ -614,9 +627,19 @@ async fn delete_workspace(
}

#[tauri::command]
async fn check_for_updates(app_handle: AppHandle<Wry>, yaak_updater: State<'_, Mutex<YaakUpdater>>,
async fn check_for_updates(
app_handle: AppHandle<Wry>,
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
yaak_updater: State<'_, Mutex<YaakUpdater>>,
) -> Result<(), String> {
yaak_updater.lock().await.check(&app_handle).await.map_err(|e| e.to_string())
let pool = &*db_instance.lock().await;
let update_mode = get_update_mode(pool).await;
yaak_updater
.lock()
.await
.force_check(&app_handle, update_mode)
.await
.map_err(|e| e.to_string())
}

fn main() {
Expand Down Expand Up @@ -659,7 +682,6 @@ fn main() {
.expect("Failed to migrate database");
app.manage(m);


let yaak_updater = YaakUpdater::new();
app.manage(Mutex::new(yaak_updater));

Expand Down Expand Up @@ -697,6 +719,7 @@ fn main() {
send_ephemeral_request,
send_request,
set_key_value,
set_update_mode,
update_environment,
update_folder,
update_request,
Expand Down Expand Up @@ -740,12 +763,19 @@ fn main() {
None,
);
}
RunEvent::WindowEvent { label: _label, event: WindowEvent::Focused(true), .. } => {
RunEvent::WindowEvent {
label: _label,
event: WindowEvent::Focused(true),
..
} => {
let h = app_handle.clone();
// Run update check whenever window is focused
tauri::async_runtime::spawn(async move {
let val: State<'_, Mutex<YaakUpdater>> = h.state();
_ = val.lock().await.check(&h).await;
let db_instance: State<'_, Mutex<Pool<Sqlite>>> = h.state();
let pool = &*db_instance.lock().await;
let update_mode = get_update_mode(pool).await;
_ = val.lock().await.check(&h, update_mode).await;
});
}
_ => {}
Expand Down Expand Up @@ -783,16 +813,16 @@ fn create_window(handle: &AppHandle<Wry>, url: Option<&str>) -> Window<Wry> {
window_id,
WindowUrl::App(url.unwrap_or_default().into()),
)
.menu(app_menu)
.fullscreen(false)
.resizable(true)
.inner_size(1100.0, 600.0)
.position(
// Randomly offset so windows don't stack exactly
100.0 + random::<f64>() * 30.0,
100.0 + random::<f64>() * 30.0,
)
.title(handle.package_info().name.to_string());
.menu(app_menu)
.fullscreen(false)
.resizable(true)
.inner_size(1100.0, 600.0)
.position(
// Randomly offset so windows don't stack exactly
100.0 + random::<f64>() * 30.0,
100.0 + random::<f64>() * 30.0,
)
.title(handle.package_info().name.to_string());

// Add macOS-only things
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -868,3 +898,12 @@ fn emit_and_return<S: Serialize + Clone, E>(
fn emit_side_effect<S: Serialize + Clone>(app_handle: &AppHandle<Wry>, event: &str, payload: S) {
app_handle.emit_all(event, &payload).unwrap();
}

async fn get_update_mode(pool: &Pool<Sqlite>) -> UpdateMode {
let mode = models::get_key_value_string("app", "update_mode", pool)
.await;
match mode {
Some(mode) => update_mode_from_str(&mode),
None => UpdateMode::Stable,
}
}
12 changes: 12 additions & 0 deletions src-tauri/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ pub async fn get_key_value(namespace: &str, key: &str, pool: &Pool<Sqlite>) -> O
.ok()
}

pub async fn get_key_value_string(namespace: &str, key: &str, pool: &Pool<Sqlite>) -> Option<String> {
let kv = get_key_value(namespace, key, pool).await?;
let result = serde_json::from_str(&kv.value);
match result {
Ok(v) => Some(v),
Err(e) => {
println!("Failed to parse key value: {}", e);
None
}
}
}

pub async fn find_workspaces(pool: &Pool<Sqlite>) -> Result<Vec<Workspace>, sqlx::Error> {
sqlx::query_as!(
Workspace,
Expand Down
50 changes: 44 additions & 6 deletions src-tauri/src/updates.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::time::SystemTime;

use log::info;
use tauri::{AppHandle, updater, Window, Wry};
use tauri::api::dialog;

Expand All @@ -11,19 +12,31 @@ pub struct YaakUpdater {
last_update_check: SystemTime,
}

pub enum UpdateMode {
Stable,
Beta,
}

impl YaakUpdater {
pub fn new() -> Self {
Self {
last_update_check: SystemTime::UNIX_EPOCH,
}
}
pub async fn check(&mut self, app_handle: &AppHandle<Wry>) -> Result<(), updater::Error> {
if self.last_update_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS {
return Ok(());
}

pub async fn force_check(
&mut self,
app_handle: &AppHandle<Wry>,
mode: UpdateMode,
) -> Result<(), updater::Error> {
self.last_update_check = SystemTime::now();
match app_handle.updater().check().await {
let update_mode = get_update_mode_str(mode);
info!("Checking for updates mode={}", update_mode);
match app_handle
.updater()
.header("X-Update-Mode", update_mode)?
.check()
.await
{
Ok(update) => {
if dialog::blocking::ask(
None::<&Window>,
Expand All @@ -38,4 +51,29 @@ impl YaakUpdater {
Err(e) => Err(e),
}
}
pub async fn check(
&mut self,
app_handle: &AppHandle<Wry>,
mode: UpdateMode,
) -> Result<(), updater::Error> {
if self.last_update_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS {
return Ok(());
}

self.force_check(app_handle, mode).await
}
}

pub fn update_mode_from_str(mode: &str) -> UpdateMode {
match mode {
"beta" => UpdateMode::Beta,
_ => UpdateMode::Stable,
}
}

fn get_update_mode_str(mode: UpdateMode) -> &'static str {
match mode {
UpdateMode::Stable => "stable",
UpdateMode::Beta => "beta",
}
}
29 changes: 23 additions & 6 deletions src-web/components/WorkspaceActionsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useImportData } from '../hooks/useImportData';
import { usePrompt } from '../hooks/usePrompt';
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
import { useTheme } from '../hooks/useTheme';
import { useUpdateMode } from '../hooks/useUpdateMode';
import { useUpdateWorkspace } from '../hooks/useUpdateWorkspace';
import { useWorkspaces } from '../hooks/useWorkspaces';
import type { ButtonProps } from './core/Button';
Expand Down Expand Up @@ -39,6 +40,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const dialog = useDialog();
const prompt = usePrompt();
const routes = useAppRoutes();
const [updateMode, setUpdateMode] = useUpdateMode();

const items: DropdownItem[] = useMemo(() => {
const workspaceItems: DropdownItem[] = workspaces.map((w) => ({
Expand Down Expand Up @@ -145,12 +147,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
createWorkspace.mutate({ name });
},
},
{
key: 'appearance',
label: 'Toggle Theme',
onSelect: toggleAppearance,
leftSlot: <Icon icon={appearance === 'dark' ? 'sun' : 'moon'} />,
},
{
key: 'import-data',
label: 'Import Data',
Expand All @@ -163,6 +159,25 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
leftSlot: <Icon icon="upload" />,
onSelect: () => exportData.mutate(),
},
{ type: 'separator' },
{
key: 'appearance',
label: 'Toggle Theme',
onSelect: toggleAppearance,
leftSlot: <Icon icon={appearance === 'dark' ? 'sun' : 'moon'} />,
},
{
key: 'update-mode',
label: updateMode === 'stable' ? 'Enable Beta' : 'Disable Beta',
onSelect: () => setUpdateMode(updateMode === 'stable' ? 'beta' : 'stable'),
leftSlot: <Icon icon="camera" />,
},
{
key: 'update-check',
label: 'Check for Updates',
onSelect: () => invoke('check_for_updates'),
leftSlot: <Icon icon="update" />,
},
];
}, [
activeWorkspace?.name,
Expand All @@ -175,7 +190,9 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
importData,
prompt,
routes,
setUpdateMode,
toggleAppearance,
updateMode,
updateWorkspace,
workspaces,
]);
Expand Down
12 changes: 12 additions & 0 deletions src-web/hooks/useUpdateMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { NAMESPACE_APP } from '../lib/keyValueStore';
import { useKeyValue } from './useKeyValue';

export function useUpdateMode() {
const kv = useKeyValue<'stable' | 'beta'>({
namespace: NAMESPACE_APP,
key: 'update_mode',
defaultValue: 'stable',
});

return [kv.value, kv.set] as const;
}
Loading

0 comments on commit da414de

Please sign in to comment.