mirror of https://github.com/tauri-apps/tauri
feat(tauri) add httpRequest API (#589)
This commit is contained in:
parent
b9277ea53f
commit
4b54cc1564
|
@ -0,0 +1,160 @@
|
||||||
|
import tauri from './tauri'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {number} ResponseType
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @enum {ResponseType}
|
||||||
|
*/
|
||||||
|
const ResponseType = {
|
||||||
|
JSON: 1,
|
||||||
|
Text: 2,
|
||||||
|
Binary: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {number} BodyType
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @enum {BodyType}
|
||||||
|
*/
|
||||||
|
const BodyType = {
|
||||||
|
Form: 1,
|
||||||
|
File: 2,
|
||||||
|
Auto: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} HttpOptions
|
||||||
|
* @property {String} options.method GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE
|
||||||
|
* @property {String} options.url the request URL
|
||||||
|
* @property {Object} [options.headers] the request headers
|
||||||
|
* @property {Object} [options.propertys] the request query propertys
|
||||||
|
* @property {Object|String|Binary} [options.body] the request body
|
||||||
|
* @property {Boolean} followRedirects whether to follow redirects or not
|
||||||
|
* @property {Number} maxRedirections max number of redirections
|
||||||
|
* @property {Number} connectTimeout request connect timeout
|
||||||
|
* @property {Number} readTimeout request read timeout
|
||||||
|
* @property {Number} timeout request timeout
|
||||||
|
* @property {Boolean} allowCompression
|
||||||
|
* @property {ResponseType} [responseType=1] response type
|
||||||
|
* @property {BodyType} [bodyType=3] body type
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a HTTP request
|
||||||
|
*
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function request (options) {
|
||||||
|
return tauri.httpRequest(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a GET request
|
||||||
|
*
|
||||||
|
* @param {String} url request URL
|
||||||
|
* @param {String|Object|Binary} body request body
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function get (url, options = {}) {
|
||||||
|
return request({
|
||||||
|
method: 'GET',
|
||||||
|
url,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a POST request
|
||||||
|
*
|
||||||
|
* @param {String} url request URL
|
||||||
|
* @param {String|Object|Binary} body request body
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function post (url, body = void 0, options = {}) {
|
||||||
|
return request({
|
||||||
|
method: 'POST',
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a PUT request
|
||||||
|
*
|
||||||
|
* @param {String} url request URL
|
||||||
|
* @param {String|Object|Binary} body request body
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function put (url, body = void 0, options = {}) {
|
||||||
|
return request({
|
||||||
|
method: 'PUT',
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a PATCH request
|
||||||
|
*
|
||||||
|
* @param {String} url request URL
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function patch (url, options = {}) {
|
||||||
|
return request({
|
||||||
|
method: 'PATCH',
|
||||||
|
url,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes a DELETE request
|
||||||
|
*
|
||||||
|
* @param {String} url request URL
|
||||||
|
* @param {HttpOptions} options request options
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} promise resolving to the response
|
||||||
|
*/
|
||||||
|
function deleteRequest (url, options = {}) {
|
||||||
|
return request({
|
||||||
|
method: 'DELETE',
|
||||||
|
url,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
request,
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
put,
|
||||||
|
patch,
|
||||||
|
deleteRequest,
|
||||||
|
ResponseType,
|
||||||
|
BodyType
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
request,
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
put,
|
||||||
|
patch,
|
||||||
|
delete: deleteRequest,
|
||||||
|
ResponseType,
|
||||||
|
BodyType
|
||||||
|
}
|
|
@ -100,6 +100,9 @@ var Dir = {
|
||||||
}
|
}
|
||||||
|
|
||||||
<% if (ctx.dev) { %>
|
<% if (ctx.dev) { %>
|
||||||
|
function camelToKebab (string) {
|
||||||
|
return string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @name return __whitelistWarning
|
* @name return __whitelistWarning
|
||||||
* @description Present a stylish warning to the developer that their API
|
* @description Present a stylish warning to the developer that their API
|
||||||
|
@ -108,7 +111,7 @@ var Dir = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
var __whitelistWarning = function (func) {
|
var __whitelistWarning = function (func) {
|
||||||
console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + func + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
|
console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + camelToKebab(func) + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
|
||||||
return __reject()
|
return __reject()
|
||||||
}
|
}
|
||||||
<% } %>
|
<% } %>
|
||||||
|
@ -467,8 +470,8 @@ window.tauri = {
|
||||||
<% if (tauri.whitelist.renameFile === true || tauri.whitelist.all === true) { %>
|
<% if (tauri.whitelist.renameFile === true || tauri.whitelist.all === true) { %>
|
||||||
return this.promisified({
|
return this.promisified({
|
||||||
cmd: 'renameFile',
|
cmd: 'renameFile',
|
||||||
old_path: oldPath,
|
oldPath: oldPath,
|
||||||
new_path: newPath,
|
newPath: newPath,
|
||||||
options: options
|
options: options
|
||||||
});
|
});
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
@ -611,13 +614,48 @@ window.tauri = {
|
||||||
<% } %>
|
<% } %>
|
||||||
},
|
},
|
||||||
|
|
||||||
loadAsset: function loadAsset(assetName, assetType) {
|
<% if (ctx.dev) { %>
|
||||||
return this.promisified({
|
/**
|
||||||
cmd: 'loadAsset',
|
* @name httpRequest
|
||||||
asset: assetName,
|
* @description Makes an HTTP request
|
||||||
asset_type: assetType || 'unknown'
|
* @param {Object} options
|
||||||
})
|
* @param {String} options.method GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE
|
||||||
}
|
* @param {String} options.url the request URL
|
||||||
|
* @param {Object} [options.headers] the request headers
|
||||||
|
* @param {Object} [options.params] the request query params
|
||||||
|
* @param {Object|String|Binary} [options.body] the request body
|
||||||
|
* @param {Boolean} followRedirects whether to follow redirects or not
|
||||||
|
* @param {Number} maxRedirections max number of redirections
|
||||||
|
* @param {Number} connectTimeout request connect timeout
|
||||||
|
* @param {Number} readTimeout request read timeout
|
||||||
|
* @param {Number} timeout request timeout
|
||||||
|
* @param {Boolean} allowCompression
|
||||||
|
* @param {Number} [responseType=1] 1 - JSON, 2 - Text, 3 - Binary
|
||||||
|
* @param {Number} [bodyType=3] 1 - Form, 2 - File, 3 - Auto
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
<% } %>
|
||||||
|
httpRequest: function httpRequest(options) {
|
||||||
|
<% if (tauri.whitelist.readBinaryFile === true || tauri.whitelist.all === true) { %>
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'httpRequest',
|
||||||
|
options: options
|
||||||
|
});
|
||||||
|
<% } else { %>
|
||||||
|
<% if (ctx.dev) { %>
|
||||||
|
return __whitelistWarning('httpRequest')
|
||||||
|
<% } %>
|
||||||
|
return __reject()
|
||||||
|
<% } %>
|
||||||
|
},
|
||||||
|
|
||||||
|
loadAsset: function loadAsset(assetName, assetType) {
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'loadAsset',
|
||||||
|
asset: assetName,
|
||||||
|
assetType: assetType || 'unknown'
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// init tauri API
|
// init tauri API
|
||||||
|
|
|
@ -11,6 +11,7 @@ exclude = ["test/fixture/**"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
ignore = "0.4.11"
|
ignore = "0.4.11"
|
||||||
|
@ -24,6 +25,8 @@ flate2 = "1"
|
||||||
error-chain = "0.12"
|
error-chain = "0.12"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
nfd = "0.0.4"
|
nfd = "0.0.4"
|
||||||
|
attohttpc = {version = "0.13.0", features=["json", "form" ]}
|
||||||
|
http = "0.2"
|
||||||
tauri-utils = {version = "0.5", path = "../tauri-utils"}
|
tauri-utils = {version = "0.5", path = "../tauri-utils"}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use attohttpc::{RequestBuilder, Method};
|
||||||
|
use http::header::HeaderName;
|
||||||
|
use serde_json::Value;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_repr::{Serialize_repr, Deserialize_repr};
|
||||||
|
|
||||||
|
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
|
||||||
|
#[repr(u16)]
|
||||||
|
/// The request's body type
|
||||||
|
pub enum BodyType {
|
||||||
|
/// Send request body as application/x-www-form-urlencoded
|
||||||
|
Form = 1,
|
||||||
|
/// Send request body (which is a path to a file) as application/octet-stream
|
||||||
|
File,
|
||||||
|
/// Detects the body type automatically
|
||||||
|
/// - if the body is a byte array, send is as bytes (application/octet-stream)
|
||||||
|
/// - if the body is an object or array, send it as JSON (application/json with UTF-8 charset)
|
||||||
|
/// - if the body is a string, send it as text (text/plain with UTF-8 charset)
|
||||||
|
Auto
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
|
||||||
|
#[repr(u16)]
|
||||||
|
/// The request's response type
|
||||||
|
pub enum ResponseType {
|
||||||
|
/// Read the response as JSON
|
||||||
|
Json = 1,
|
||||||
|
/// Read the response as text
|
||||||
|
Text,
|
||||||
|
/// Read the response as binary
|
||||||
|
Binary
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
/// The configuration object of an HTTP request
|
||||||
|
pub struct HttpRequestOptions {
|
||||||
|
/// The request method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE)
|
||||||
|
pub method: String,
|
||||||
|
/// The request URL
|
||||||
|
pub url: String,
|
||||||
|
/// The request query params
|
||||||
|
pub params: Option<HashMap<String, Value>>,
|
||||||
|
/// The request headers
|
||||||
|
pub headers: Option<HashMap<String, Value>>,
|
||||||
|
/// The request body
|
||||||
|
pub body: Option<Value>,
|
||||||
|
/// Whether to follow redirects or not
|
||||||
|
pub follow_redirects: Option<bool>,
|
||||||
|
/// Max number of redirections to follow
|
||||||
|
pub max_redirections: Option<u32>,
|
||||||
|
/// Connect timeout for the request
|
||||||
|
pub connect_timeout: Option<u64>,
|
||||||
|
/// Read timeout for the request
|
||||||
|
pub read_timeout: Option<u64>,
|
||||||
|
/// Timeout for the whole request
|
||||||
|
pub timeout: Option<u64>,
|
||||||
|
/// Whether the request will announce that it accepts compression
|
||||||
|
pub allow_compression: Option<bool>,
|
||||||
|
/// The body type (defaults to Auto)
|
||||||
|
pub body_type: Option<BodyType>,
|
||||||
|
/// The response type (defaults to Json)
|
||||||
|
pub response_type: Option<ResponseType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes an HTTP request
|
||||||
|
///
|
||||||
|
/// The response will be transformed to String,
|
||||||
|
/// If reading the response as binary, the byte array will be serialized using serde_json
|
||||||
|
pub fn make_request(options: HttpRequestOptions) -> crate::Result<String> {
|
||||||
|
let method = Method::from_bytes(options.method.to_uppercase().as_bytes())?;
|
||||||
|
let mut builder = RequestBuilder::new(method, options.url);
|
||||||
|
if let Some(params) = options.params {
|
||||||
|
for (param, param_value) in params.iter() {
|
||||||
|
builder = builder.param(param, param_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(headers) = options.headers {
|
||||||
|
for (header, header_value) in headers.iter() {
|
||||||
|
builder = builder.header(HeaderName::from_bytes(header.as_bytes())?, format!("{}", header_value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(follow_redirects) = options.follow_redirects {
|
||||||
|
builder = builder.follow_redirects(follow_redirects);
|
||||||
|
}
|
||||||
|
if let Some(max_redirections) = options.max_redirections {
|
||||||
|
builder = builder.max_redirections(max_redirections);
|
||||||
|
}
|
||||||
|
if let Some(connect_timeout) = options.connect_timeout {
|
||||||
|
builder = builder.connect_timeout(Duration::from_secs(connect_timeout));
|
||||||
|
}
|
||||||
|
if let Some(read_timeout) = options.read_timeout {
|
||||||
|
builder = builder.read_timeout(Duration::from_secs(read_timeout));
|
||||||
|
}
|
||||||
|
if let Some(timeout) = options.timeout {
|
||||||
|
builder = builder.timeout(Duration::from_secs(timeout));
|
||||||
|
}
|
||||||
|
if let Some(allow_compression) = options.allow_compression {
|
||||||
|
builder = builder.allow_compression(allow_compression);
|
||||||
|
}
|
||||||
|
builder = builder.danger_accept_invalid_certs(true).danger_accept_invalid_hostnames(true);
|
||||||
|
|
||||||
|
let response = if let Some(body) = options.body {
|
||||||
|
match options.body_type.unwrap_or(BodyType::Auto) {
|
||||||
|
BodyType::Form => builder.form(&body)?.send(),
|
||||||
|
BodyType::File => {
|
||||||
|
if let Some(path) = body.as_str() {
|
||||||
|
builder.file(File::open(path)?).send()
|
||||||
|
} else {
|
||||||
|
return Err(crate::Error::from("Body must be the path to the file"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BodyType::Auto => {
|
||||||
|
if body.is_object() {
|
||||||
|
builder.json(&body)?.send()
|
||||||
|
} else if let Some(text) = body.as_str() {
|
||||||
|
builder.text(&text).send()
|
||||||
|
} else if body.is_array() {
|
||||||
|
let u: Result<Vec<u8>, _> = serde_json::from_value(body.clone());
|
||||||
|
match u {
|
||||||
|
Ok(vec) => builder.bytes(&vec).send(),
|
||||||
|
Err(_) => builder.json(&body)?.send()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { builder.send() };
|
||||||
|
|
||||||
|
let response = response?;
|
||||||
|
if response.is_success() {
|
||||||
|
let response_data = match options.response_type.unwrap_or(ResponseType::Json) {
|
||||||
|
ResponseType::Json => response.json()?,
|
||||||
|
ResponseType::Text => response.text()?,
|
||||||
|
ResponseType::Binary => serde_json::to_string(&response.bytes()?)?
|
||||||
|
};
|
||||||
|
Ok(response_data)
|
||||||
|
} else {
|
||||||
|
Err(crate::Error::from(response.status().as_str()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub mod version;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
pub mod dialog;
|
pub mod dialog;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
pub mod http;
|
||||||
|
|
||||||
pub use tauri_utils::*;
|
pub use tauri_utils::*;
|
||||||
|
|
||||||
|
@ -22,6 +23,10 @@ error_chain! {
|
||||||
ZipError(::zip::result::ZipError);
|
ZipError(::zip::result::ZipError);
|
||||||
SemVer(::semver::SemVerError);
|
SemVer(::semver::SemVerError);
|
||||||
Platform(::tauri_utils::Error);
|
Platform(::tauri_utils::Error);
|
||||||
|
Json(::serde_json::Error);
|
||||||
|
Http(::attohttpc::Error);
|
||||||
|
HttpMethod(::http::method::InvalidMethod);
|
||||||
|
HttpHeaderName(::http::header::InvalidHeaderName);
|
||||||
}
|
}
|
||||||
errors {
|
errors {
|
||||||
Extract(t: String) {
|
Extract(t: String) {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
const methodSelect = document.getElementById('request-method')
|
||||||
|
const requestUrlInput = document.getElementById('request-url')
|
||||||
|
const requestBodyInput = document.getElementById('request-body')
|
||||||
|
|
||||||
|
document.getElementById('make-request').addEventListener('click', function () {
|
||||||
|
const method = methodSelect.value || 'GET'
|
||||||
|
const url = requestUrlInput.value || ''
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
url: url,
|
||||||
|
method: method
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = requestBodyInput.value || ''
|
||||||
|
if ((body.startsWith('{') && body.endsWith('}')) || (body.startsWith('[') && body.endsWith(']'))) {
|
||||||
|
body = JSON.parse(body)
|
||||||
|
} else if (body.startsWith('/') || body.match(/\S:\//g)) {
|
||||||
|
options.bodyAsFile = true
|
||||||
|
}
|
||||||
|
options.body = body
|
||||||
|
|
||||||
|
window.tauri.httpRequest(options).then(registerResponse).catch(registerResponse)
|
||||||
|
})
|
|
@ -41,6 +41,19 @@
|
||||||
<button id="save-dialog">Open save dialog</button>
|
<button id="save-dialog">Open save dialog</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 24px">
|
||||||
|
<select id="request-method">
|
||||||
|
<option value="GET">GET</option>
|
||||||
|
<option value="POST">POST</option>
|
||||||
|
<option value="PUT">PUT</option>
|
||||||
|
<option value="PATCH">PATCH</option>
|
||||||
|
<option value="DELETE">DELETE</option>
|
||||||
|
</select>
|
||||||
|
<input id="request-url" placeholder="Type the request URL...">
|
||||||
|
<textarea id="request-body" placeholder="Request body"></textarea>
|
||||||
|
<button id="make-request">Make request</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="response"></div>
|
<div id="response"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -76,5 +89,6 @@
|
||||||
<script src="fs.js"></script>
|
<script src="fs.js"></script>
|
||||||
<script src="window.js"></script>
|
<script src="window.js"></script>
|
||||||
<script src="dialog.js"></script>
|
<script src="dialog.js"></script>
|
||||||
|
<script src="http.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -100,6 +100,9 @@ var Dir = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function camelToKebab (string) {
|
||||||
|
return string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @name return __whitelistWarning
|
* @name return __whitelistWarning
|
||||||
* @description Present a stylish warning to the developer that their API
|
* @description Present a stylish warning to the developer that their API
|
||||||
|
@ -108,7 +111,7 @@ var Dir = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
var __whitelistWarning = function (func) {
|
var __whitelistWarning = function (func) {
|
||||||
console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + func + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
|
console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + camelToKebab(func) + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ')
|
||||||
return __reject()
|
return __reject()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +420,8 @@ window.tauri = {
|
||||||
|
|
||||||
return this.promisified({
|
return this.promisified({
|
||||||
cmd: 'renameFile',
|
cmd: 'renameFile',
|
||||||
old_path: oldPath,
|
oldPath: oldPath,
|
||||||
new_path: newPath,
|
newPath: newPath,
|
||||||
options: options
|
options: options
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -531,13 +534,43 @@ window.tauri = {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loadAsset: function loadAsset(assetName, assetType) {
|
|
||||||
return this.promisified({
|
/**
|
||||||
cmd: 'loadAsset',
|
* @name httpRequest
|
||||||
asset: assetName,
|
* @description Makes an HTTP request
|
||||||
asset_type: assetType || 'unknown'
|
* @param {Object} options
|
||||||
})
|
* @param {String} options.method GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT or TRACE
|
||||||
}
|
* @param {String} options.url the request URL
|
||||||
|
* @param {Object} [options.headers] the request headers
|
||||||
|
* @param {Object} [options.params] the request query params
|
||||||
|
* @param {Object|String|Binary} [options.body] the request body
|
||||||
|
* @param {Boolean} followRedirects whether to follow redirects or not
|
||||||
|
* @param {Number} maxRedirections max number of redirections
|
||||||
|
* @param {Number} connectTimeout request connect timeout
|
||||||
|
* @param {Number} readTimeout request read timeout
|
||||||
|
* @param {Number} timeout request timeout
|
||||||
|
* @param {Boolean} allowCompression
|
||||||
|
* @param {Boolean} bodyAsForm send the body as application/x-www-form-urlencoded
|
||||||
|
* @param {Boolean} bodyAsFile send the body as a file (body must be the path to the file)
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
httpRequest: function httpRequest(options) {
|
||||||
|
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'httpRequest',
|
||||||
|
options: options
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
loadAsset: function loadAsset(assetName, assetType) {
|
||||||
|
return this.promisified({
|
||||||
|
cmd: 'loadAsset',
|
||||||
|
asset: assetName,
|
||||||
|
assetType: assetType || 'unknown'
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// init tauri API
|
// init tauri API
|
||||||
|
@ -591,4 +624,4 @@ if (document.readyState === 'complete' || document.readyState === 'interactive')
|
||||||
__openLinks()
|
__openLinks()
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
</script> <div> <button id="log">Call Log API</button> <button id="request">Call Request (async) API</button> <button id="event">Send event to Rust</button> </div> <div style="margin-top:24px"> <select id="dir"> <option value="">None</option> </select> <input id="path-to-read" placeholder="Type the path to read..."> <button id="read">Read</button> </div> <div style="margin-top:24px"> <input id="url" value="https://tauri.studio"> <button id="open-url">Open URL</button> </div> <div style="margin-top:24px"> <input id="title" value="Awesome Tauri Example!"> <button id="set-title">Set title</button> </div> <div style="margin-top:24px"> <input id="dialog-default-path" placeholder="Default path"> <input id="dialog-filter" placeholder="Extensions filter"> <div> <input type="checkbox" id="dialog-multiple"> <label>Multiple</label> </div> <div> <input type="checkbox" id="dialog-directory"> <label>Directory</label> </div> <button id="open-dialog">Open dialog</button> <button id="save-dialog">Open save dialog</button> </div> <div id="response"></div> <script>function registerResponse(e){document.getElementById("response").innerHTML="object"==typeof e?JSON.stringify(e):e}function addClickEnterHandler(e,n,t){e.addEventListener("click",t),n.addEventListener("keyup",function(e){13===e.keyCode&&t()})}window.tauri.listen("rust-event",function(e){document.getElementById("response").innerHTML=JSON.stringify(e)});var dirSelect=document.getElementById("dir");for(var key in window.tauri.Dir){var value=window.tauri.Dir[key],opt=document.createElement("option");opt.value=value,opt.innerHTML=key,dirSelect.appendChild(opt)}</script> <script>document.getElementById("log").addEventListener("click",function(){window.tauri.invoke({cmd:"logOperation",event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}),document.getElementById("request").addEventListener("click",function(){window.tauri.promisified({cmd:"performRequest",endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(registerResponse).catch(registerResponse)}),document.getElementById("event").addEventListener("click",function(){window.tauri.emit("js-event","this is the payload string")});</script> <script>var dirSelect=document.getElementById("dir");function getDir(){return dirSelect.value?parseInt(dir.value):null}function arrayBufferToBase64(e,n){var t=new Blob([e],{type:"application/octet-binary"}),r=new FileReader;r.onload=function(e){var t=e.target.result;n(t.substr(t.indexOf(",")+1))},r.readAsDataURL(t)}var pathInput=document.getElementById("path-to-read");addClickEnterHandler(document.getElementById("read"),pathInput,function(){var r=pathInput.value,a=r.match(/\S+\.\S+$/g),e={dir:getDir()};(a?window.tauri.readBinaryFile(r,e):window.tauri.readDir(r,e)).then(function(e){if(a)if(r.includes(".png")||r.includes(".jpg"))arrayBufferToBase64(new Uint8Array(e),function(e){registerResponse('<img src="'+("data:image/png;base64,"+e)+'"></img>')});else{var t=String.fromCharCode.apply(null,e);registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>');var n=document.getElementById("file-response");n.value=t,document.getElementById("file-save").addEventListener("click",function(){window.tauri.writeFile({file:r,contents:n.value},{dir:getDir()}).catch(registerResponse)})}else registerResponse(e)}).catch(registerResponse)});</script> <script>var urlInput=document.getElementById("url");addClickEnterHandler(document.getElementById("open-url"),urlInput,function(){window.tauri.open(urlInput.value)});var titleInput=document.getElementById("title");addClickEnterHandler(document.getElementById("set-title"),titleInput,function(){window.tauri.setTitle(titleInput.value)});</script> <script>var defaultPathInput=document.getElementById("dialog-default-path"),filterInput=document.getElementById("dialog-filter"),multipleInput=document.getElementById("dialog-multiple"),directoryInput=document.getElementById("dialog-directory");document.getElementById("open-dialog").addEventListener("click",function(){window.tauri.openDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null,multiple:multipleInput.checked,directory:directoryInput.checked}).then(registerResponse).catch(registerResponse)}),document.getElementById("save-dialog").addEventListener("click",function(){window.tauri.saveDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null}).then(registerResponse).catch(registerResponse)});</script> </body></html>
|
</script> <div> <button id="log">Call Log API</button> <button id="request">Call Request (async) API</button> <button id="event">Send event to Rust</button> </div> <div style="margin-top:24px"> <select id="dir"> <option value="">None</option> </select> <input id="path-to-read" placeholder="Type the path to read..."> <button id="read">Read</button> </div> <div style="margin-top:24px"> <input id="url" value="https://tauri.studio"> <button id="open-url">Open URL</button> </div> <div style="margin-top:24px"> <input id="title" value="Awesome Tauri Example!"> <button id="set-title">Set title</button> </div> <div style="margin-top:24px"> <input id="dialog-default-path" placeholder="Default path"> <input id="dialog-filter" placeholder="Extensions filter"> <div> <input type="checkbox" id="dialog-multiple"> <label>Multiple</label> </div> <div> <input type="checkbox" id="dialog-directory"> <label>Directory</label> </div> <button id="open-dialog">Open dialog</button> <button id="save-dialog">Open save dialog</button> </div> <div style="margin-top:24px"> <select id="request-method"> <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="PATCH">PATCH</option> <option value="DELETE">DELETE</option> </select> <input id="request-url" placeholder="Type the request URL..."> <textarea id="request-body" placeholder="Request body"></textarea> <button id="make-request">Make request</button> </div> <div id="response"></div> <script>function registerResponse(e){document.getElementById("response").innerHTML="object"==typeof e?JSON.stringify(e):e}function addClickEnterHandler(e,n,t){e.addEventListener("click",t),n.addEventListener("keyup",function(e){13===e.keyCode&&t()})}window.tauri.listen("rust-event",function(e){document.getElementById("response").innerHTML=JSON.stringify(e)});var dirSelect=document.getElementById("dir");for(var key in window.tauri.Dir){var value=window.tauri.Dir[key],opt=document.createElement("option");opt.value=value,opt.innerHTML=key,dirSelect.appendChild(opt)}</script> <script>document.getElementById("log").addEventListener("click",function(){window.tauri.invoke({cmd:"logOperation",event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}),document.getElementById("request").addEventListener("click",function(){window.tauri.promisified({cmd:"performRequest",endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(registerResponse).catch(registerResponse)}),document.getElementById("event").addEventListener("click",function(){window.tauri.emit("js-event","this is the payload string")});</script> <script>var dirSelect=document.getElementById("dir");function getDir(){return dirSelect.value?parseInt(dir.value):null}function arrayBufferToBase64(e,n){var t=new Blob([e],{type:"application/octet-binary"}),r=new FileReader;r.onload=function(e){var t=e.target.result;n(t.substr(t.indexOf(",")+1))},r.readAsDataURL(t)}var pathInput=document.getElementById("path-to-read");addClickEnterHandler(document.getElementById("read"),pathInput,function(){var r=pathInput.value,a=r.match(/\S+\.\S+$/g),e={dir:getDir()};(a?window.tauri.readBinaryFile(r,e):window.tauri.readDir(r,e)).then(function(e){if(a)if(r.includes(".png")||r.includes(".jpg"))arrayBufferToBase64(new Uint8Array(e),function(e){registerResponse('<img src="'+("data:image/png;base64,"+e)+'"></img>')});else{var t=String.fromCharCode.apply(null,e);registerResponse('<textarea id="file-response" style="height: 400px"></textarea><button id="file-save">Save</button>');var n=document.getElementById("file-response");n.value=t,document.getElementById("file-save").addEventListener("click",function(){window.tauri.writeFile({file:r,contents:n.value},{dir:getDir()}).catch(registerResponse)})}else registerResponse(e)}).catch(registerResponse)});</script> <script>var urlInput=document.getElementById("url");addClickEnterHandler(document.getElementById("open-url"),urlInput,function(){window.tauri.open(urlInput.value)});var titleInput=document.getElementById("title");addClickEnterHandler(document.getElementById("set-title"),titleInput,function(){window.tauri.setTitle(titleInput.value)});</script> <script>var defaultPathInput=document.getElementById("dialog-default-path"),filterInput=document.getElementById("dialog-filter"),multipleInput=document.getElementById("dialog-multiple"),directoryInput=document.getElementById("dialog-directory");document.getElementById("open-dialog").addEventListener("click",function(){window.tauri.openDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null,multiple:multipleInput.checked,directory:directoryInput.checked}).then(registerResponse).catch(registerResponse)}),document.getElementById("save-dialog").addEventListener("click",function(){window.tauri.saveDialog({defaultPath:defaultPathInput.value||null,filter:filterInput.value||null}).then(registerResponse).catch(registerResponse)});</script> <script></script> </body></html>
|
|
@ -3,12 +3,20 @@ use serde::Deserialize;
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct RequestBody {
|
pub struct RequestBody {
|
||||||
id: i32,
|
id: i32,
|
||||||
name: String
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "cmd", rename_all = "camelCase")]
|
#[serde(tag = "cmd", rename_all = "camelCase")]
|
||||||
pub enum Cmd {
|
pub enum Cmd {
|
||||||
LogOperation { event: String, payload: Option<String> },
|
LogOperation {
|
||||||
PerformRequest { endpoint: String, body: RequestBody, callback: String, error: String },
|
event: String,
|
||||||
|
payload: Option<String>,
|
||||||
|
},
|
||||||
|
PerformRequest {
|
||||||
|
endpoint: String,
|
||||||
|
body: RequestBody,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Reply {
|
struct Reply {
|
||||||
data: String
|
data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -32,15 +32,18 @@ fn main() {
|
||||||
.invoke_handler(|_webview, arg| {
|
.invoke_handler(|_webview, arg| {
|
||||||
use cmd::Cmd::*;
|
use cmd::Cmd::*;
|
||||||
match serde_json::from_str(arg) {
|
match serde_json::from_str(arg) {
|
||||||
Err(e) => {
|
Err(e) => Err(e.to_string()),
|
||||||
Err(e.to_string())
|
|
||||||
}
|
|
||||||
Ok(command) => {
|
Ok(command) => {
|
||||||
match command {
|
match command {
|
||||||
LogOperation { event, payload } => {
|
LogOperation { event, payload } => {
|
||||||
println!("{} {:?}", event, payload);
|
println!("{} {:?}", event, payload);
|
||||||
},
|
}
|
||||||
PerformRequest { endpoint, body, callback, error } => {
|
PerformRequest {
|
||||||
|
endpoint,
|
||||||
|
body,
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
} => {
|
||||||
// tauri::execute_promise is a helper for APIs that uses the tauri.promisified JS function
|
// tauri::execute_promise is a helper for APIs that uses the tauri.promisified JS function
|
||||||
// so you can easily communicate between JS and Rust with promises
|
// so you can easily communicate between JS and Rust with promises
|
||||||
tauri::execute_promise(
|
tauri::execute_promise(
|
||||||
|
@ -54,9 +57,9 @@ fn main() {
|
||||||
Ok("{ key: 'response', value: [{ id: 3 }] }".to_string())
|
Ok("{ key: 'response', value: [{ id: 3 }] }".to_string())
|
||||||
},
|
},
|
||||||
callback,
|
callback,
|
||||||
error
|
error,
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,13 @@ impl App {
|
||||||
runner::run(&mut self).expect("Failed to build webview");
|
runner::run(&mut self).expect("Failed to build webview");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_invoke_handler(&mut self, webview: &mut WebView<'_, ()>, arg: &str) -> Result<bool, String> {
|
pub(crate) fn run_invoke_handler(
|
||||||
|
&mut self,
|
||||||
|
webview: &mut WebView<'_, ()>,
|
||||||
|
arg: &str,
|
||||||
|
) -> Result<bool, String> {
|
||||||
if let Some(ref mut invoke_handler) = self.invoke_handler {
|
if let Some(ref mut invoke_handler) = self.invoke_handler {
|
||||||
invoke_handler(webview, arg)
|
invoke_handler(webview, arg).map(|_| true)
|
||||||
.map(|_| true)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +43,7 @@ impl App {
|
||||||
pub struct AppBuilder {
|
pub struct AppBuilder {
|
||||||
invoke_handler: Option<InvokeHandler>,
|
invoke_handler: Option<InvokeHandler>,
|
||||||
setup: Option<Setup>,
|
setup: Option<Setup>,
|
||||||
splashscreen_html: Option<String>
|
splashscreen_html: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppBuilder {
|
impl AppBuilder {
|
||||||
|
|
|
@ -4,9 +4,9 @@ use std::{fs::read_to_string, path::Path, process::Stdio, thread::spawn};
|
||||||
use web_view::{builder, Content, WebView};
|
use web_view::{builder, Content, WebView};
|
||||||
|
|
||||||
use super::App;
|
use super::App;
|
||||||
use crate::config::{get, Config};
|
|
||||||
#[cfg(feature = "embedded-server")]
|
#[cfg(feature = "embedded-server")]
|
||||||
use crate::api::tcp::{get_available_port, port_is_available};
|
use crate::api::tcp::{get_available_port, port_is_available};
|
||||||
|
use crate::config::{get, Config};
|
||||||
|
|
||||||
// Main entry point function for running the Webview
|
// Main entry point function for running the Webview
|
||||||
pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
||||||
|
@ -32,7 +32,12 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
|
||||||
config,
|
config,
|
||||||
main_content,
|
main_content,
|
||||||
if application.splashscreen_html().is_some() {
|
if application.splashscreen_html().is_some() {
|
||||||
Some(Content::Html(application.splashscreen_html().expect("failed to get splashscreen_html").to_string()))
|
Some(Content::Html(
|
||||||
|
application
|
||||||
|
.splashscreen_html()
|
||||||
|
.expect("failed to get splashscreen_html")
|
||||||
|
.to_string(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
@ -153,7 +158,7 @@ fn build_webview(
|
||||||
application: &mut App,
|
application: &mut App,
|
||||||
config: Config,
|
config: Config,
|
||||||
content: Content<String>,
|
content: Content<String>,
|
||||||
splashscreen_content: Option<Content<String>>
|
splashscreen_content: Option<Content<String>>,
|
||||||
) -> crate::Result<WebView<'_, ()>> {
|
) -> crate::Result<WebView<'_, ()>> {
|
||||||
let content_clone = match content {
|
let content_clone = match content {
|
||||||
Content::Html(ref html) => Content::Html(html.clone()),
|
Content::Html(ref html) => Content::Html(html.clone()),
|
||||||
|
@ -201,16 +206,18 @@ fn build_webview(
|
||||||
Some(e.replace("'", "\\'"))
|
Some(e.replace("'", "\\'"))
|
||||||
} else {
|
} else {
|
||||||
let handled = handled_by_app.expect("failed to check if the invoke was handled");
|
let handled = handled_by_app.expect("failed to check if the invoke was handled");
|
||||||
if handled { None } else { Some(tauri_handle_error_str) }
|
if handled {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(tauri_handle_error_str)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
handler_error = Some(tauri_handle_error_str);
|
handler_error = Some(tauri_handle_error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handler_error_message) = handler_error {
|
if let Some(handler_error_message) = handler_error {
|
||||||
webview.eval(
|
webview.eval(&get_api_error_message(arg, handler_error_message))?;
|
||||||
&get_api_error_message(arg, handler_error_message)
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +236,8 @@ fn build_webview(
|
||||||
if has_splashscreen {
|
if has_splashscreen {
|
||||||
// inject the tauri.js entry point
|
// inject the tauri.js entry point
|
||||||
webview
|
webview
|
||||||
.handle()
|
.handle()
|
||||||
.dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))?;
|
.dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(webview)
|
Ok(webview)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
mod cmd;
|
mod cmd;
|
||||||
mod salt;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
mod file_system;
|
|
||||||
mod dialog;
|
mod dialog;
|
||||||
|
mod file_system;
|
||||||
|
mod http;
|
||||||
|
mod salt;
|
||||||
|
|
||||||
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -149,7 +149,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||||
OpenDialog {
|
OpenDialog {
|
||||||
options,
|
options,
|
||||||
callback,
|
callback,
|
||||||
error
|
error,
|
||||||
} => {
|
} => {
|
||||||
dialog::open(webview, options, callback, error);
|
dialog::open(webview, options, callback, error);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,15 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
|
||||||
} => {
|
} => {
|
||||||
dialog::save(webview, options, callback, error);
|
dialog::save(webview, options, callback, error);
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
#[cfg(any(feature = "all-api", feature = "http-request"))]
|
||||||
|
HttpRequest {
|
||||||
|
options,
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
} => {
|
||||||
|
http::make_request(webview, options, callback, error);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
||||||
LoadAsset {
|
LoadAsset {
|
||||||
asset,
|
asset,
|
||||||
asset_type,
|
asset_type,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use serde::Deserialize;
|
|
||||||
use crate::api::path::BaseDirectory;
|
use crate::api::path::BaseDirectory;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tauri_api::http::HttpRequestOptions;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct DirOperationOptions {
|
pub struct DirOperationOptions {
|
||||||
|
@ -14,6 +15,7 @@ pub struct FileOperationOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct OpenDialogOptions {
|
pub struct OpenDialogOptions {
|
||||||
pub filter: Option<String>,
|
pub filter: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -24,6 +26,7 @@ pub struct OpenDialogOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SaveDialogOptions {
|
pub struct SaveDialogOptions {
|
||||||
pub filter: Option<String>,
|
pub filter: Option<String>,
|
||||||
pub default_path: Option<String>,
|
pub default_path: Option<String>,
|
||||||
|
@ -91,6 +94,7 @@ pub enum Cmd {
|
||||||
callback: String,
|
callback: String,
|
||||||
error: String,
|
error: String,
|
||||||
},
|
},
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg(any(feature = "all-api", feature = "rename-file"))]
|
#[cfg(any(feature = "all-api", feature = "rename-file"))]
|
||||||
RenameFile {
|
RenameFile {
|
||||||
old_path: String,
|
old_path: String,
|
||||||
|
@ -142,6 +146,13 @@ pub enum Cmd {
|
||||||
callback: String,
|
callback: String,
|
||||||
error: String,
|
error: String,
|
||||||
},
|
},
|
||||||
|
#[cfg(any(feature = "all-api", feature = "http-request"))]
|
||||||
|
HttpRequest {
|
||||||
|
options: HttpRequestOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
},
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
#[cfg(any(feature = "embedded-server", feature = "no-server"))]
|
||||||
LoadAsset {
|
LoadAsset {
|
||||||
asset: String,
|
asset: String,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::api::dialog::{select, select_multiple, save_file, pick_folder, Response};
|
|
||||||
use super::cmd::{OpenDialogOptions, SaveDialogOptions};
|
use super::cmd::{OpenDialogOptions, SaveDialogOptions};
|
||||||
|
use crate::api::dialog::{pick_folder, save_file, select, select_multiple, Response};
|
||||||
use web_view::WebView;
|
use web_view::WebView;
|
||||||
|
|
||||||
fn map_response(response: Response) -> String {
|
fn map_response(response: Response) -> String {
|
||||||
match response {
|
match response {
|
||||||
Response::Okay(path) => format!(r#""{}""#, path).replace("\\", "\\\\"),
|
Response::Okay(path) => format!(r#""{}""#, path).replace("\\", "\\\\"),
|
||||||
Response::OkayMultiple(paths) => format!("{:?}", paths),
|
Response::OkayMultiple(paths) => format!("{:?}", paths),
|
||||||
Response::Cancel => panic!("unexpected response type")
|
Response::Cancel => panic!("unexpected response type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,14 +52,15 @@ pub fn copy_file<T: 'static>(
|
||||||
webview,
|
webview,
|
||||||
move || {
|
move || {
|
||||||
let (src, dest) = match options.and_then(|o| o.dir) {
|
let (src, dest) = match options.and_then(|o| o.dir) {
|
||||||
Some(dir) => {
|
Some(dir) => (
|
||||||
(resolve_path(source, Some(dir.clone()))?, resolve_path(destination, Some(dir))?)
|
resolve_path(source, Some(dir.clone()))?,
|
||||||
}
|
resolve_path(destination, Some(dir))?,
|
||||||
None => (source, destination)
|
),
|
||||||
|
None => (source, destination),
|
||||||
};
|
};
|
||||||
fs::copy(src, dest)
|
fs::copy(src, dest)
|
||||||
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
||||||
.map(|_| "".to_string())
|
.map(|_| "".to_string())
|
||||||
},
|
},
|
||||||
callback,
|
callback,
|
||||||
error,
|
error,
|
||||||
|
@ -90,7 +91,7 @@ pub fn create_dir<T: 'static>(
|
||||||
|
|
||||||
response
|
response
|
||||||
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
||||||
.map(|_| "".to_string())
|
.map(|_| "".to_string())
|
||||||
},
|
},
|
||||||
callback,
|
callback,
|
||||||
error,
|
error,
|
||||||
|
@ -160,10 +161,11 @@ pub fn rename_file<T: 'static>(
|
||||||
webview,
|
webview,
|
||||||
move || {
|
move || {
|
||||||
let (old, new) = match options.and_then(|o| o.dir) {
|
let (old, new) = match options.and_then(|o| o.dir) {
|
||||||
Some(dir) => {
|
Some(dir) => (
|
||||||
(resolve_path(old_path, Some(dir.clone()))?, resolve_path(new_path, Some(dir))?)
|
resolve_path(old_path, Some(dir.clone()))?,
|
||||||
}
|
resolve_path(new_path, Some(dir))?,
|
||||||
None => (old_path, new_path)
|
),
|
||||||
|
None => (old_path, new_path),
|
||||||
};
|
};
|
||||||
fs::rename(old, new)
|
fs::rename(old, new)
|
||||||
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
||||||
|
@ -210,10 +212,7 @@ pub fn read_text_file<T: 'static>(
|
||||||
move || {
|
move || {
|
||||||
file::read_string(resolve_path(path, options.and_then(|o| o.dir))?)
|
file::read_string(resolve_path(path, options.and_then(|o| o.dir))?)
|
||||||
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
||||||
.and_then(|f| {
|
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
|
||||||
serde_json::to_string(&f)
|
|
||||||
.map_err(|err| err.into())
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
callback,
|
callback,
|
||||||
error,
|
error,
|
||||||
|
@ -232,10 +231,7 @@ pub fn read_binary_file<T: 'static>(
|
||||||
move || {
|
move || {
|
||||||
file::read_binary(resolve_path(path, options.and_then(|o| o.dir))?)
|
file::read_binary(resolve_path(path, options.and_then(|o| o.dir))?)
|
||||||
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
.map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
|
||||||
.and_then(|f| {
|
.and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
|
||||||
serde_json::to_string(&f)
|
|
||||||
.map_err(|err| err.into())
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
callback,
|
callback,
|
||||||
error,
|
error,
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
use tauri_api::http::{make_request as request, HttpRequestOptions, ResponseType};
|
||||||
|
use web_view::WebView;
|
||||||
|
|
||||||
|
/// Makes a HTTP request and resolves the response to the webview
|
||||||
|
pub fn make_request<T: 'static>(
|
||||||
|
webview: &mut WebView<'_, T>,
|
||||||
|
options: HttpRequestOptions,
|
||||||
|
callback: String,
|
||||||
|
error: String,
|
||||||
|
) {
|
||||||
|
crate::execute_promise(
|
||||||
|
webview,
|
||||||
|
move || {
|
||||||
|
let response_type = options.response_type.clone();
|
||||||
|
request(options)
|
||||||
|
.map_err(|e| crate::ErrorKind::Http(e.to_string()).into())
|
||||||
|
.map(|response| {
|
||||||
|
match response_type.unwrap_or(ResponseType::Json) {
|
||||||
|
ResponseType::Text => format!(r#""{}""#, response),
|
||||||
|
_ => response
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}
|
|
@ -50,6 +50,10 @@ error_chain! {
|
||||||
description("FileSystem Error")
|
description("FileSystem Error")
|
||||||
display("FileSystem Error: '{}'", t)
|
display("FileSystem Error: '{}'", t)
|
||||||
}
|
}
|
||||||
|
Http(t: String) {
|
||||||
|
description("Http Error")
|
||||||
|
display("Http Error: '{}'", t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue