Clean up diff
This commit is contained in:
parent
3a20a7c2f8
commit
6d40097bcd
11 changed files with 52 additions and 164 deletions
|
|
@ -59,6 +59,26 @@ export class DeterministicAgent extends debugging.InMemoryFileSystem {
|
|||
this.data.settings = { ...initialSettings };
|
||||
}
|
||||
|
||||
private static isCreateDocumentRequest(
|
||||
input: RequestInfo | URL,
|
||||
init: RequestInit | undefined
|
||||
): boolean {
|
||||
const method =
|
||||
init?.method ??
|
||||
(typeof Request !== "undefined" && input instanceof Request
|
||||
? input.method
|
||||
: "GET");
|
||||
if (method.toUpperCase() !== "POST") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const url =
|
||||
input instanceof URL
|
||||
? input
|
||||
: new URL(typeof input === "string" ? input : input.url);
|
||||
return /\/documents\/?$/.test(url.pathname);
|
||||
}
|
||||
|
||||
public async init(
|
||||
fetchImplementation: typeof globalThis.fetch
|
||||
): Promise<void> {
|
||||
|
|
@ -118,7 +138,7 @@ export class DeterministicAgent extends debugging.InMemoryFileSystem {
|
|||
this.nextCreateResponseDrop === undefined,
|
||||
`Client ${this.clientId} already has a create response drop armed`
|
||||
);
|
||||
let resolveDropped!: () => void;
|
||||
let resolveDropped: () => void = () => {};
|
||||
const dropped = new Promise<void>((resolve) => {
|
||||
resolveDropped = resolve;
|
||||
});
|
||||
|
|
@ -461,23 +481,4 @@ export class DeterministicAgent extends debugging.InMemoryFileSystem {
|
|||
};
|
||||
}
|
||||
|
||||
private static isCreateDocumentRequest(
|
||||
input: RequestInfo | URL,
|
||||
init: RequestInit | undefined
|
||||
): boolean {
|
||||
const method =
|
||||
init?.method ??
|
||||
(typeof Request !== "undefined" && input instanceof Request
|
||||
? input.method
|
||||
: "GET");
|
||||
if (method.toUpperCase() !== "POST") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const url =
|
||||
input instanceof URL
|
||||
? input
|
||||
: new URL(typeof input === "string" ? input : input.url);
|
||||
return /\/documents\/?$/.test(url.pathname);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ cd sync-server
|
|||
cargo test export_bindings
|
||||
cd -
|
||||
|
||||
# Both target directories contain only generated bindings — wipe and copy
|
||||
# Wipe and copy generated bindings into the consuming workspace
|
||||
rm -f frontend/sync-client/src/services/types/*.ts
|
||||
rm -f frontend/history-ui/src/lib/types/*.ts
|
||||
cp -r sync-server/bindings/* frontend/sync-client/src/services/types/
|
||||
cp -r sync-server/bindings/* frontend/history-ui/src/lib/types/
|
||||
|
||||
cd frontend
|
||||
npm run lint
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ missing_debug_implementations = "warn"
|
|||
[lints.clippy]
|
||||
await_holding_lock = "warn"
|
||||
dbg_macro = "warn"
|
||||
empty_enum = "warn"
|
||||
disallowed_macros = { level = "deny", priority = 1 }
|
||||
empty_enums = "warn"
|
||||
enum_glob_use = "warn"
|
||||
exit = "warn"
|
||||
filter_map_next = "warn"
|
||||
|
|
|
|||
4
sync-server/clippy.toml
Normal file
4
sync-server/clippy.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
disallowed-macros = [
|
||||
{ path = "std::eprintln", reason = "use log::info! or log::warn! instead" },
|
||||
{ path = "std::println", reason = "use log::info! or log::warn! instead" },
|
||||
]
|
||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
AppState,
|
||||
database::models::{DocumentId, DocumentVersion, VaultId, VaultUpdateId},
|
||||
},
|
||||
errors::{SyncServerError, client_error, not_found_error, server_error},
|
||||
errors::{SyncServerError, not_found_error, server_error},
|
||||
utils::normalize::normalize,
|
||||
};
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ pub async fn fetch_document_version(
|
|||
)?;
|
||||
|
||||
if result.document_id != document_id {
|
||||
return Err(client_error(anyhow!(
|
||||
return Err(not_found_error(anyhow!(
|
||||
"Document with document id `{document_id}` does not have a version with id \
|
||||
`{vault_update_id}`",
|
||||
)));
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
AppState,
|
||||
database::models::{DocumentId, VaultId, VaultUpdateId},
|
||||
},
|
||||
errors::{SyncServerError, client_error, not_found_error, server_error},
|
||||
errors::{SyncServerError, not_found_error, server_error},
|
||||
utils::normalize::normalize,
|
||||
};
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ pub async fn fetch_document_version_content(
|
|||
)?;
|
||||
|
||||
if result.document_id != document_id {
|
||||
return Err(client_error(anyhow!(
|
||||
return Err(not_found_error(anyhow!(
|
||||
"Document with document id `{document_id}` does not have a version with id \
|
||||
`{vault_update_id}`",
|
||||
)));
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
use anyhow::anyhow;
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
app_state::{
|
||||
AppState,
|
||||
database::models::{DocumentId, DocumentVersion, VaultId},
|
||||
},
|
||||
errors::{SyncServerError, not_found_error, server_error},
|
||||
utils::normalize::normalize,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FetchLatestDocumentVersionPathParams {
|
||||
#[serde(deserialize_with = "normalize")]
|
||||
vault_id: VaultId,
|
||||
|
||||
document_id: DocumentId,
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
pub async fn fetch_latest_document_version(
|
||||
Path(FetchLatestDocumentVersionPathParams {
|
||||
vault_id,
|
||||
document_id,
|
||||
}): Path<FetchLatestDocumentVersionPathParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<DocumentVersion>, SyncServerError> {
|
||||
debug!("Fetching latest document version for document `{document_id}` in vault `{vault_id}`");
|
||||
|
||||
let latest_version = state
|
||||
.database
|
||||
.get_latest_document(&vault_id, &document_id, None)
|
||||
.await
|
||||
.map_err(server_error)?
|
||||
.map_or_else(
|
||||
|| {
|
||||
Err(not_found_error(anyhow!(
|
||||
"Document with id `{document_id}` not found",
|
||||
)))
|
||||
},
|
||||
Ok,
|
||||
)?;
|
||||
|
||||
Ok(Json(latest_version.into()))
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
use axum::{
|
||||
Json,
|
||||
extract::{Path, Query, State},
|
||||
};
|
||||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::responses::FetchLatestDocumentsResponse;
|
||||
use crate::{
|
||||
app_state::{
|
||||
AppState,
|
||||
database::models::{VaultId, VaultUpdateId},
|
||||
},
|
||||
errors::{SyncServerError, server_error},
|
||||
utils::normalize::normalize,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FetchLatestDocumentsPathParams {
|
||||
#[serde(deserialize_with = "normalize")]
|
||||
vault_id: VaultId,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct QueryParams {
|
||||
since_update_id: Option<VaultUpdateId>,
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
pub async fn fetch_latest_documents(
|
||||
Path(FetchLatestDocumentsPathParams { vault_id }): Path<FetchLatestDocumentsPathParams>,
|
||||
Query(QueryParams { since_update_id }): Query<QueryParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<FetchLatestDocumentsResponse>, SyncServerError> {
|
||||
debug!("Fetching latest documents in vault `{vault_id}` since update ID `{since_update_id:?}`");
|
||||
|
||||
let documents = if let Some(since_update_id) = since_update_id {
|
||||
state
|
||||
.database
|
||||
.get_latest_documents_since(&vault_id, since_update_id, None, None)
|
||||
.await
|
||||
.map_err(server_error)
|
||||
} else {
|
||||
state
|
||||
.database
|
||||
.get_latest_documents(&vault_id, None, None)
|
||||
.await
|
||||
.map_err(server_error)
|
||||
}?;
|
||||
|
||||
Ok(Json(FetchLatestDocumentsResponse {
|
||||
last_update_id: documents
|
||||
.iter()
|
||||
.map(|doc| doc.vault_update_id)
|
||||
.max()
|
||||
.unwrap_or(since_update_id.unwrap_or(0)),
|
||||
latest_documents: documents,
|
||||
}))
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ use axum_extra::{
|
|||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{auth::auth, responses::PingResponse};
|
||||
use super::{auth::authenticate_for_vault, responses::PingResponse};
|
||||
use crate::{
|
||||
app_state::{AppState, database::models::VaultId},
|
||||
consts::SUPPORTED_API_VERSION,
|
||||
|
|
@ -31,8 +31,9 @@ pub async fn ping(
|
|||
) -> Result<Json<PingResponse>, SyncServerError> {
|
||||
debug!("Pinging vault `{vault_id}`");
|
||||
|
||||
let is_authenticated = maybe_auth_header
|
||||
.is_some_and(|auth_header| auth(&state, auth_header.token(), &vault_id).is_ok());
|
||||
let is_authenticated = maybe_auth_header.is_some_and(|auth_header| {
|
||||
authenticate_for_vault(&state, auth_header.token(), &vault_id).is_ok()
|
||||
});
|
||||
|
||||
Ok(Json(PingResponse {
|
||||
server_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use serde::{self, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::app_state::database::models::{
|
||||
DocumentVersion, DocumentVersionWithoutContent, VaultUpdateId,
|
||||
};
|
||||
use crate::app_state::database::models::{DocumentVersion, DocumentVersionWithoutContent};
|
||||
|
||||
/// Response to a ping request.
|
||||
#[derive(TS, Debug, Clone, Serialize)]
|
||||
|
|
@ -25,17 +23,6 @@ pub struct PingResponse {
|
|||
pub supported_api_version: u32,
|
||||
}
|
||||
|
||||
/// Response to a fetch latest documents request.
|
||||
#[derive(TS, Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct FetchLatestDocumentsResponse {
|
||||
pub latest_documents: Vec<DocumentVersionWithoutContent>,
|
||||
|
||||
/// The update ID of the latest document in the response.
|
||||
pub last_update_id: VaultUpdateId,
|
||||
}
|
||||
|
||||
/// Response to a create/update document request.
|
||||
#[derive(TS, Debug, Clone, Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ use std::{
|
|||
fs::{self, OpenOptions},
|
||||
io::{self, Write},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, Mutex},
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use log::warn;
|
||||
use tracing_subscriber::fmt::MakeWriter;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -93,6 +94,17 @@ impl RotatingFileWriter {
|
|||
SystemTime::now() >= inner.next_rotation_time
|
||||
}
|
||||
|
||||
fn lock_inner(&self) -> MutexGuard<'_, RotatingFileWriterInner> {
|
||||
match self.inner.lock() {
|
||||
Ok(inner) => inner,
|
||||
Err(poisoned) => {
|
||||
warn!("RotatingFileWriter mutex was poisoned, recovering");
|
||||
self.inner.clear_poison();
|
||||
poisoned.into_inner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open_or_create_log_file(inner: &mut RotatingFileWriterInner) -> io::Result<()> {
|
||||
// If we haven't reached rotation time and there's an existing log file, reuse it
|
||||
if !Self::should_rotate(inner)
|
||||
|
|
@ -132,10 +144,7 @@ impl RotatingFileWriter {
|
|||
|
||||
impl Write for RotatingFileWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let mut inner = self.inner.lock().unwrap_or_else(|poisoned| {
|
||||
eprintln!("RotatingFileWriter mutex was poisoned, recovering");
|
||||
poisoned.into_inner()
|
||||
});
|
||||
let mut inner = self.lock_inner();
|
||||
|
||||
// Reset file handle after poison recovery so the next branch
|
||||
// re-opens a valid file rather than writing to a potentially
|
||||
|
|
@ -154,10 +163,7 @@ impl Write for RotatingFileWriter {
|
|||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
let mut inner = self.inner.lock().unwrap_or_else(|poisoned| {
|
||||
eprintln!("RotatingFileWriter mutex was poisoned, recovering");
|
||||
poisoned.into_inner()
|
||||
});
|
||||
let mut inner = self.lock_inner();
|
||||
if let Some(ref mut file) = inner.current_file {
|
||||
file.flush()
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue