mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 15:34:09 +01:00
Migrations and initial data stuff
This commit is contained in:
@@ -9,81 +9,25 @@ extern crate objc;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::create_dir_all;
|
||||
use tokio::sync::Mutex;
|
||||
use std::path::Path;
|
||||
|
||||
use http::header::{HeaderName, USER_AGENT};
|
||||
use http::{HeaderMap, HeaderValue, Method};
|
||||
use reqwest::redirect::Policy;
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::SqlitePoolOptions;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use tauri::{AppHandle, State, Wry};
|
||||
use tauri::{CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, WindowEvent};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::models::{create_workspace, find_workspaces, Request, Workspace};
|
||||
use window_ext::WindowExt;
|
||||
|
||||
mod models;
|
||||
mod runtime;
|
||||
mod window_ext;
|
||||
|
||||
fn main() {
|
||||
// here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label.
|
||||
let quit = CustomMenuItem::new("quit".to_string(), "Quit");
|
||||
let tray_menu = SystemTrayMenu::new().add_item(quit);
|
||||
let system_tray = SystemTray::new().with_menu(tray_menu);
|
||||
|
||||
tauri::Builder::default()
|
||||
.system_tray(system_tray)
|
||||
.setup(|app| {
|
||||
let win = app.get_window("main").unwrap();
|
||||
win.position_traffic_lights();
|
||||
Ok(())
|
||||
})
|
||||
.setup(|app| {
|
||||
let dir = app.path_resolver().app_data_dir().unwrap();
|
||||
create_dir_all(dir.clone()).expect("Problem creating App directory!");
|
||||
let p = dir.join("db.sqlite");
|
||||
let p_string = p.to_string_lossy().replace(" ", "%20");
|
||||
let url = format!("sqlite://{}?mode=rwc", p_string);
|
||||
println!("DB URL: {}", url);
|
||||
tauri::async_runtime::block_on(async move {
|
||||
let pool = SqlitePoolOptions::new()
|
||||
.connect(url.as_str())
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
app.manage(Mutex::new(pool));
|
||||
println!("CONNECTED!");
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.on_system_tray_event(|app, event| match event {
|
||||
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
|
||||
"quit" => {
|
||||
std::process::exit(0);
|
||||
}
|
||||
"hide" => {
|
||||
let window = app.get_window("main").unwrap();
|
||||
window.hide().unwrap();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
})
|
||||
.on_window_event(|e| {
|
||||
let apply_offset = || {
|
||||
let win = e.window();
|
||||
win.position_traffic_lights();
|
||||
};
|
||||
|
||||
match e.event() {
|
||||
WindowEvent::Resized(..) => apply_offset(),
|
||||
WindowEvent::ThemeChanged(..) => apply_offset(),
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![send_request, greet, load_db,])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct CustomResponse {
|
||||
status: u16,
|
||||
@@ -98,18 +42,11 @@ pub struct CustomResponse {
|
||||
|
||||
#[tauri::command]
|
||||
async fn load_db(db_instance: State<'_, Mutex<Pool<Sqlite>>>) -> Result<(), String> {
|
||||
println!("INITIALIZING DB");
|
||||
sqlx::query(
|
||||
"CREATE TABLE IF NOT EXISTS responses (
|
||||
id INTEGER PRIMARY KEY,
|
||||
body TEXT NOT NULL,
|
||||
status INT NOT NULL
|
||||
)",
|
||||
)
|
||||
.execute(&*db_instance.lock().await)
|
||||
.await
|
||||
.expect("Failed to create table");
|
||||
|
||||
let pool = &*db_instance.lock().await;
|
||||
let m = Migrator::new(Path::new("./migrations"))
|
||||
.await
|
||||
.expect("Failed to load migrations");
|
||||
m.run(pool).await.expect("Failed to run migrations");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -142,9 +79,7 @@ async fn send_request(
|
||||
);
|
||||
|
||||
let m = Method::from_bytes(method.to_uppercase().as_bytes()).unwrap();
|
||||
let builder = client
|
||||
.request(m, abs_url.to_string())
|
||||
.headers(headers);
|
||||
let builder = client.request(m, abs_url.to_string()).headers(headers);
|
||||
|
||||
let req = match body {
|
||||
Some(b) => builder.body(b.to_string()).build(),
|
||||
@@ -160,7 +95,6 @@ async fn send_request(
|
||||
};
|
||||
|
||||
let resp = client.execute(req).await;
|
||||
|
||||
let elapsed = start.elapsed().as_millis();
|
||||
|
||||
let p = app_handle
|
||||
@@ -183,12 +117,6 @@ async fn send_request(
|
||||
.collect::<HashMap<String, String>>();
|
||||
let body = v.text().await.unwrap();
|
||||
let elapsed2 = start.elapsed().as_millis();
|
||||
sqlx::query("INSERT INTO responses (body, status) VALUES (?, ?)")
|
||||
.bind(body.clone())
|
||||
.bind(status.clone())
|
||||
.execute(&*db_instance.lock().await)
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(CustomResponse {
|
||||
status,
|
||||
status_reason,
|
||||
@@ -207,7 +135,122 @@ async fn send_request(
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn upsert_request(
|
||||
id: Option<&str>,
|
||||
workspace_id: &str,
|
||||
name: &str,
|
||||
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
|
||||
) -> Result<Request, String> {
|
||||
let pool = &*db_instance.lock().await;
|
||||
models::upsert_request(
|
||||
id,
|
||||
workspace_id,
|
||||
name,
|
||||
"GET",
|
||||
None,
|
||||
"https://google.com",
|
||||
pool,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn requests(
|
||||
workspace_id: &str,
|
||||
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
|
||||
) -> Result<Vec<Request>, String> {
|
||||
let pool = &*db_instance.lock().await;
|
||||
models::find_requests(workspace_id, pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn workspaces(db_instance: State<'_, Mutex<Pool<Sqlite>>>) -> Result<Vec<Workspace>, String> {
|
||||
let pool = &*db_instance.lock().await;
|
||||
let workspaces = find_workspaces(pool)
|
||||
.await
|
||||
.expect("Failed to find workspaces");
|
||||
if workspaces.is_empty() {
|
||||
let workspace = create_workspace("Default", "This is the default workspace", pool)
|
||||
.await
|
||||
.expect("Failed to create workspace");
|
||||
Ok(vec![workspace])
|
||||
} else {
|
||||
Ok(workspaces)
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label.
|
||||
let quit = CustomMenuItem::new("quit".to_string(), "Quit");
|
||||
let tray_menu = SystemTrayMenu::new().add_item(quit);
|
||||
let system_tray = SystemTray::new().with_menu(tray_menu);
|
||||
|
||||
tauri::Builder::default()
|
||||
.system_tray(system_tray)
|
||||
.setup(|app| {
|
||||
let win = app.get_window("main").unwrap();
|
||||
win.position_traffic_lights();
|
||||
Ok(())
|
||||
})
|
||||
.setup(|app| {
|
||||
let dir = app.path_resolver().app_data_dir().unwrap();
|
||||
create_dir_all(dir.clone()).expect("Problem creating App directory!");
|
||||
let p = dir.join("db.sqlite");
|
||||
let p_string = p.to_string_lossy().replace(" ", "%20");
|
||||
let url = format!("sqlite://{}?mode=rwc", p_string);
|
||||
println!("DB PATH: {}", p_string);
|
||||
tauri::async_runtime::block_on(async move {
|
||||
let pool = SqlitePoolOptions::new()
|
||||
.connect(url.as_str())
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
app.manage(Mutex::new(pool));
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.on_system_tray_event(|app, event| {
|
||||
if let SystemTrayEvent::MenuItemClick { id, .. } = event {
|
||||
match id.as_str() {
|
||||
"quit" => {
|
||||
std::process::exit(0);
|
||||
}
|
||||
"hide" => {
|
||||
let window = app.get_window("main").unwrap();
|
||||
window.hide().unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_window_event(|e| {
|
||||
let apply_offset = || {
|
||||
let win = e.window();
|
||||
win.position_traffic_lights();
|
||||
};
|
||||
|
||||
match e.event() {
|
||||
WindowEvent::Resized(..) => apply_offset(),
|
||||
WindowEvent::ThemeChanged(..) => apply_offset(),
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
send_request,
|
||||
greet,
|
||||
load_db,
|
||||
workspaces,
|
||||
requests,
|
||||
upsert_request,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
169
src-tauri/src/models.rs
Normal file
169
src-tauri/src/models.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::types::chrono::NaiveDateTime;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Workspace {
|
||||
pub id: String,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
pub deleted_at: Option<NaiveDateTime>,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Request {
|
||||
pub id: String,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
pub deleted_at: Option<NaiveDateTime>,
|
||||
pub workspace_id: String,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub method: String,
|
||||
pub body: Option<String>,
|
||||
pub headers: String,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Response {
|
||||
pub id: String,
|
||||
pub workspace_id: String,
|
||||
pub request_id: String,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
pub deleted_at: Option<NaiveDateTime>,
|
||||
pub name: String,
|
||||
pub status: u16,
|
||||
pub status_reason: Option<&'static str>,
|
||||
pub body: String,
|
||||
pub url: String,
|
||||
pub method: String,
|
||||
pub elapsed: u128,
|
||||
pub elapsed2: u128,
|
||||
pub headers: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub async fn find_workspaces(pool: &Pool<Sqlite>) -> Result<Vec<Workspace>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Workspace,
|
||||
r#"
|
||||
SELECT id, created_at, updated_at, deleted_at, name, description
|
||||
FROM workspaces
|
||||
"#,
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_workspace(id: &str, pool: &Pool<Sqlite>) -> Result<Workspace, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Workspace,
|
||||
r#"
|
||||
SELECT id, created_at, updated_at, deleted_at, name, description
|
||||
FROM workspaces
|
||||
WHERE id = ?
|
||||
"#,
|
||||
id,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_workspace(
|
||||
name: &str,
|
||||
description: &str,
|
||||
pool: &Pool<Sqlite>,
|
||||
) -> Result<Workspace, sqlx::Error> {
|
||||
let id = generate_id("wrk");
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO workspaces (id, name, description)
|
||||
VALUES (?, ?, ?)
|
||||
"#,
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.expect("Failed to insert new workspace");
|
||||
|
||||
get_workspace(&id, pool).await
|
||||
}
|
||||
|
||||
pub async fn upsert_request(
|
||||
id: Option<&str>,
|
||||
workspace_id: &str,
|
||||
name: &str,
|
||||
method: &str,
|
||||
body: Option<&str>,
|
||||
url: &str,
|
||||
pool: &Pool<Sqlite>,
|
||||
) -> Result<Request, sqlx::Error> {
|
||||
let id = generate_id("wrk");
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO requests (id, workspace_id, name, url, method, body, updated_at, headers)
|
||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, '{}')
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
name = excluded.name,
|
||||
method = excluded.method,
|
||||
body = excluded.body,
|
||||
url = excluded.url;
|
||||
"#,
|
||||
id,
|
||||
workspace_id,
|
||||
name,
|
||||
url,
|
||||
method,
|
||||
body,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.expect("Failed to insert new request");
|
||||
get_request(&id, pool).await
|
||||
}
|
||||
|
||||
pub async fn find_requests(
|
||||
workspace_id: &str,
|
||||
pool: &Pool<Sqlite>,
|
||||
) -> Result<Vec<Request>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Request,
|
||||
r#"
|
||||
SELECT id, workspace_id, created_at, updated_at, deleted_at, name, url, method, body, headers
|
||||
FROM requests
|
||||
WHERE workspace_id = ?;
|
||||
"#,
|
||||
workspace_id,
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_request(id: &str, pool: &Pool<Sqlite>) -> Result<Request, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Request,
|
||||
r#"
|
||||
SELECT id, workspace_id, created_at, updated_at, deleted_at, name, url, method, body, headers
|
||||
FROM requests
|
||||
WHERE id = ?
|
||||
"#,
|
||||
id,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
fn generate_id(prefix: &str) -> String {
|
||||
format!(
|
||||
"{prefix}_{}",
|
||||
Alphanumeric.sample_string(&mut rand::thread_rng(), 10)
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
(function (globalThis) {
|
||||
Deno.core.initializeAsyncOps();
|
||||
// Deno.core.print(Object.keys(Deno.core).join('\n'));
|
||||
|
||||
function argsToMessage(...args) {
|
||||
return args.map((arg) => JSON.stringify(arg)).join(' ');
|
||||
|
||||
@@ -24,12 +24,18 @@ pub async fn run_plugin(file_path: &str) -> Result<(), AnyError> {
|
||||
|
||||
runtime
|
||||
.execute_script("<runtime>", include_str!("runtime.js"))
|
||||
.unwrap();
|
||||
.expect("Failed to execute runtime.js");
|
||||
|
||||
let main_module = deno_core::resolve_path(file_path)?;
|
||||
let mod_id = runtime.load_main_module(&main_module, None).await?;
|
||||
let main_module = deno_core::resolve_path(file_path).expect("Failed to resolve path");
|
||||
let mod_id = runtime
|
||||
.load_main_module(&main_module, None)
|
||||
.await
|
||||
.expect("Failed to load main module");
|
||||
let result = runtime.mod_evaluate(mod_id);
|
||||
runtime.run_event_loop(false).await?;
|
||||
runtime
|
||||
.run_event_loop(false)
|
||||
.await
|
||||
.expect("Failed to run event loop");
|
||||
result.await?
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user