mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 04:00:21 +00:00 
			
		
		
		
	Refactored the runtime API handling
This commit is contained in:
		
							parent
							
								
									f03ca4e8f8
								
							
						
					
					
						commit
						e6789dcfeb
					
				@ -13,6 +13,7 @@ use crate::certificate::CERTIFICATE_FINGERPRINT;
 | 
				
			|||||||
use crate::encryption::ENCRYPTION;
 | 
					use crate::encryption::ENCRYPTION;
 | 
				
			||||||
use crate::environment::is_dev;
 | 
					use crate::environment::is_dev;
 | 
				
			||||||
use crate::network::get_available_port;
 | 
					use crate::network::get_available_port;
 | 
				
			||||||
 | 
					use crate::runtime_api::API_SERVER_PORT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The .NET server is started in a separate process and communicates with this
 | 
					// The .NET server is started in a separate process and communicates with this
 | 
				
			||||||
// runtime process via IPC. However, we do net start the .NET server in
 | 
					// runtime process via IPC. However, we do net start the .NET server in
 | 
				
			||||||
@ -31,7 +32,7 @@ pub fn dotnet_port(_token: APIToken) -> String {
 | 
				
			|||||||
    format!("{dotnet_server_port}")
 | 
					    format!("{dotnet_server_port}")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn start_dotnet_server(api_server_port: u16) {
 | 
					pub fn start_dotnet_server() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the secret password & salt and convert it to a base64 string:
 | 
					    // Get the secret password & salt and convert it to a base64 string:
 | 
				
			||||||
    let secret_password = BASE64_STANDARD.encode(ENCRYPTION.secret_password);
 | 
					    let secret_password = BASE64_STANDARD.encode(ENCRYPTION.secret_password);
 | 
				
			||||||
@ -47,8 +48,7 @@ pub fn start_dotnet_server(api_server_port: u16) {
 | 
				
			|||||||
    info!("Try to start the .NET server...");
 | 
					    info!("Try to start the .NET server...");
 | 
				
			||||||
    let server_spawn_clone = DOTNET_SERVER.clone();
 | 
					    let server_spawn_clone = DOTNET_SERVER.clone();
 | 
				
			||||||
    tauri::async_runtime::spawn(async move {
 | 
					    tauri::async_runtime::spawn(async move {
 | 
				
			||||||
        let api_port = api_server_port;
 | 
					        let api_port = *API_SERVER_PORT;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        let (mut rx, child) = match is_dev() {
 | 
					        let (mut rx, child) = match is_dev() {
 | 
				
			||||||
            true => {
 | 
					            true => {
 | 
				
			||||||
                // We are in the development environment, so we try to start a process
 | 
					                // We are in the development environment, so we try to start a process
 | 
				
			||||||
 | 
				
			|||||||
@ -7,4 +7,5 @@ pub mod api_token;
 | 
				
			|||||||
pub mod app_window;
 | 
					pub mod app_window;
 | 
				
			||||||
pub mod secret;
 | 
					pub mod secret;
 | 
				
			||||||
pub mod clipboard;
 | 
					pub mod clipboard;
 | 
				
			||||||
 | 
					pub mod runtime_api;
 | 
				
			||||||
pub mod certificate;
 | 
					pub mod certificate;
 | 
				
			||||||
@ -4,31 +4,13 @@
 | 
				
			|||||||
extern crate rocket;
 | 
					extern crate rocket;
 | 
				
			||||||
extern crate core;
 | 
					extern crate core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::collections::HashSet;
 | 
					 | 
				
			||||||
use once_cell::sync::Lazy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use log::{info, warn};
 | 
					use log::{info, warn};
 | 
				
			||||||
use rocket::figment::Figment;
 | 
					 | 
				
			||||||
use rocket::routes;
 | 
					 | 
				
			||||||
use rocket::config::{Shutdown};
 | 
					 | 
				
			||||||
use mindwork_ai_studio::app_window::start_tauri;
 | 
					use mindwork_ai_studio::app_window::start_tauri;
 | 
				
			||||||
use mindwork_ai_studio::certificate::{generate_certificate, CERTIFICATE, CERTIFICATE_PRIVATE_KEY};
 | 
					use mindwork_ai_studio::certificate::{generate_certificate};
 | 
				
			||||||
use mindwork_ai_studio::dotnet::start_dotnet_server;
 | 
					use mindwork_ai_studio::dotnet::start_dotnet_server;
 | 
				
			||||||
use mindwork_ai_studio::environment::is_dev;
 | 
					use mindwork_ai_studio::environment::is_dev;
 | 
				
			||||||
use mindwork_ai_studio::log::init_logging;
 | 
					use mindwork_ai_studio::log::init_logging;
 | 
				
			||||||
use mindwork_ai_studio::network::get_available_port;
 | 
					use mindwork_ai_studio::runtime_api::start_runtime_api;
 | 
				
			||||||
 | 
					 | 
				
			||||||
// The port used for the runtime API server. In the development environment, we use a fixed
 | 
					 | 
				
			||||||
// port, in the production environment we use the next available port. This differentiation
 | 
					 | 
				
			||||||
// is necessary because we cannot communicate the port to the .NET server in the development
 | 
					 | 
				
			||||||
// environment.
 | 
					 | 
				
			||||||
static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
					 | 
				
			||||||
    if is_dev() {
 | 
					 | 
				
			||||||
        5000
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        get_available_port().unwrap()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::main]
 | 
					#[tokio::main]
 | 
				
			||||||
async fn main() {
 | 
					async fn main() {
 | 
				
			||||||
@ -48,6 +30,7 @@ async fn main() {
 | 
				
			|||||||
    init_logging();
 | 
					    init_logging();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info!("Starting MindWork AI Studio:");
 | 
					    info!("Starting MindWork AI Studio:");
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    let working_directory = std::env::current_dir().unwrap();
 | 
					    let working_directory = std::env::current_dir().unwrap();
 | 
				
			||||||
    info!(".. The working directory is: '{working_directory:?}'");
 | 
					    info!(".. The working directory is: '{working_directory:?}'");
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -66,78 +49,7 @@ async fn main() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    generate_certificate();
 | 
					    generate_certificate();
 | 
				
			||||||
 | 
					    start_runtime_api();
 | 
				
			||||||
    let api_port = *API_SERVER_PORT;
 | 
					    start_dotnet_server();
 | 
				
			||||||
    info!("Try to start the API server on 'http://localhost:{api_port}'...");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The shutdown configuration for the runtime API server:
 | 
					 | 
				
			||||||
    let mut shutdown = Shutdown {
 | 
					 | 
				
			||||||
        // We do not want to use the Ctrl+C signal to stop the server:
 | 
					 | 
				
			||||||
        ctrlc: false,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Everything else is set to default for now:
 | 
					 | 
				
			||||||
        ..Shutdown::default()
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[cfg(unix)]
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // We do not want to use the termination signal to stop the server.
 | 
					 | 
				
			||||||
        // This option, however, is only available on Unix systems:
 | 
					 | 
				
			||||||
        shutdown.signals = HashSet::new();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Configure the runtime API server:
 | 
					 | 
				
			||||||
    let figment = Figment::from(rocket::Config::release_default())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // We use the next available port which was determined before:
 | 
					 | 
				
			||||||
        .merge(("port", api_port))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The runtime API server should be accessible only from the local machine:
 | 
					 | 
				
			||||||
        .merge(("address", "127.0.0.1"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // We do not want to use the Ctrl+C signal to stop the server:
 | 
					 | 
				
			||||||
        .merge(("ctrlc", false))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Set a name for the server:
 | 
					 | 
				
			||||||
        .merge(("ident", "AI Studio Runtime API"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Set the maximum number of workers and blocking threads:
 | 
					 | 
				
			||||||
        .merge(("workers", 3))
 | 
					 | 
				
			||||||
        .merge(("max_blocking", 12))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // No colors and emojis in the log output:
 | 
					 | 
				
			||||||
        .merge(("cli_colors", false))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Read the TLS certificate and key from the generated certificate data in-memory:
 | 
					 | 
				
			||||||
        .merge(("tls.certs", CERTIFICATE.get().unwrap()))
 | 
					 | 
				
			||||||
        .merge(("tls.key", CERTIFICATE_PRIVATE_KEY.get().unwrap()))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Set the shutdown configuration:
 | 
					 | 
				
			||||||
        .merge(("shutdown", shutdown));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Start the runtime API server in a separate thread. This is necessary
 | 
					 | 
				
			||||||
    // because the server is blocking, and we need to run the Tauri app in
 | 
					 | 
				
			||||||
    // parallel:
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    tauri::async_runtime::spawn(async move {
 | 
					 | 
				
			||||||
        rocket::custom(figment)
 | 
					 | 
				
			||||||
            .mount("/", routes![
 | 
					 | 
				
			||||||
                mindwork_ai_studio::dotnet::dotnet_port,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::dotnet::dotnet_ready,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::clipboard::set_clipboard,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::app_window::check_for_update,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::app_window::install_update,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::secret::get_secret,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::secret::store_secret,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::secret::delete_secret,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::environment::get_data_directory,
 | 
					 | 
				
			||||||
                mindwork_ai_studio::environment::get_config_directory,
 | 
					 | 
				
			||||||
            ])
 | 
					 | 
				
			||||||
            .ignite().await.unwrap()
 | 
					 | 
				
			||||||
            .launch().await.unwrap();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    start_dotnet_server(*API_SERVER_PORT);
 | 
					 | 
				
			||||||
    start_tauri();
 | 
					    start_tauri();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										94
									
								
								runtime/src/runtime_api.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								runtime/src/runtime_api.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					use std::collections::HashSet;
 | 
				
			||||||
 | 
					use log::info;
 | 
				
			||||||
 | 
					use once_cell::sync::Lazy;
 | 
				
			||||||
 | 
					use rocket::config::Shutdown;
 | 
				
			||||||
 | 
					use rocket::figment::Figment;
 | 
				
			||||||
 | 
					use rocket::routes;
 | 
				
			||||||
 | 
					use crate::certificate::{CERTIFICATE, CERTIFICATE_PRIVATE_KEY};
 | 
				
			||||||
 | 
					use crate::environment::is_dev;
 | 
				
			||||||
 | 
					use crate::network::get_available_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The port used for the runtime API server. In the development environment, we use a fixed
 | 
				
			||||||
 | 
					// port, in the production environment we use the next available port. This differentiation
 | 
				
			||||||
 | 
					// is necessary because we cannot communicate the port to the .NET server in the development
 | 
				
			||||||
 | 
					// environment.
 | 
				
			||||||
 | 
					pub static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
				
			||||||
 | 
					    if is_dev() {
 | 
				
			||||||
 | 
					        5000
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        get_available_port().unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn start_runtime_api() {
 | 
				
			||||||
 | 
					    let api_port = *API_SERVER_PORT;
 | 
				
			||||||
 | 
					    info!("Try to start the API server on 'http://localhost:{api_port}'...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The shutdown configuration for the runtime API server:
 | 
				
			||||||
 | 
					    let mut shutdown = Shutdown {
 | 
				
			||||||
 | 
					        // We do not want to use the Ctrl+C signal to stop the server:
 | 
				
			||||||
 | 
					        ctrlc: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Everything else is set to default for now:
 | 
				
			||||||
 | 
					        ..Shutdown::default()
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[cfg(unix)]
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // We do not want to use the termination signal to stop the server.
 | 
				
			||||||
 | 
					        // This option, however, is only available on Unix systems:
 | 
				
			||||||
 | 
					        shutdown.signals = HashSet::new();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Configure the runtime API server:
 | 
				
			||||||
 | 
					    let figment = Figment::from(rocket::Config::release_default())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // We use the next available port which was determined before:
 | 
				
			||||||
 | 
					        .merge(("port", api_port))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The runtime API server should be accessible only from the local machine:
 | 
				
			||||||
 | 
					        .merge(("address", "127.0.0.1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // We do not want to use the Ctrl+C signal to stop the server:
 | 
				
			||||||
 | 
					        .merge(("ctrlc", false))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set a name for the server:
 | 
				
			||||||
 | 
					        .merge(("ident", "AI Studio Runtime API"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the maximum number of workers and blocking threads:
 | 
				
			||||||
 | 
					        .merge(("workers", 3))
 | 
				
			||||||
 | 
					        .merge(("max_blocking", 12))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // No colors and emojis in the log output:
 | 
				
			||||||
 | 
					        .merge(("cli_colors", false))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Read the TLS certificate and key from the generated certificate data in-memory:
 | 
				
			||||||
 | 
					        .merge(("tls.certs", CERTIFICATE.get().unwrap()))
 | 
				
			||||||
 | 
					        .merge(("tls.key", CERTIFICATE_PRIVATE_KEY.get().unwrap()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the shutdown configuration:
 | 
				
			||||||
 | 
					        .merge(("shutdown", shutdown));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    // Start the runtime API server in a separate thread. This is necessary
 | 
				
			||||||
 | 
					    // because the server is blocking, and we need to run the Tauri app in
 | 
				
			||||||
 | 
					    // parallel:
 | 
				
			||||||
 | 
					    //
 | 
				
			||||||
 | 
					    tauri::async_runtime::spawn(async move {
 | 
				
			||||||
 | 
					        rocket::custom(figment)
 | 
				
			||||||
 | 
					            .mount("/", routes![
 | 
				
			||||||
 | 
					                crate::dotnet::dotnet_port,
 | 
				
			||||||
 | 
					                crate::dotnet::dotnet_ready,
 | 
				
			||||||
 | 
					                crate::clipboard::set_clipboard,
 | 
				
			||||||
 | 
					                crate::app_window::check_for_update,
 | 
				
			||||||
 | 
					                crate::app_window::install_update,
 | 
				
			||||||
 | 
					                crate::secret::get_secret,
 | 
				
			||||||
 | 
					                crate::secret::store_secret,
 | 
				
			||||||
 | 
					                crate::secret::delete_secret,
 | 
				
			||||||
 | 
					                crate::environment::get_data_directory,
 | 
				
			||||||
 | 
					                crate::environment::get_config_directory,
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					            .ignite().await.unwrap()
 | 
				
			||||||
 | 
					            .launch().await.unwrap();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user