Migrations and initial data stuff

This commit is contained in:
Gregory Schier
2023-02-25 16:39:18 -08:00
parent ba3b899115
commit 93105a3e89
17 changed files with 1082 additions and 129 deletions

177
src-tauri/Cargo.lock generated
View File

@@ -59,6 +59,15 @@ dependencies = [
"alloc-no-stdlib",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.69"
@@ -295,6 +304,22 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"serde",
"time 0.1.45",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "cocoa"
version = "0.24.1"
@@ -326,6 +351,16 @@ dependencies = [
"objc",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@@ -504,6 +539,50 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "cxx"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf"
[[package]]
name = "cxxbridge-macro"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "darling"
version = "0.13.4"
@@ -600,9 +679,9 @@ dependencies = [
[[package]]
name = "deno_core"
version = "0.171.0"
version = "0.173.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc41944f05dfeacfc2610e91f40ddcf246f3aeeac8ae4c26df46bfbf01a3902"
checksum = "e3f5ea1db875ff1eb020c04b900f75c810a9b66deec4a5437205b868bff9a7df"
dependencies = [
"anyhow",
"bytes",
@@ -625,9 +704,9 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.49.0"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4740bc5738ad07dc1f523a232a4079a995fa2ad11efd71e09e8e32bf28f21ee1"
checksum = "1d06332c139917f0fe6722e6c9bd3aac45bfdf3e306627e7eb681a42bad56497"
dependencies = [
"once_cell",
"pmutil",
@@ -736,6 +815,9 @@ name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
dependencies = [
"serde",
]
[[package]]
name = "embed_plist"
@@ -1432,6 +1514,30 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
dependencies = [
"cxx",
"cxx-build",
]
[[package]]
name = "ico"
version = "0.1.0"
@@ -1786,6 +1892,15 @@ dependencies = [
"safemem",
]
[[package]]
name = "link-cplusplus"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
[[package]]
name = "lock_api"
version = "0.4.9"
@@ -2426,7 +2541,7 @@ dependencies = [
"line-wrap",
"quick-xml",
"serde",
"time",
"time 0.3.17",
]
[[package]]
@@ -2842,6 +2957,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
version = "0.7.0"
@@ -3003,9 +3124,9 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.82.0"
version = "0.84.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c060fd38f18c420e82ab21592ec1f088b39bccb6897b1dda394d63628e22158d"
checksum = "94c6b0ea68c2368070520883b5caac9b5bff17597cfac77aebc07280e8585f7f"
dependencies = [
"bytes",
"derive_more",
@@ -3221,6 +3342,7 @@ dependencies = [
"bitflags",
"byteorder",
"bytes",
"chrono",
"crc",
"crossbeam-queue",
"dotenvy",
@@ -3245,12 +3367,15 @@ dependencies = [
"percent-encoding",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"sha2",
"smallvec",
"sqlformat",
"sqlx-rt",
"stringprep",
"thiserror",
"time 0.3.17",
"tokio-stream",
"url",
"webpki-roots",
@@ -3265,9 +3390,12 @@ dependencies = [
"dotenvy",
"either",
"heck 0.4.1",
"hex",
"once_cell",
"proc-macro2",
"quote",
"serde",
"serde_json",
"sha2",
"sqlx-core",
"sqlx-rt",
@@ -3848,12 +3976,14 @@ dependencies = [
name = "tauri-app"
version = "0.0.0"
dependencies = [
"chrono",
"cocoa",
"deno_ast",
"deno_core",
"futures",
"http",
"objc",
"rand 0.8.5",
"reqwest",
"serde",
"serde_json",
@@ -3861,6 +3991,7 @@ dependencies = [
"tauri",
"tauri-build",
"tokio",
"uuid 1.3.0",
]
[[package]]
@@ -3900,7 +4031,7 @@ dependencies = [
"sha2",
"tauri-utils",
"thiserror",
"time",
"time 0.3.17",
"uuid 1.3.0",
"walkdir",
]
@@ -4013,6 +4144,15 @@ dependencies = [
"utf-8",
]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "text_lines"
version = "0.6.0"
@@ -4058,6 +4198,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "time"
version = "0.3.17"
@@ -4386,9 +4537,9 @@ dependencies = [
[[package]]
name = "v8"
version = "0.60.1"
version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07fd5b3ed559897ff02c0f62bc0a5f300bfe79bb4c77a50031b8df771701c628"
checksum = "547e58962ac268fe0b1fbfb653ed341a08e3953994f7f7c978e46ec30afdf8f0"
dependencies = [
"bitflags",
"fslock",
@@ -4453,6 +4604,12 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View File

@@ -13,18 +13,21 @@ edition = "2021"
tauri-build = { version = "1.2", features = [] }
[dependencies]
serde_json = { version = "1.0" }
serde_json = { version = "1.0", features = ["raw_value"] }
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.2", features = ["config-toml", "devtools", "shell-open", "system-tray", "window-start-dragging"] }
http = { version = "0.2.8" }
reqwest = { version = "0.11.14", features = ["json"] }
tokio = { version = "1.25.0", features = [ "sync"] }
tokio = { version = "1.25.0", features = ["sync"] }
futures = { version = "0.3.26" }
deno_core = { version = "0.171.0" }
deno_core = { version = "0.173.0" }
deno_ast = { version = "0.24.0", features = ["transpiling"] }
objc = { version = "0.2.7" }
cocoa = { version = "0.24.1" }
sqlx = { version = "0.6.2", features = ["sqlite", "runtime-tokio-rustls"] }
sqlx = { version = "0.6.2", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time", "offline"] }
uuid = { version = "1.3.0" }
rand = { version = "0.8.5" }
chrono = { version = "0.4.23", features = ["serde"] }
[features]
# by default Tauri runs in production mode

View File

@@ -1,3 +1,3 @@
fn main() {
tauri_build::build()
tauri_build::build()
}

View File

@@ -0,0 +1,38 @@
CREATE TABLE workspaces
(
id TEXT NOT NULL PRIMARY KEY,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME,
name TEXT NOT NULL,
description TEXT NOT NULL
);
CREATE TABLE requests
(
id TEXT NOT NULL PRIMARY KEY,
workspace_id TEXT NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME,
name TEXT NOT NULL,
url TEXT NOT NULL,
method TEXT NOT NULL,
headers TEXT NOT NULL,
body TEXT
);
CREATE TABLE responses
(
id TEXT NOT NULL PRIMARY KEY,
request_id TEXT NOT NULL REFERENCES requests (id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces (id) ON DELETE CASCADE,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME,
elapsed INTEGER NOT NULL,
status INTEGER NOT NULL,
status_reason TEXT NOT NULL,
body TEXT NOT NULL,
headers TEXT NOT NULL
);

View File

@@ -2,4 +2,4 @@ console.log('---------------------------');
console.log('- 👋 Hello from plugin.ts -');
console.log('---------------------------');
Deno.core.ops.op_hello('World');
Deno.core.opAsync('op_hello', 'World');

263
src-tauri/sqlx-data.json Normal file
View File

@@ -0,0 +1,263 @@
{
"db": "SQLite",
"74850a49fa21f4cb5f30905b8ede1fa76935c1ff7ad13c105c6de772d10ff742": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 6
}
},
"query": "\n INSERT INTO requests (id, workspace_id, name, url, method, body, updated_at, headers)\n VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, '{}')\n ON CONFLICT (id) DO UPDATE SET\n name = excluded.name,\n method = excluded.method,\n body = excluded.body,\n url = excluded.url;\n "
},
"8069c0bd326f659faca7b45b03e5317d7339a168f4cd7776d9f84304bb7ae7ac": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 1,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "deleted_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "name",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "description",
"ordinal": 5,
"type_info": "Text"
}
],
"nullable": [
false,
false,
false,
true,
false,
false
],
"parameters": {
"Right": 0
}
},
"query": "\n SELECT id, created_at, updated_at, deleted_at, name, description\n FROM workspaces\n "
},
"d461b9471bdc1fd3f85ca9351f686def07634b4906c8429eeef343b11992b445": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "workspace_id",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "deleted_at",
"ordinal": 4,
"type_info": "Datetime"
},
{
"name": "name",
"ordinal": 5,
"type_info": "Text"
},
{
"name": "url",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "method",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "body",
"ordinal": 8,
"type_info": "Text"
},
{
"name": "headers",
"ordinal": 9,
"type_info": "Text"
}
],
"nullable": [
false,
false,
false,
false,
true,
false,
false,
false,
true,
false
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT id, workspace_id, created_at, updated_at, deleted_at, name, url, method, body, headers\n FROM requests\n WHERE id = ?\n "
},
"da08ebedec0942fd5c54ed1e180d7dc399629f83bfa1341c1c09a048123adac1": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "workspace_id",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "deleted_at",
"ordinal": 4,
"type_info": "Datetime"
},
{
"name": "name",
"ordinal": 5,
"type_info": "Text"
},
{
"name": "url",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "method",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "body",
"ordinal": 8,
"type_info": "Text"
},
{
"name": "headers",
"ordinal": 9,
"type_info": "Text"
}
],
"nullable": [
false,
false,
false,
false,
true,
false,
false,
false,
true,
false
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT id, workspace_id, created_at, updated_at, deleted_at, name, url, method, body, headers\n FROM requests\n WHERE workspace_id = ?;\n "
},
"f116d8cf9aad828135bb8c3a4c8b8e6b857ae13303989e9133a33b2d1cf20e96": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 3
}
},
"query": "\n INSERT INTO workspaces (id, name, description)\n VALUES (?, ?, ?)\n "
},
"fa5011146663ba5675764f33bf55a86b8274aa18737aff427fd1e3fb74ef3535": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 1,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "deleted_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "name",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "description",
"ordinal": 5,
"type_info": "Text"
}
],
"nullable": [
false,
false,
false,
true,
false,
false
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT id, created_at, updated_at, deleted_at, name, description\n FROM workspaces\n WHERE id = ?\n "
}
}

View File

@@ -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
View 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)
)
}

View File

@@ -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(' ');

View File

@@ -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?
}