mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-22 14:59:56 +02:00
Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a71a0192b8 | |||
| e7d9efee37 | |||
| dd8bc4ab39 | |||
| 8d6045421a | |||
| c77cbe936d | |||
| 11048fd997 | |||
| f595684ba8 | |||
| d472eebad2 | |||
| c27699ffab | |||
| 68d77f999c | |||
| 1712f27b77 | |||
| 8dd371814a | |||
| 5c3b2f7511 | |||
| 227bf5424a | |||
| c25b7537e3 | |||
| 9e24e52164 | |||
| 444a16ca73 | |||
| cff0cdeaa8 | |||
| 57c1db41a3 | |||
| 6630e5db75 | |||
| 662c61826b | |||
| 44df7726ae | |||
| b4535af927 | |||
| 77b81af36c | |||
| 9b20f28d74 | |||
| 1e56d86b51 | |||
| 07650ca94b | |||
| d68d5cce60 | |||
| faab5f6cee | |||
| 4ecc649839 | |||
| 9f27e6e441 | |||
| 3f0917bd50 | |||
| 9048f80a4e | |||
| ac7390973b | |||
| d5f5d78830 | |||
| 1f799ae25e | |||
| fa32d1afa9 | |||
| f41d3e5e77 | |||
| 9b96996b5a | |||
| 9af4c3727c | |||
| 3d279094d4 | |||
| 6c7a4c0984 | |||
| 1c17161f2a | |||
| 6111c7f3da | |||
| 746067bb70 | |||
| 0623903f12 | |||
| 043de033b0 | |||
| 7432a399db | |||
| 305c5793ae | |||
| 4a39b74d5c | |||
| dc5a14b6ad | |||
| 2b65e0a149 | |||
| beb9095f11 | |||
| 418294b1a3 | |||
| 3febb72f28 | |||
| 90fecadb86 | |||
| 63834d9b63 | |||
| 8654caa26e | |||
| 473991371d | |||
| e98e8eac3d | |||
| 44d8f60e0d | |||
| b04bde3461 | |||
| 0190f68f1d | |||
| 5b85dd22c7 | |||
| 76832e60bf | |||
| 5b814f56e6 | |||
| 6647e6ea90 | |||
| 83148da959 | |||
| e8d7e765e7 | |||
| 76bcecf5b2 | |||
| d49aa664e9 | |||
| bd0d88243a | |||
| f001df870f | |||
| 72a6e3ba68 | |||
| 7e58dc8502 | |||
| ac495b9fb4 | |||
| dacde1629d | |||
| 700549ab02 | |||
| 811b1ec12d | |||
| 174c5e52e3 | |||
| 37d057df61 | |||
| cdb77c4b65 | |||
| e47dca954f | |||
| 94f62d2503 | |||
| ee0d314bb5 | |||
| ae8a581f9a | |||
| 67bff4559d | |||
| d272bde2bb | |||
| 919616d7d3 | |||
| b60b46a0b8 | |||
| 6d8f517148 | |||
| 949c59f8a5 | |||
| b99844706e | |||
| 92514cca47 | |||
| 81fb450c39 | |||
| c3a6dab24c | |||
| 0863f800b8 | |||
| 600ad30756 | |||
| 51f20b438e | |||
| 4fd6b58070 | |||
| c8c6d56d1b | |||
| 2ed0fd716c | |||
| 8286b06198 | |||
| 180ec441aa | |||
| 07f3a89df0 | |||
| c009cb383f | |||
| 00915af7e7 | |||
| c499238892 | |||
| ac6f08f193 | |||
| 84d8a21e55 | |||
| 280f99c5f3 | |||
| 8c10a1b0a7 | |||
| b6ffbe33da | |||
| 2f2da76aa8 | |||
| 9dba680114 | |||
| 2365c46534 | |||
| 01ede23b34 | |||
| a2503b795d | |||
| 65e6870195 | |||
| ec74b2d69a | |||
| 6845cefc82 | |||
| 2a8e168149 | |||
| efcc3df3fe | |||
| 9e440d27ae |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold-js": patch
|
||||
---
|
||||
|
||||
Change the argument name of the `Stronghold.remove` from `location` to `recordPath` to match the Stronghold command argument
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold": patch
|
||||
---
|
||||
|
||||
Added `Builder::with_argon2`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold-js": minor
|
||||
---
|
||||
|
||||
Added `Stronghold.load` and removed its constructor.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"positioner": patch
|
||||
---
|
||||
|
||||
`TrayLeft`, `TrayRight` and `TrayCenter` will now position the window according to the tray position relative to the monitor dimensions to prevent windows being displayed partially off-screen.
|
||||
Generated
+1003
-893
File diff suppressed because it is too large
Load Diff
+25
-17
@@ -10,26 +10,34 @@
|
||||
"format-check": "prettier --check ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.0.2",
|
||||
"@rollup/plugin-terser": "^0.4.1",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
||||
"@typescript-eslint/parser": "^5.58.0",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-standard-with-typescript": "^36.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^16.0.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-security": "^1.7.1",
|
||||
"prettier": "^3.0.0",
|
||||
"rollup": "^3.20.4",
|
||||
"typescript": "^5.0.4"
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-typescript": "11.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "6.9.1",
|
||||
"@typescript-eslint/parser": "6.9.1",
|
||||
"eslint": "8.52.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-config-standard-with-typescript": "39.1.1",
|
||||
"eslint-plugin-import": "2.29.0",
|
||||
"eslint-plugin-n": "16.2.0",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-security": "1.7.1",
|
||||
"prettier": "3.0.3",
|
||||
"rollup": "4.2.0",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"semver": ">=7.5.2"
|
||||
"semver": ">=7.5.2",
|
||||
"optionator": ">=0.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=7.33.0"
|
||||
"pnpm": ">=7.33.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"auditConfig": {
|
||||
"ignoreCves": [
|
||||
"CVE-2023-46115"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ _This plugin requires a Rust version of at least **1.64**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
1. Use crates.io and npm (easiest, and requires you to trust that our publishing pipeline worked)
|
||||
1. Use crates.io and npm (easiest and requires you to trust that our publishing pipeline worked)
|
||||
2. Pull sources directly from Github using git tags / revision hashes (most secure)
|
||||
3. Git submodule install this repo in your tauri project and then use file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
3. Git submodule install this repo in your tauri project and then use the file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
|
||||
Install the Core plugin by adding the following to your `Cargo.toml` file:
|
||||
Install the authenticator plugin by adding the following lines to your `Cargo.toml` file:
|
||||
|
||||
`src-tauri/Cargo.toml`
|
||||
|
||||
@@ -37,7 +37,7 @@ yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v1
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to register the core plugin with Tauri:
|
||||
First, you need to register the authenticator plugin with Tauri:
|
||||
|
||||
`src-tauri/src/main.rs`
|
||||
|
||||
@@ -50,7 +50,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
Afterwards, all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
|
||||
```javascript
|
||||
import { Authenticator } from "tauri-plugin-authenticator-api";
|
||||
@@ -71,7 +71,7 @@ const domain = "https://tauri.app";
|
||||
const json = await auth.register(challenge, domain);
|
||||
const registerResult = JSON.parse(json);
|
||||
|
||||
// verify te registration was successfull
|
||||
// verify the registration was successful
|
||||
const r2 = await auth.verifyRegistration(
|
||||
challenge,
|
||||
app,
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -15,4 +15,4 @@ serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
auto-launch = "0.4"
|
||||
auto-launch = "0.5"
|
||||
@@ -24,9 +24,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -16,4 +16,4 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
notify = { version = "6" , features = ["serde"] }
|
||||
notify-debouncer-mini = { version = "0.3" , features = ["serde"] }
|
||||
notify-debouncer-mini = { version = "0.4" , features = ["serde"] }
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ async fn watch<R: Runtime>(
|
||||
|
||||
let watcher = if let Some(delay) = options.delay_ms {
|
||||
let (tx, rx) = channel();
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), tx)?;
|
||||
let watcher = debouncer.watcher();
|
||||
for path in &paths {
|
||||
watcher.watch(path, mode)?;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
+35
-7
@@ -118,7 +118,7 @@ pub enum LogTarget {
|
||||
///
|
||||
/// The plugin will ensure the directory exists before writing logs.
|
||||
Folder(PathBuf),
|
||||
/// Write logs to the OS specififc logs directory.
|
||||
/// Write logs to the OS specific logs directory.
|
||||
///
|
||||
/// ### Platform-specific
|
||||
///
|
||||
@@ -167,6 +167,7 @@ pub struct Builder {
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
max_file_size: u128,
|
||||
targets: Vec<LogTarget>,
|
||||
log_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
@@ -189,6 +190,7 @@ impl Default for Builder {
|
||||
timezone_strategy: DEFAULT_TIMEZONE_STRATEGY,
|
||||
max_file_size: DEFAULT_MAX_FILE_SIZE,
|
||||
targets: DEFAULT_LOG_TARGETS.into(),
|
||||
log_name: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +264,29 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Writes logs to the given file. Default: <app_name>.log)
|
||||
///
|
||||
/// Note: This does not modify the directory logs go into. For that refer to `LogTarget::Folder`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tauri_plugin_log::Builder;
|
||||
/// let name = "custom-name";
|
||||
/// let builder = Builder::default()
|
||||
/// .targets([
|
||||
/// LogTarget::LogDir
|
||||
/// ])
|
||||
/// .log_name(name)
|
||||
/// .build()
|
||||
/// ); // Outputs content to custom-name.log
|
||||
///
|
||||
/// ```
|
||||
pub fn log_name<S: Into<String>>(mut self, log_name: S) -> Self {
|
||||
self.log_name = Some(log_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "colored")]
|
||||
pub fn with_colors(self, colors: fern::colors::ColoredLevelConfig) -> Self {
|
||||
let format =
|
||||
@@ -284,7 +309,10 @@ impl Builder {
|
||||
plugin::Builder::new("log")
|
||||
.invoke_handler(tauri::generate_handler![log])
|
||||
.setup(move |app_handle| {
|
||||
let app_name = &app_handle.package_info().name;
|
||||
let log_name = self
|
||||
.log_name
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| &app_handle.package_info().name);
|
||||
|
||||
// setup targets
|
||||
for target in &self.targets {
|
||||
@@ -298,7 +326,7 @@ impl Builder {
|
||||
|
||||
fern::log_file(get_log_file_path(
|
||||
&path,
|
||||
app_name,
|
||||
log_name,
|
||||
&self.rotation_strategy,
|
||||
&self.timezone_strategy,
|
||||
self.max_file_size,
|
||||
@@ -313,7 +341,7 @@ impl Builder {
|
||||
|
||||
fern::log_file(get_log_file_path(
|
||||
&path,
|
||||
app_name,
|
||||
log_name,
|
||||
&self.rotation_strategy,
|
||||
&self.timezone_strategy,
|
||||
self.max_file_size,
|
||||
@@ -347,12 +375,12 @@ impl Builder {
|
||||
|
||||
fn get_log_file_path(
|
||||
dir: &impl AsRef<Path>,
|
||||
app_name: &str,
|
||||
log_name: &str,
|
||||
rotation_strategy: &RotationStrategy,
|
||||
timezone_strategy: &TimezoneStrategy,
|
||||
max_file_size: u128,
|
||||
) -> plugin::Result<PathBuf> {
|
||||
let path = dir.as_ref().join(format!("{app_name}.log"));
|
||||
let path = dir.as_ref().join(format!("{log_name}.log"));
|
||||
|
||||
if path.exists() {
|
||||
let log_size = File::open(&path)?.metadata()?.len() as u128;
|
||||
@@ -361,7 +389,7 @@ fn get_log_file_path(
|
||||
RotationStrategy::KeepAll => {
|
||||
let to = dir.as_ref().join(format!(
|
||||
"{}_{}.log",
|
||||
app_name,
|
||||
log_name,
|
||||
timezone_strategy
|
||||
.get_now()
|
||||
.format(
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -15,7 +15,7 @@ serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
aho-corasick = "1.0"
|
||||
aho-corasick = "1.1"
|
||||
bincode = "1"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,13 +107,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
},
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayLeft => {
|
||||
if let Some((tray_x, tray_y)) = tray_position {
|
||||
PhysicalPosition {
|
||||
x: tray_x,
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
if let (Some((tray_x, tray_y)), Some((_, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x: tray_x, y }
|
||||
} else {
|
||||
panic!("tray position not set");
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
@@ -129,11 +136,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayRight => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition {
|
||||
x: tray_x + tray_width,
|
||||
y: tray_y - window_size.height,
|
||||
y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
@@ -153,12 +169,19 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayCenter => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
PhysicalPosition {
|
||||
x: tray_x + (tray_width / 2) - (window_size.width / 2),
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
let x = tray_x + tray_width / 2 - window_size.width / 2;
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x, y }
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -9,6 +9,6 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.3"
|
||||
"@tauri-apps/cli": "1.5.5"
|
||||
}
|
||||
}
|
||||
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@tauri-apps/cli': ^1.0.0
|
||||
|
||||
dependencies:
|
||||
'@tauri-apps/cli': 1.0.2
|
||||
|
||||
packages:
|
||||
|
||||
/@tauri-apps/cli-darwin-arm64/1.0.2:
|
||||
resolution: {integrity: sha512-Ahd951yoYon1+WLNBg6xsx6Bb7+GJt7WwC1FllHZ2/iLCbrtWCS2qfeLS0L4ngBqCuWyL35JC/M2LIr9mcUzrg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-darwin-x64/1.0.2:
|
||||
resolution: {integrity: sha512-8wo+SN1zWoXFQVa/iyEt3Cs0vNMjxDXqVe3Srm4UNpgKboFN5mIgbugwqvM+aJKnEZAH8h8n+ZJUHzc4wtPGHA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm-gnueabihf/1.0.2:
|
||||
resolution: {integrity: sha512-PGQghMn0adt9PTnyi2K2o/CLG3tWbOyZvwQjam5cfQbK757WmMgPErC1VqsxiQc+PItWYvqoE9gjANiFc2MpAQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm64-gnu/1.0.2:
|
||||
resolution: {integrity: sha512-Uc+XNlWelrnRh7DYrdxBi8Oam9JAQM1GzgEwjupF6Pv7BwlODN7s0HImGPQOKrEkqzpfmYw7KpfgWiiEjS5/3Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm64-musl/1.0.2:
|
||||
resolution: {integrity: sha512-lVwCG1QzQs2zWP32H4+Dw8NKgJ6hBox2X+bmawGfV9Ce+K4P84bnqfNgpdaSAncjeiTjrO+g7yT9gJFQCOrjlQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-x64-gnu/1.0.2:
|
||||
resolution: {integrity: sha512-G2XmGxvufW9sgGhA3rx+HehcifVTUo8zyISd8DpvGwtpp6Z4WakbivzKFyGiNnnok0nvj/WUrLgBxtUbfdSY+A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-x64-musl/1.0.2:
|
||||
resolution: {integrity: sha512-/eX536p+KXSmkFuINGeU6EQmYiQEXj6JXbmetmJmkXN0297HbtH3rS3wlyVDCnobRzh1hMeOJEnV+XA20GghMA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-win32-ia32-msvc/1.0.2:
|
||||
resolution: {integrity: sha512-ZvnaKkCABqUbyUKlNk4RdxKyfOte30D5BxN1pj6iZNeKAwXEuTcgP6iPzOovdeaDirkIjcWCEZymwtZDXN4Rvg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-win32-x64-msvc/1.0.2:
|
||||
resolution: {integrity: sha512-uMcQyQQD7nyxps34HyYBYUYzFwH26lP58/qdT/GZWvBL1Sv2rqkQXuxHT7xtp4g7nTs0fGRWOtfcnvYIr/1wDw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli/1.0.2:
|
||||
resolution: {integrity: sha512-OJdQJVwtKnTAuv2a9JQlOd0gHbbGsXwT+N6M6YQiXZ3/5WdlXey1zhnD78GXwZsf8Cz0R7QIGTBECO4ur4fnKg==}
|
||||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
'@tauri-apps/cli-darwin-arm64': 1.0.2
|
||||
'@tauri-apps/cli-darwin-x64': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm64-gnu': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm64-musl': 1.0.2
|
||||
'@tauri-apps/cli-linux-x64-gnu': 1.0.2
|
||||
'@tauri-apps/cli-linux-x64-musl': 1.0.2
|
||||
'@tauri-apps/cli-win32-ia32-msvc': 1.0.2
|
||||
'@tauri-apps/cli-win32-x64-msvc': 1.0.2
|
||||
dev: false
|
||||
@@ -17,11 +17,11 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
futures-core = "0.3"
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "json", "time"] }
|
||||
sqlx = { version = "0.7", features = ["json", "time"] }
|
||||
time = "0.3"
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
|
||||
[features]
|
||||
sqlite = ["sqlx/sqlite"]
|
||||
mysql = ["sqlx/mysql"]
|
||||
postgres = ["sqlx/postgres"]
|
||||
sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"]
|
||||
mysql = ["sqlx/mysql", "sqlx/runtime-tokio-rustls"]
|
||||
postgres = ["sqlx/postgres", "sqlx/runtime-tokio-rustls"]
|
||||
|
||||
@@ -65,6 +65,37 @@ const db = await Database.load("postgres://postgres:password@localhost/test");
|
||||
await db.execute("INSERT INTO ...");
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
We use sqlx as our underlying library, adopting their query syntax:
|
||||
|
||||
- sqlite and postgres use the "$#" syntax when substituting query data
|
||||
- mysql uses "?" when substituting query data
|
||||
|
||||
```javascript
|
||||
// INSERT and UPDATE examples for sqlite and postgres
|
||||
const result = await db.execute(
|
||||
"INSERT into todos (id, title, status) VALUES ($1, $2, $3)",
|
||||
[todos.id, todos.title, todos.status],
|
||||
);
|
||||
|
||||
const result = await db.execute(
|
||||
"UPDATE todos SET title = $1, completed = $2 WHERE id = $3",
|
||||
[todos.title, todos.status, todos.id],
|
||||
);
|
||||
|
||||
// INSERT and UPDATE examples for mysql
|
||||
const result = await db.execute(
|
||||
"INSERT into todos (id, title, status) VALUES (?, ?, ?)",
|
||||
[todos.id, todos.title, todos.status],
|
||||
);
|
||||
|
||||
const result = await db.execute(
|
||||
"UPDATE todos SET title = ?, completed = ? WHERE id = ?",
|
||||
[todos.title, todos.status, todos.id],
|
||||
);
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
|
||||
|
||||
@@ -76,10 +76,29 @@ export default class Database {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // for sqlite & postgres
|
||||
* // INSERT example
|
||||
* const result = await db.execute(
|
||||
* "INSERT into todos (id, title, status) VALUES ($1, $2, $3)",
|
||||
* [ todos.id, todos.title, todos.status ]
|
||||
* );
|
||||
* // UPDATE example
|
||||
* const result = await db.execute(
|
||||
* "UPDATE todos SET title = $1, completed = $2 WHERE id = $3",
|
||||
* [ todos.title, todos.status, todos.id ]
|
||||
* );
|
||||
*
|
||||
* // for mysql
|
||||
* // INSERT example
|
||||
* const result = await db.execute(
|
||||
* "INSERT into todos (id, title, status) VALUES (?, ?, ?)",
|
||||
* [ todos.id, todos.title, todos.status ]
|
||||
* );
|
||||
* // UPDATE example
|
||||
* const result = await db.execute(
|
||||
* "UPDATE todos SET title = ?, completed = ? WHERE id = ?",
|
||||
* [ todos.title, todos.status, todos.id ]
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
async execute(query: string, bindValues?: unknown[]): Promise<QueryResult> {
|
||||
@@ -91,13 +110,11 @@ export default class Database {
|
||||
values: bindValues ?? [],
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
lastInsertId,
|
||||
rowsAffected,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* **select**
|
||||
*
|
||||
@@ -105,9 +122,15 @@ export default class Database {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // for sqlite & postgres
|
||||
* const result = await db.select(
|
||||
* "SELECT * from todos WHERE id = $1", id
|
||||
* );
|
||||
*
|
||||
* // for mysql
|
||||
* const result = await db.select(
|
||||
* "SELECT * from todos WHERE id = ?", id
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
async select<T>(query: string, bindValues?: unknown[]): Promise<T> {
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,14 @@ pub(crate) fn to_json(v: MySqlValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT" | "DOUBLE" => {
|
||||
"FLOAT" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DOUBLE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
|
||||
@@ -17,14 +17,35 @@ pub(crate) fn to_json(v: PgValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT4" | "FLOAT8" => {
|
||||
"FLOAT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT2" | "INT4" | "INT8" => {
|
||||
"INT2" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i16>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i32>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -16,10 +16,19 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
iota_stronghold = "1"
|
||||
iota-crypto = "0.21"
|
||||
iota-crypto = "0.23"
|
||||
hex = "0.4"
|
||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||
|
||||
# kdf dependencies
|
||||
rust-argon2 = { version = "1", optional = true }
|
||||
rand_chacha = { version = "0.3.1", optional = true }
|
||||
rand_core = { version = "0.6.4", features = ["getrandom"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
rusty-fork = "0.3"
|
||||
rusty-fork = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["kdf"]
|
||||
kdf = ["dep:rust-argon2", "dep:rand_chacha", "dep:rand_core"]
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use std::path::Path;
|
||||
|
||||
/// NOTE: Hash supplied to Stronghold must be 32bits long.
|
||||
/// This is a current limitation of Stronghold.
|
||||
const HASH_LENGTH: usize = 32;
|
||||
|
||||
pub struct KeyDerivation {}
|
||||
|
||||
impl KeyDerivation {
|
||||
/// Will create a key from [`password`] and a generated salt.
|
||||
/// Salt will be generated to file [`salt_path`] or taken from it
|
||||
/// if file already exists
|
||||
pub fn argon2(password: &str, salt_path: &Path) -> Vec<u8> {
|
||||
let mut salt = [0u8; HASH_LENGTH];
|
||||
create_or_get_salt(&mut salt, salt_path);
|
||||
|
||||
argon2::hash_raw(password.as_bytes(), &salt, &Default::default())
|
||||
.expect("Failed to generate hash for password")
|
||||
}
|
||||
}
|
||||
|
||||
fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
|
||||
if salt_path.is_file() {
|
||||
// Get existing salt
|
||||
let tmp = std::fs::read(salt_path).unwrap();
|
||||
salt.clone_from_slice(&tmp);
|
||||
} else {
|
||||
// Generate new salt
|
||||
let mut gen = ChaCha20Rng::from_entropy();
|
||||
gen.fill_bytes(salt);
|
||||
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ use tauri::{
|
||||
};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "kdf")]
|
||||
pub mod kdf;
|
||||
|
||||
pub mod stronghold;
|
||||
|
||||
type PasswordHashFn = dyn Fn(&str) -> Vec<u8> + Send + Sync;
|
||||
@@ -394,26 +397,70 @@ fn get_client(
|
||||
}
|
||||
}
|
||||
|
||||
enum PasswordHashFunctionKind {
|
||||
#[cfg(feature = "kdf")]
|
||||
Argon2(PathBuf),
|
||||
Custom(Box<PasswordHashFn>),
|
||||
}
|
||||
|
||||
pub struct Builder {
|
||||
password_hash_function: Box<PasswordHashFn>,
|
||||
password_hash_function: PasswordHashFunctionKind,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new<F: Fn(&str) -> Vec<u8> + Send + Sync + 'static>(password_hash_function: F) -> Self {
|
||||
Self {
|
||||
password_hash_function: Box::new(password_hash_function),
|
||||
password_hash_function: PasswordHashFunctionKind::Custom(Box::new(
|
||||
password_hash_function,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes [`Self`] with argon2 as password hash function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let salt_path = app
|
||||
/// .path_resolver()
|
||||
/// .app_local_data_dir()
|
||||
/// .expect("could not resolve app local data path")
|
||||
/// .join("salt.txt");
|
||||
/// app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
#[cfg(feature = "kdf")]
|
||||
pub fn with_argon2(salt_path: &std::path::Path) -> Self {
|
||||
Self {
|
||||
password_hash_function: PasswordHashFunctionKind::Argon2(salt_path.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let password_hash_function = self.password_hash_function;
|
||||
|
||||
PluginBuilder::new("stronghold")
|
||||
.setup(move |app| {
|
||||
app.manage(StrongholdCollection::default());
|
||||
app.manage(PasswordHashFunction(password_hash_function));
|
||||
Ok(())
|
||||
})
|
||||
let plugin_builder = PluginBuilder::new("stronghold").setup(move |app| {
|
||||
app.manage(StrongholdCollection::default());
|
||||
app.manage(PasswordHashFunction(match password_hash_function {
|
||||
#[cfg(feature = "kdf")]
|
||||
PasswordHashFunctionKind::Argon2(path) => {
|
||||
Box::new(move |p| kdf::KeyDerivation::argon2(p, &path))
|
||||
}
|
||||
PasswordHashFunctionKind::Custom(f) => f,
|
||||
}));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Builder::invoke_stronghold_handlers_and_build(plugin_builder)
|
||||
}
|
||||
|
||||
fn invoke_stronghold_handlers_and_build<R: Runtime>(
|
||||
builder: PluginBuilder<R>,
|
||||
) -> TauriPlugin<R> {
|
||||
builder
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
initialize,
|
||||
destroy,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
+37
-10
@@ -9,7 +9,10 @@ use tauri::{
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Runtime, Window,
|
||||
};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncWriteExt, BufWriter},
|
||||
};
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
|
||||
use read_progress_stream::ReadProgressStream;
|
||||
@@ -64,20 +67,44 @@ async fn download<R: Runtime>(
|
||||
let response = request.send().await?;
|
||||
let total = response.content_length().unwrap_or(0);
|
||||
|
||||
let mut file = File::create(file_path).await?;
|
||||
let mut file = BufWriter::new(File::create(file_path).await?);
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
let mut i = 0;
|
||||
let mut temp_progress = 0;
|
||||
|
||||
while let Some(chunk) = stream.try_next().await? {
|
||||
i = i + 1;
|
||||
file.write_all(&chunk).await?;
|
||||
let _ = window.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: chunk.len() as u64,
|
||||
total,
|
||||
},
|
||||
);
|
||||
temp_progress = temp_progress + chunk.len();
|
||||
if i >= 10 {
|
||||
window
|
||||
.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: temp_progress as u64,
|
||||
total,
|
||||
},
|
||||
)
|
||||
.unwrap(); // TODO: remove the unwrap again.
|
||||
i = 0;
|
||||
temp_progress = 0;
|
||||
}
|
||||
}
|
||||
if temp_progress != 0 {
|
||||
window
|
||||
.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: temp_progress as u64,
|
||||
total,
|
||||
},
|
||||
)
|
||||
.unwrap(); // TODO: remove the unwrap again.
|
||||
}
|
||||
file.flush().await?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -18,4 +18,4 @@ thiserror.workspace = true
|
||||
rand = "0.8"
|
||||
futures-util = "0.3"
|
||||
tokio = { version = "1", features = ["net", "sync"] }
|
||||
tokio-tungstenite = { version = "0.19", features = ["native-tls"] }
|
||||
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^2.1.0",
|
||||
"@sveltejs/kit": "^1.22.0",
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"svelte": "^4.0.4",
|
||||
"svelte-check": "^3.4.4",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.4.0"
|
||||
"@sveltejs/adapter-auto": "2.1.0",
|
||||
"@sveltejs/kit": "1.27.2",
|
||||
"@tauri-apps/cli": "1.5.5",
|
||||
"svelte": "4.2.2",
|
||||
"svelte-check": "3.5.2",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "4.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tauri-plugin-websocket-api": "link:../../"
|
||||
|
||||
+4
-4
@@ -2774,9 +2774,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c"
|
||||
checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
@@ -2806,9 +2806,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67"
|
||||
checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
|
||||
@@ -13,7 +13,7 @@ tauri = { version = "1", features = [] }
|
||||
tokio = { version = "1", features = ["net"] }
|
||||
futures-util = "0.3"
|
||||
tauri-plugin-websocket = { path = "../../../" }
|
||||
tokio-tungstenite = "0.19"
|
||||
tokio-tungstenite = "0.20"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1", features = [] }
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { invoke, transformCallback } from "@tauri-apps/api/tauri";
|
||||
|
||||
export interface ConnectionConfig {
|
||||
writeBufferSize?: number;
|
||||
maxWriteBufferSize?: number;
|
||||
maxMessageSize?: number;
|
||||
maxFrameSize?: number;
|
||||
acceptUnmaskedFrames?: boolean;
|
||||
headers?: HeadersInit;
|
||||
}
|
||||
|
||||
export interface MessageKind<T, D> {
|
||||
type: T;
|
||||
data: D;
|
||||
@@ -26,16 +35,23 @@ export default class WebSocket {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
static async connect(url: string, options?: unknown): Promise<WebSocket> {
|
||||
static async connect(
|
||||
url: string,
|
||||
config?: ConnectionConfig,
|
||||
): Promise<WebSocket> {
|
||||
const listeners: Array<(arg: Message) => void> = [];
|
||||
const handler = (message: Message): void => {
|
||||
listeners.forEach((l) => l(message));
|
||||
};
|
||||
|
||||
if (config?.headers) {
|
||||
config.headers = Array.from(new Headers(config.headers).entries());
|
||||
}
|
||||
|
||||
return await invoke<number>("plugin:websocket|connect", {
|
||||
url,
|
||||
callbackFunction: transformCallback(handler),
|
||||
options,
|
||||
config,
|
||||
}).then((id) => new WebSocket(id, listeners));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ use tokio_tungstenite::{
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use tauri::http::header::{HeaderName, HeaderValue};
|
||||
use tokio_tungstenite::tungstenite::client::IntoClientRequest;
|
||||
|
||||
type Id = u32;
|
||||
type WebSocket = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
@@ -28,6 +31,10 @@ enum Error {
|
||||
Websocket(#[from] tokio_tungstenite::tungstenite::Error),
|
||||
#[error("connection not found for the given id: {0}")]
|
||||
ConnectionNotFound(Id),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderValue(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderValue),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderName(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderName),
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
@@ -42,20 +49,29 @@ impl Serialize for Error {
|
||||
#[derive(Default)]
|
||||
struct ConnectionManager(Mutex<HashMap<Id, WebSocketWriter>>);
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConnectionConfig {
|
||||
pub max_send_queue: Option<usize>,
|
||||
pub write_buffer_size: Option<usize>,
|
||||
pub max_write_buffer_size: Option<usize>,
|
||||
pub max_message_size: Option<usize>,
|
||||
pub max_frame_size: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub accept_unmasked_frames: bool,
|
||||
pub headers: Option<Vec<(String, String)>>,
|
||||
}
|
||||
|
||||
impl From<ConnectionConfig> for WebSocketConfig {
|
||||
fn from(config: ConnectionConfig) -> Self {
|
||||
// Disabling the warning on max_send_queue which we don't use anymore since it was deprecated.
|
||||
#[allow(deprecated)]
|
||||
Self {
|
||||
max_send_queue: config.max_send_queue,
|
||||
max_send_queue: None,
|
||||
write_buffer_size: config.write_buffer_size.unwrap_or(128 * 1024),
|
||||
max_write_buffer_size: config.max_write_buffer_size.unwrap_or(usize::MAX),
|
||||
// This may be harmful since if it's not provided from js we're overwriting the default value with None, meaning no size limit.
|
||||
max_message_size: config.max_message_size,
|
||||
// This may be harmful since if it's not provided from js we're overwriting the default value with None, meaning no size limit.
|
||||
max_frame_size: config.max_frame_size,
|
||||
accept_unmasked_frames: config.accept_unmasked_frames,
|
||||
}
|
||||
@@ -86,7 +102,17 @@ async fn connect<R: Runtime>(
|
||||
config: Option<ConnectionConfig>,
|
||||
) -> Result<Id> {
|
||||
let id = rand::random();
|
||||
let (ws_stream, _) = connect_async_with_config(url, config.map(Into::into), false).await?;
|
||||
let mut request = url.into_client_request()?;
|
||||
|
||||
if let Some(headers) = config.as_ref().and_then(|c| c.headers.as_ref()) {
|
||||
for (k, v) in headers {
|
||||
let header_name = HeaderName::from_str(k.as_str())?;
|
||||
let header_value = HeaderValue::from_str(v.as_str())?;
|
||||
request.headers_mut().insert(header_name, header_value);
|
||||
}
|
||||
}
|
||||
|
||||
let (ws_stream, _) = connect_async_with_config(request, config.map(Into::into), false).await?;
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let (write, read) = ws_stream.split();
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
Generated
+801
-659
File diff suppressed because it is too large
Load Diff
@@ -24,9 +24,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.4.1"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["ES2019", "ES2020.Promise", "ES2020.String", "DOM"],
|
||||
"lib": ["ES2019", "ES2020.Promise", "ES2020.String", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
|
||||
Reference in New Issue
Block a user