mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-04-20 13:39:15 +00:00

* feat: implement a file streamer for file share Only server with hardcoded file path * bump valibot version * feat: add server-info gRPC module to serve server info * feat: add ssl cert and public key to peers state When peer is online, KK always have know its cert and pub key for future secure communication * feat: add grpc ts package * Enable "/refresh-worker-extension" rest API, grpc version isn't ready yet * update pnpm lock * ci: fix CI by moving protobuf install order * ci: fix * upgrade api due to valibot incompatibility * fix: use fs instead of bun shell to be compatible with windows * skip grpc pkg build on windows * feat: local network file transfer prototype working * fix: grpc build.ts * download next to 14 * ci: add ci env try to fix next * fix: hideRefreshBtn and a few other btns' hide API in iframe ext page * feat: disable NODE_TLS_REJECT_UNAUTHORIZED for extension HMR refresh * fix: manifest json schema with objectWithRest to allow any other fields in package.json * chore: update valibot and related dependencies to version 1.0.0-beta.9 in pnpm-lock.yaml * ci: add protobuf compiler installation to manifest-schema-upload workflow * refactor: move grpc code from jarvis to a separate grpc crate for easier testing * feat(file-transfer): POC multi file + directory file transfer * feat(file-transfer): replace file transfer recursive download in ts with rust * feat(file-transfer): implement on_progress event for file transfer * feat(file-transfer): report progress every 1MB instead of 100 iterations * feat(file-transfer): add progress bar * feat(file-transfer): UI * feat(file-transfer): add file transfer bucket info preview Show total size and number of files * feat(file-transfer): improve UX Show bucket info during confirm; improve progress bar UI, prevent inconsistent width * feat(grpc): skip build in Cloudflare Pages due to missing protoc * refactor: with cargo fix, unused imports removed * ci: debug cloudflare pages env var * fix(grpc): update environment variable access for Cloudflare Pages build check * fix(grpc): add error handling for protoc command in build script * chore: update kkrpc version to 0.0.13, remove kkrpc submodule, and enhance grpc build script logging - Updated kkrpc dependency version from 0.0.12 to 0.0.13 in package.json. - Removed the kkrpc submodule from the project. - Enhanced logging in the grpc build script to include additional Cloudflare Pages environment variables for better debugging. * fix(api): typescript error, remove base.json from tsconfig * chore: update pnpm lock * fix(api): update TypeScript configuration to extend base.json and clean up unused options * refactor(api): update TypeScript configuration to extend path-alias.json and enhance compiler options * fix(api): restore KunkunManifestPermission in PermissionUnion and update valibot import in schema tests * fix: missing trait error * fix: js require replaced with import * test: fix a unit test with a more robust method --------- Co-authored-by: Huakun Shen <huaukun.shen@huakunshen.com>
182 lines
6.3 KiB
Rust
182 lines
6.3 KiB
Rust
use super::model::ServerState;
|
|
use super::Protocol;
|
|
use crate::server::grpc::file_transfer::MyFileTransfer;
|
|
use crate::server::grpc::kunkun::KunkunService;
|
|
use axum::routing::{get, post};
|
|
use axum_server::tls_rustls::RustlsConfig;
|
|
use base64::prelude::*;
|
|
use grpc::{
|
|
file_transfer::file_transfer_server::FileTransferServer,
|
|
kunkun::kunkun_server::KunkunServer,
|
|
};
|
|
/// This module is responsible for controlling the main server
|
|
use obfstr::obfstr as s;
|
|
use std::sync::Mutex;
|
|
use std::{net::SocketAddr, sync::Arc};
|
|
use tauri::AppHandle;
|
|
use tonic::transport::Server as TonicServer;
|
|
use tower_http::cors::CorsLayer;
|
|
|
|
struct ServerOptions {
|
|
ssl_cert: Vec<u8>,
|
|
ssl_key: Vec<u8>,
|
|
}
|
|
|
|
async fn start_server(
|
|
protocol: Protocol,
|
|
server_addr: SocketAddr,
|
|
app_handle: AppHandle,
|
|
shtdown_handle: axum_server::Handle,
|
|
options: ServerOptions,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
let server_state = ServerState {
|
|
app_handle: app_handle.clone(),
|
|
};
|
|
let reflection_service = tonic_reflection::server::Builder::configure()
|
|
.register_encoded_file_descriptor_set(grpc::kunkun::FILE_DESCRIPTOR_SET)
|
|
.register_encoded_file_descriptor_set(grpc::file_transfer::FILE_DESCRIPTOR_SET)
|
|
.build()
|
|
.unwrap();
|
|
let file_transfer = MyFileTransfer {
|
|
app_handle: app_handle.clone(),
|
|
};
|
|
let kk_service = KunkunService {
|
|
app_handle: app_handle.clone(),
|
|
};
|
|
let grpc_router = TonicServer::builder()
|
|
.add_service(reflection_service)
|
|
.add_service(FileTransferServer::new(file_transfer))
|
|
.add_service(KunkunServer::new(kk_service))
|
|
.into_router();
|
|
let rest_router = axum::Router::new()
|
|
.route(
|
|
"/refresh-worker-extension",
|
|
post(super::rest::refresh_worker_extension),
|
|
)
|
|
.route("/info", get(super::rest::get_server_info))
|
|
.route("/download-file", get(super::rest::download_file))
|
|
// .route("/stream-file", get(super::rest::stream_file))
|
|
.layer(CorsLayer::permissive())
|
|
.with_state(server_state);
|
|
|
|
let combined_router = axum::Router::new()
|
|
.merge(grpc_router)
|
|
.merge(rest_router)
|
|
.layer(CorsLayer::permissive());
|
|
let svr = match protocol {
|
|
Protocol::Http => {
|
|
axum_server::bind(server_addr)
|
|
.handle(shtdown_handle)
|
|
.serve(combined_router.into_make_service())
|
|
.await
|
|
}
|
|
Protocol::Https => {
|
|
let tls_config = RustlsConfig::from_pem(options.ssl_cert, options.ssl_key).await?;
|
|
axum_server::bind_rustls(server_addr, tls_config)
|
|
.handle(shtdown_handle)
|
|
.serve(combined_router.into_make_service())
|
|
.await
|
|
}
|
|
};
|
|
Ok(svr?)
|
|
}
|
|
|
|
pub struct Server {
|
|
pub app_handle: AppHandle,
|
|
pub shtdown_handle: Arc<Mutex<Option<axum_server::Handle>>>,
|
|
pub protocol: Mutex<Protocol>,
|
|
pub port: u16,
|
|
pub server_handle: Arc<std::sync::Mutex<Option<tauri::async_runtime::JoinHandle<()>>>>,
|
|
pub ssl_cert: Vec<u8>,
|
|
pub ssl_key: Vec<u8>,
|
|
}
|
|
|
|
impl Server {
|
|
pub fn new(app_handle: AppHandle, port: u16, protocol: Protocol) -> Self {
|
|
let (key_pem, cert_pem) = if cfg!(debug_assertions) {
|
|
// In debug mode, use the base64 encoded certs from env
|
|
let cert_pem = BASE64_STANDARD
|
|
.decode(s!(env!("BASE64_CERT_PEM")).to_string())
|
|
.expect("Failed to decode cert_pem");
|
|
let key_pem = BASE64_STANDARD
|
|
.decode(s!(env!("BASE64_KEY_PEM")).to_string())
|
|
.expect("Failed to decode key_pem");
|
|
(key_pem, cert_pem)
|
|
} else {
|
|
// In release mode, generate new self-signed certs every time app starts for safety
|
|
let rsa = crypto::RsaCrypto::generate_rsa().expect("Failed to generate RSA key pair");
|
|
crypto::ssl::generate_self_signed_certificate(&rsa, 365)
|
|
.expect("Failed to generate self-signed certificate")
|
|
};
|
|
Self {
|
|
app_handle,
|
|
protocol: Mutex::new(protocol),
|
|
port,
|
|
server_handle: Arc::new(std::sync::Mutex::new(None)),
|
|
shtdown_handle: Arc::new(Mutex::new(None)),
|
|
ssl_cert: cert_pem,
|
|
ssl_key: key_pem,
|
|
}
|
|
}
|
|
|
|
pub async fn set_server_protocol(&self, protocol: Protocol) {
|
|
let mut p = self.protocol.lock().unwrap();
|
|
*p = protocol;
|
|
}
|
|
|
|
pub fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut server_handle = self.server_handle.lock().unwrap();
|
|
let mut shtdown_handle = self.shtdown_handle.lock().unwrap();
|
|
if server_handle.is_some() {
|
|
return Err("Server is already running".into());
|
|
}
|
|
let server_addr: SocketAddr = format!("[::]:{}", self.port).parse()?;
|
|
let app_handle = self.app_handle.clone();
|
|
let _shutdown_handle = axum_server::Handle::new();
|
|
*shtdown_handle = Some(_shutdown_handle.clone());
|
|
let protocol = self.protocol.lock().unwrap().clone();
|
|
let ssl_cert = self.ssl_cert.clone();
|
|
let ssl_key = self.ssl_key.clone();
|
|
|
|
*server_handle = Some(tauri::async_runtime::spawn(async move {
|
|
match start_server(
|
|
protocol,
|
|
server_addr,
|
|
app_handle,
|
|
_shutdown_handle,
|
|
ServerOptions { ssl_cert, ssl_key },
|
|
)
|
|
.await
|
|
{
|
|
Ok(_) => {}
|
|
Err(e) => {
|
|
eprintln!("Server start error: {}", e);
|
|
}
|
|
}
|
|
}));
|
|
Ok(())
|
|
}
|
|
|
|
pub fn stop(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut server_handle = self.server_handle.lock().unwrap();
|
|
let mut shtdown_handle = self.shtdown_handle.lock().unwrap();
|
|
match shtdown_handle.as_ref() {
|
|
Some(handle) => {
|
|
handle.shutdown();
|
|
}
|
|
None => {
|
|
return Err("Server is not running".into());
|
|
}
|
|
}
|
|
shtdown_handle.take();
|
|
// self.shutdown_tx.send(())?;
|
|
server_handle.take();
|
|
Ok(())
|
|
}
|
|
|
|
pub fn is_running(&self) -> bool {
|
|
self.server_handle.lock().unwrap().is_some()
|
|
&& self.shtdown_handle.lock().unwrap().is_some()
|
|
}
|
|
}
|