Tauri 提供界面 + 使用 rust 實現連接遠程 linux 服務器、發送文件、執行命令一、Tauri 概述
tauri 是一個用于構建跨平臺桌面應用程序的工具和框架。它的目標是通過將 web 技術與本地功能結合,使開發者能夠以簡單、高效的方式創建現代的桌面應用。
以下是 Tauri 的一些主要特點和概述:
跨平臺支持:Tauri 允許你構建跨平臺的桌面應用程序,它支持 windows、macos 和 Linux 等常見的操作系統。你可以使用一套代碼庫在多個平臺上構建應用程序。基于 Web 技術:Tauri 使用 Web 技術作為應用程序的前端開發語言。你可以使用 html、css 和 JavaScript(或其他 Web 前端框架)來構建應用程序的用戶界面。原生功能訪問:Tauri 提供了訪問原生功能的接口,讓你可以從前端代碼中直接調用本地操作系統的功能,如文件系統、網絡、系統通知等。這樣,你可以創建出與本地應用程序類似的功能和體驗。嵌入式 Web 渲染引擎:Tauri 使用嵌入式的 Web 渲染引擎(如 webview 或 WebKitGTK)來渲染應用程序的界面。這使得應用程序可以直接在桌面環境中運行,而無需依賴外部的瀏覽器。豐富的生態系統:Tauri 生態系統提供了許多有用的功能和庫,如打包工具、插件系統、前端構建工具等,以便于應用程序的開發和部署。靈活的擴展性:Tauri 允許你通過使用 Rust 和 JavaScript 進行擴展,從而實現更復雜的功能。你可以編寫原生 Rust 代碼來訪問底層的系統功能,并使用 JavaScript 與前端代碼進行交互。
總的來說,Tauri 提供了一個快速、簡單的方式來開發跨平臺的桌面應用程序。通過結合 Web 技術和原生功能,你可以創建出功能豐富、具有優秀用戶體驗的桌面應用。無論是構建獨立的應用程序,還是將現有的 Web 應用轉化為桌面應用,Tauri 都是一個強大的選擇。
二、界面預覽

三、代碼參考1、main.rs代碼語言:javascript代碼運行次數:0運行復制
// Prevents additional console window on Windows in release, DO NOT REMOVE!!#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]#![allow(unused_assignments)] // 禁用未使用賦值的警告use std::io::{Read, Write};use std::path::Path;use ssh2::Session;// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command#[tauri::command]fn go(ip_with_port: &str, username: &str, password: &str, local_file_path: &str, target_file_path: &str, command: &str) { publish(ip_with_port, username, password, local_file_path, target_file_path, command)}fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![go]) .run(tauri::generate_context!()) .expect("error while running tauri application");}const PROGRESS_UPDATE_INTERVAL: usize = 1024 * 1024; // 每傳輸 1MB 打印一次進度信息// 發布fn publish(ip_with_port: &str, username: &str, password: &str, local_file_path: &str, target_file_path: &str, command: &str) { // 連接遠程服務器 let tcp = std::net::TcpStream::connect(ip_with_port).unwrap(); // 連接到遠程服務器 let mut sess = Session::new().unwrap(); // 創建一個新的會話 sess.set_tcp_stream(tcp); // 設置會話的 TCP 流 sess.handshake().unwrap(); // 進行握手 sess.userauth_password(username, password).unwrap(); // 使用用戶名和密碼進行身份驗證 // 傳輸文件 let file_size = get_file_size(local_file_path); // 獲取文件大小 let mut channel = sess.scp_send(Path::new(target_file_path), 0o644, file_size, None).unwrap(); // 創建一個新的 SCP 通道 let mut file = std::fs::File::open(local_file_path).unwrap(); // 打開本地文件 let mut buffer = Vec::new(); // 創建一個空的字節向量 file.read_to_end(&mut buffer).unwrap(); // 讀取文件內容 let mut total_bytes_sent = 0; // 已發送的總字節數 let mut total_mb = (file_size as f64) / (1024.0 * 1024.0); // 文件總大小(MB) total_mb = (total_mb * 100.0).round() / 100.0; // 保留2位小數 let mut transferred_mb = 0.0; // 已傳輸的文件大小(MB) // 記錄已發送文件的大小 let mut bytes_sent = 0; // 已發送的字節數 for (i, chunk) in buffer.chunks(PROGRESS_UPDATE_INTERVAL).enumerate() { // 循環發送文件內容 // 循環發送,發完為止! while bytes_sent < chunk.len() { let result = channel.write(chunk).unwrap(); // 發送文件內容 bytes_sent += result; // 更新已發送的字節數 } total_bytes_sent += bytes_sent; // 更新已發送的總字節數 bytes_sent = 0; // 重置已發送的字節數 transferred_mb = (total_bytes_sent as f64) / (1024.0 * 1024.0); // 更新已傳輸的文件大小(MB) transferred_mb = (transferred_mb * 100.0).round() / 100.0; // 保留2位小數 if (i + 1) * PROGRESS_UPDATE_INTERVAL <= buffer.len() { // 如果還有剩余的文件內容需要發送 let progress = (total_bytes_sent as f64) / (file_size as f64) * 100.0; // 計算傳輸進度 println!("進度: {:.2}% ({:.2} MB / {:.2} MB)", progress, transferred_mb, total_mb); // 打印傳輸進度信息 } else { // 文件傳輸完畢 println!("進度: 100% 文件傳輸完畢!"); } } channel.send_eof().unwrap(); // 發送 EOF 標志 // 執行遠程命令 let mut channel = sess.channel_session().unwrap(); // 創建一個新的會話通道 channel.exec(command).unwrap(); // 執行命令 let mut output = Vec::new(); // 創建一個空的字節向量 channel.read_to_end(&mut output).unwrap(); // 讀取命令輸出 println!("{}", String::from_utf8_lossy(&output)); // 打印命令輸出}// 獲取文件大小fn get_file_size(file_path: &str) -> u64 { std::fs::metadata(file_path) // 獲取文件元數據 .map(|metadata| metadata.len()) // 獲取文件大小 .unwrap_or(0) // 如果獲取失敗,則返回 0}
2、App.vue代碼語言:javascript代碼運行次數:0運行復制
<script setup lang="ts">import Greet from "./components/Greet.vue";</script><template> <div class="container"> <h1>Spring Boot 程序發布工具!</h1> <div class="tips">程序發布 = 連接 Linux + 發送文件 + 執行命令</div> <Greet /> </div></template><style scoped>.tips { color: #666666; margin-bottom: 10px;}</style>
3、Greet.vue代碼語言:javascript代碼運行次數:0運行復制
<template> <form class="row" @submit.prevent="go"> <input v-model="ipWithPort" placeholder="IP地址:端口號"/> <input v-model="username" placeholder="賬號"/> <input v-model="password" placeholder="密碼" type="password"/> <input v-model="filePath" placeholder="本地文件路徑"/> <input v-model="targetPath" placeholder="目標文件路徑"/> <input v-model="command" placeholder="命令"/> <button type="submit">執行!</button> </form> <p>{{result}}</p></template><script setup lang="ts">import {ref} from "vue";import {invoke} from "@tauri-apps/api/tauri";// IP地址和端口號:ip:portconst ipWithPort = ref("222.222.222.222:22");// 賬號const username = ref("root");// 密碼const password = ref("root");// 本地文件路徑const filePath = ref("C:\Users\Administrator\Desktop\app.jar");// 目標文件路徑const targetPath = ref("/home/zibo/app.jar");// 命令const command = ref("pwd");// 執行結果const result = ref("未開始執行!");async function go() { result.value = "執行中..."; await invoke("go", {ipWithPort: ipWithPort.value, username: username.value, password: password.value, localFilePath: filePath.value, targetFilePath: targetPath.value, command: command.value}); result.value = "執行完畢!";}</script><style>.row { display: flex; flex-direction: column; margin: 0 10px;}.row input { margin-bottom: 10px;}</style>
4、依賴代碼語言:javascript代碼運行次數:0運行復制
# ssh2ssh2 = "0.9.4"