feat: enhance desktop application startup diagnostics and logging

- Introduced a new `startup` module to capture and manage startup diagnostics.
- Implemented logging functionality with daily rotation and error reporting for application startup failures.
- Updated the main application run function to return an exit code based on startup success or failure.
- Added new dependencies for logging and diagnostics in `Cargo.toml`.
- Increased request timeout in the control service for improved stability.
- Expanded maximum search results in the federation module for better search capabilities.
This commit is contained in:
leookun
2026-08-30 03:19:01 +08:00
parent 44e2d8057a
commit fd7998e43c
24 changed files with 295 additions and 32 deletions
Generated
+114
View File
@@ -97,6 +97,28 @@ dependencies = [
"x11rb", "x11rb",
] ]
[[package]]
name = "ashpd"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f3f79755c74fd155000314eb349864caa787c6592eace6c6882dad873d9c39"
dependencies = [
"async-fs",
"async-net",
"enumflags2",
"futures-channel",
"futures-util",
"rand 0.9.5",
"raw-window-handle",
"serde",
"serde_repr",
"url",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"zbus",
]
[[package]] [[package]]
name = "asn1-rs" name = "asn1-rs"
version = "0.7.2" version = "0.7.2"
@@ -186,6 +208,17 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "async-fs"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5"
dependencies = [
"async-lock",
"blocking",
"futures-lite",
]
[[package]] [[package]]
name = "async-io" name = "async-io"
version = "2.6.0" version = "2.6.0"
@@ -215,6 +248,17 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "async-net"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
dependencies = [
"async-io",
"blocking",
"futures-lite",
]
[[package]] [[package]]
name = "async-process" name = "async-process"
version = "2.5.0" version = "2.5.0"
@@ -1132,6 +1176,7 @@ version = "0.1.5-beta.1"
dependencies = [ dependencies = [
"axum", "axum",
"cursor-server", "cursor-server",
"rfd",
"serde", "serde",
"serde_json", "serde_json",
"tauri", "tauri",
@@ -1145,6 +1190,7 @@ dependencies = [
"tokio", "tokio",
"tokio-util", "tokio-util",
"tracing", "tracing",
"tracing-appender",
"tracing-subscriber", "tracing-subscriber",
"url", "url",
] ]
@@ -1520,6 +1566,15 @@ dependencies = [
"syn 3.0.3", "syn 3.0.3",
] ]
[[package]]
name = "dlib"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a"
dependencies = [
"libloading",
]
[[package]] [[package]]
name = "dlopen2" name = "dlopen2"
version = "0.8.2" version = "0.8.2"
@@ -4555,6 +4610,12 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "pollster"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "1.15.0" version = "1.15.0"
@@ -5196,6 +5257,30 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "rfd"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed"
dependencies = [
"ashpd",
"block2",
"dispatch2",
"js-sys",
"log",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"pollster",
"raw-window-handle",
"urlencoding",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.14" version = "0.17.14"
@@ -6289,6 +6374,12 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "symlink"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@@ -7262,6 +7353,19 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-appender"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c"
dependencies = [
"crossbeam-channel",
"symlink",
"thiserror 2.0.20",
"time",
"tracing-subscriber",
]
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.31" version = "0.1.31"
@@ -7636,6 +7740,12 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "urlpattern" name = "urlpattern"
version = "0.3.0" version = "0.3.0"
@@ -7852,6 +7962,7 @@ dependencies = [
"cc", "cc",
"downcast-rs", "downcast-rs",
"rustix", "rustix",
"scoped-tls",
"smallvec", "smallvec",
"wayland-sys", "wayland-sys",
] ]
@@ -7910,6 +8021,8 @@ version = "0.31.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be"
dependencies = [ dependencies = [
"dlib",
"log",
"pkg-config", "pkg-config",
] ]
@@ -9028,6 +9141,7 @@ dependencies = [
"endi", "endi",
"enumflags2", "enumflags2",
"serde", "serde",
"url",
"winnow 1.0.4", "winnow 1.0.4",
"zcheapstr", "zcheapstr",
"zvariant_derive", "zvariant_derive",
+2
View File
@@ -14,6 +14,7 @@ tauri-build = { version = "2", features = [] }
[dependencies] [dependencies]
axum = "0.8" axum = "0.8"
cursor-server = { path = "../../../server" } cursor-server = { path = "../../../server" }
rfd = "0.15"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
tauri = { version = "2", features = ["tray-icon"] } tauri = { version = "2", features = ["tray-icon"] }
@@ -26,5 +27,6 @@ tauri-plugin-updater = "2"
tokio = { version = "1", features = ["time"] } tokio = { version = "1", features = ["time"] }
tokio-util = "0.7" tokio-util = "0.7"
tracing = "0.1" tracing = "0.1"
tracing-appender = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
url = "2" url = "2"
+28 -13
View File
@@ -1,5 +1,5 @@
use std::{ use std::{
process::Command, process::{Command, ExitCode},
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Mutex, Mutex,
@@ -19,7 +19,6 @@ use tauri::{
}; };
use tauri_plugin_opener::OpenerExt; use tauri_plugin_opener::OpenerExt;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[cfg(dev)] #[cfg(dev)]
use cursor_server::config::ConsoleSource; use cursor_server::config::ConsoleSource;
@@ -27,6 +26,7 @@ use cursor_server::{App, Config, Result};
#[cfg(not(dev))] #[cfg(not(dev))]
use crate::frontend; use crate::frontend;
use crate::startup::{self, StartupDiagnostics};
use crate::tray; use crate::tray;
pub(crate) const MAIN_WINDOW_LABEL: &str = "main"; pub(crate) const MAIN_WINDOW_LABEL: &str = "main";
@@ -141,16 +141,23 @@ fn create_main_window(
builder.build() builder.build()
} }
pub fn run() { pub fn run() -> ExitCode {
let started_by_autostart = std::env::args_os().any(|arg| arg == AUTOSTART_ARG); let diagnostics = match StartupDiagnostics::initialize() {
Ok(diagnostics) => diagnostics,
Err(error) => {
startup::report_logging_failure(error.as_ref());
return ExitCode::FAILURE;
}
};
tracing::info!(
version = env!("CARGO_PKG_VERSION"),
os = std::env::consts::OS,
architecture = std::env::consts::ARCH,
log_directory = %diagnostics.log_directory().display(),
"desktop starting"
);
tracing_subscriber::registry() let started_by_autostart = std::env::args_os().any(|arg| arg == AUTOSTART_ARG);
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "cursor_server=info".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let app = tauri::Builder::default() let app = tauri::Builder::default()
.invoke_handler(tauri::generate_handler![open_terminal_with_command]) .invoke_handler(tauri::generate_handler![open_terminal_with_command])
@@ -218,8 +225,14 @@ pub fn run() {
tray::create(app)?; tray::create(app)?;
Ok(()) Ok(())
}) })
.build(tauri::generate_context!()) .build(tauri::generate_context!());
.expect("failed to build Cursor BYOK desktop app"); let app = match app {
Ok(app) => app,
Err(error) => {
diagnostics.report_fatal(&error);
return ExitCode::FAILURE;
}
};
app.run(|app, event| match event { app.run(|app, event| match event {
RunEvent::WindowEvent { RunEvent::WindowEvent {
@@ -264,4 +277,6 @@ pub fn run() {
} => tray::show_main_window(app), } => tray::show_main_window(app),
_ => {} _ => {}
}); });
ExitCode::SUCCESS
} }
+1
View File
@@ -1,6 +1,7 @@
mod desktop; mod desktop;
#[cfg(not(dev))] #[cfg(not(dev))]
mod frontend; mod frontend;
mod startup;
mod tray; mod tray;
pub use desktop::run; pub use desktop::run;
+2 -2
View File
@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() { fn main() -> std::process::ExitCode {
cursor_byok_desktop::run(); cursor_byok_desktop::run()
} }
+139
View File
@@ -0,0 +1,139 @@
//! Captures startup diagnostics before the database and desktop runtime initialize.
use std::{error::Error, path::PathBuf};
use rfd::{MessageButtons, MessageDialog, MessageLevel};
use tracing_appender::{
non_blocking::WorkerGuard,
rolling::{RollingFileAppender, Rotation},
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
const LOG_DIRECTORY_NAME: &str = "logs";
const LOG_FILE_PREFIX: &str = "cursor-byok";
const LOG_FILE_SUFFIX: &str = "log";
const RETAINED_LOG_FILES: usize = 15;
type BoxError = Box<dyn Error + Send + Sync>;
pub(crate) struct StartupDiagnostics {
log_directory: PathBuf,
_writer_guard: WorkerGuard,
}
impl StartupDiagnostics {
pub(crate) fn initialize() -> Result<Self, BoxError> {
let log_directory = cursor_server::config::managed_data_dir()?.join(LOG_DIRECTORY_NAME);
std::fs::create_dir_all(&log_directory)?;
let file_appender = RollingFileAppender::builder()
.rotation(Rotation::DAILY)
.filename_prefix(LOG_FILE_PREFIX)
.filename_suffix(LOG_FILE_SUFFIX)
.max_log_files(RETAINED_LOG_FILES)
.build(&log_directory)?;
let (file_writer, writer_guard) = tracing_appender::non_blocking(file_appender);
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "cursor_byok_desktop=info,cursor_server=info".into());
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer())
.with(
tracing_subscriber::fmt::layer()
.with_ansi(false)
.with_writer(file_writer),
)
.try_init()?;
Ok(Self {
log_directory,
_writer_guard: writer_guard,
})
}
pub(crate) fn log_directory(&self) -> &std::path::Path {
&self.log_directory
}
pub(crate) fn report_fatal(&self, error: &(dyn Error + 'static)) {
let details = error_chain(error);
tracing::error!(
error = %details,
log_directory = %self.log_directory.display(),
"desktop failed to start"
);
show_fatal_dialog(&details, Some(&self.log_directory));
}
}
pub(crate) fn report_logging_failure(error: &(dyn Error + 'static)) {
let details = error_chain(error);
eprintln!("Cursor BYOK failed to initialize logging: {details}");
show_fatal_dialog(&details, None);
}
fn show_fatal_dialog(details: &str, log_directory: Option<&std::path::Path>) {
let log_guidance = match log_directory {
Some(directory) => format!(
"日志目录 / Log directory:\n{}\n\n请将最新的日志文件发送给开发者。\nPlease send the latest log file to the developer.",
directory.display()
),
None => "日志系统也未能启动,因此没有生成日志文件。\nLogging also failed to initialize, so no log file was created."
.to_owned(),
};
let description = format!(
"Cursor BYOK 无法启动 / failed to start.\n\n错误 / Error:\n{details}\n\n{log_guidance}"
);
let _ = MessageDialog::new()
.set_level(MessageLevel::Error)
.set_title("Cursor BYOK 启动失败 / Startup Error")
.set_description(description)
.set_buttons(MessageButtons::Ok)
.show();
}
fn error_chain(error: &(dyn Error + 'static)) -> String {
let mut details = error.to_string();
let mut source = error.source();
while let Some(cause) = source {
details.push_str("\nCaused by: ");
details.push_str(&cause.to_string());
source = cause.source();
}
details
}
#[cfg(test)]
mod tests {
use super::*;
use std::fmt;
#[derive(Debug)]
struct OuterError(std::io::Error);
impl fmt::Display for OuterError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("database initialization failed")
}
}
impl Error for OuterError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.0)
}
}
#[test]
fn fatal_report_includes_the_complete_error_chain() {
let error = OuterError(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"database file is read-only",
));
assert_eq!(
error_chain(&error),
"database initialization failed\nCaused by: database file is read-only"
);
}
}
+5 -1
View File
@@ -12,7 +12,11 @@ if (!existsSync(vite)) run(['ci'], desktopRoot);
run(['run', 'build:demo'], desktopRoot); run(['run', 'build:demo'], desktopRoot);
function run(args, cwd) { function run(args, cwd) {
const result = spawnSync(npm, args, { cwd, stdio: 'inherit' }); const result = spawnSync(npm, args, {
cwd,
stdio: 'inherit',
shell: process.platform === 'win32',
});
if (result.error) throw result.error; if (result.error) throw result.error;
if (result.status !== 0) process.exit(result.status ?? 1); if (result.status !== 0) process.exit(result.status ?? 1);
} }
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are now in Agent mode. You have EXITED your previous mode. Continue with the task in the new mode. You are now in Agent mode. You have EXITED your previous mode. Continue with the task in the new mode.
</system_reminder> </system_reminder>
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are now in Ask mode. You have EXITED your previous mode. Continue with the task in the new mode. You are now in Ask mode. You have EXITED your previous mode. Continue with the task in the new mode.
</system_reminder> </system_reminder>
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are compacting conversation history for future model turns. You are compacting conversation history for future model turns.
Produce a concise plain-text summary that preserves durable context: user goals, constraints, facts, decisions, files, commands, errors, tool outcomes, and pending follow-ups. Produce a concise plain-text summary that preserves durable context: user goals, constraints, facts, decisions, files, commands, errors, tool outcomes, and pending follow-ups.
Do not address the user. Do not mention compaction, summarization, or token limits. Do not address the user. Do not mention compaction, summarization, or token limits.
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<timestamp>{{TIMESTAMP}}</timestamp> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<timestamp>{{TIMESTAMP}}</timestamp>
<user_query> <user_query>
{{USER_QUERY}} {{USER_QUERY}}
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are now in Debug mode. You have EXITED your previous mode. Continue with the task in the new mode. You are now in Debug mode. You have EXITED your previous mode. Continue with the task in the new mode.
</system_reminder> </system_reminder>
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by Cursor {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by Cursor {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are now in Multitask mode. You have EXITED your previous mode. Continue with the task in the new mode. You are now in Multitask mode. You have EXITED your previous mode. Continue with the task in the new mode.
</system_reminder> </system_reminder>
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are now in Plan mode. You have EXITED your previous mode. Continue with the task in the new mode. You are now in Plan mode. You have EXITED your previous mode. Continue with the task in the new mode.
</system_reminder> </system_reminder>
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor. You are an AI coding assistant, powered by {{FAKE_MODEL_NAME}}. You operate in Cursor.
Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag. Your main goal is to follow the USER's instructions, which are denoted by the <user_query> tag.
-1
View File
@@ -1,4 +1,3 @@
<!-- Defines stable Cursor prompt content embedded by the server. -->
{{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder> {{OPEN_FILES}}{{SELECTED_CONTEXT}}{{ACTION_CONTEXT}}<system_reminder>
You are currently working inside a Task subagent. Your parent agent has delegated a clearly bounded assignment to you. Complete that assignment directly with the tools available in this session. The Task tool is unavailable inside subagents, so delegation cannot be nested. You are currently working inside a Task subagent. Your parent agent has delegated a clearly bounded assignment to you. Complete that assignment directly with the tools available in this session. The Task tool is unavailable inside subagents, so delegation cannot be nested.
</system_reminder> </system_reminder>
+1 -1
View File
@@ -169,7 +169,7 @@ impl ControlService {
.header(OS_HEADER, std::env::consts::OS) .header(OS_HEADER, std::env::consts::OS)
.header(APP_VERSION_HEADER, env!("CARGO_PKG_VERSION")) .header(APP_VERSION_HEADER, env!("CARGO_PKG_VERSION"))
.header(LANGUAGE_HEADER, language) .header(LANGUAGE_HEADER, language)
.timeout(std::time::Duration::from_secs(5)); .timeout(std::time::Duration::from_secs(60));
if let Some(disabled_ad_ids) = disabled_ad_ids.filter(|value| !value.is_empty()) { if let Some(disabled_ad_ids) = disabled_ad_ids.filter(|value| !value.is_empty()) {
request = request.header(DISABLED_AD_IDS_HEADER, disabled_ad_ids); request = request.header(DISABLED_AD_IDS_HEADER, disabled_ad_ids);
} }
+1 -1
View File
@@ -8,7 +8,7 @@ use crate::store::Store;
use super::{catalog, SearchEngine, SearchHit}; use super::{catalog, SearchEngine, SearchHit};
const RRF_K: f64 = 60.0; const RRF_K: f64 = 60.0;
const MAX_RESULTS: usize = 10; const MAX_RESULTS: usize = 30;
#[derive(Clone)] #[derive(Clone)]
pub struct WebSearch { pub struct WebSearch {
+2
View File
@@ -28,7 +28,9 @@ impl Store {
.max_connections(8) .max_connections(8)
.connect_with(options) .connect_with(options)
.await?; .await?;
tracing::info!("running database migrations");
sqlx::migrate!("./migrations").run(&pool).await?; sqlx::migrate!("./migrations").run(&pool).await?;
tracing::info!("database migrations completed");
Ok(Self { Ok(Self {
pool, pool,
writes: WriteCoordinator::default(), writes: WriteCoordinator::default(),