search database has to be a file, as in-memory dbs are per connection
Some checks failed
Build Multiarch Container Image / call-reusable-workflow (push) Has been cancelled
Some checks failed
Build Multiarch Container Image / call-reusable-workflow (push) Has been cancelled
This commit is contained in:
parent
97cf9db9ff
commit
b8ed5b1cdf
50
Cargo.lock
generated
50
Cargo.lock
generated
@ -201,6 +201,7 @@ dependencies = [
|
|||||||
"r2d2_sqlite",
|
"r2d2_sqlite",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
@ -452,6 +453,16 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fallible-iterator"
|
name = "fallible-iterator"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -464,6 +475,12 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.30"
|
version = "1.0.30"
|
||||||
@ -887,9 +904,15 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "little-hesinde"
|
name = "little-hesinde"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"calibre-db",
|
"calibre-db",
|
||||||
"clap",
|
"clap",
|
||||||
@ -1435,6 +1458,19 @@ version = "0.1.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
@ -1657,6 +1693,18 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tera"
|
name = "tera"
|
||||||
version = "1.19.1"
|
version = "1.19.1"
|
||||||
|
@ -19,5 +19,6 @@ FROM scratch
|
|||||||
COPY --from=builder /app /app
|
COPY --from=builder /app /app
|
||||||
CMD ["/app", "--listen-address", "[::]:3000", "--", "/library"]
|
CMD ["/app", "--listen-address", "[::]:3000", "--", "/library"]
|
||||||
|
|
||||||
|
ENV TMPDIR=/
|
||||||
VOLUME ["/library"]
|
VOLUME ["/library"]
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
@ -12,5 +12,6 @@ r2d2 = "0.8.10"
|
|||||||
r2d2_sqlite = "0.24.0"
|
r2d2_sqlite = "0.24.0"
|
||||||
rusqlite = { version = "0.31.0", features = ["bundled", "time"] }
|
rusqlite = { version = "0.31.0", features = ["bundled", "time"] }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
tempfile = "3.10.1"
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
time = { workspace = true }
|
time = { workspace = true }
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
//! Error handling for calibre database access.
|
//! Error handling for calibre database access.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use tempfile::PersistError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use time::error::Parse;
|
use time::error::Parse;
|
||||||
|
|
||||||
@ -16,9 +19,15 @@ pub enum DataStoreError {
|
|||||||
/// Error connecting to the database.
|
/// Error connecting to the database.
|
||||||
#[error("connection error")]
|
#[error("connection error")]
|
||||||
ConnectionError(#[from] r2d2::Error),
|
ConnectionError(#[from] r2d2::Error),
|
||||||
/// Error wparsing a datetime from the database.
|
/// Error parsing a datetime from the database.
|
||||||
#[error("failed to parse datetime")]
|
#[error("failed to parse datetime")]
|
||||||
DateTimeError(#[from] Parse),
|
DateTimeError(#[from] Parse),
|
||||||
|
/// Error creating the search database.
|
||||||
|
#[error("failed to create search database")]
|
||||||
|
SearchDbError(#[from] io::Error),
|
||||||
|
/// Error marking the search database as persistent.
|
||||||
|
#[error("failed to persist search database")]
|
||||||
|
PersistSearchDbError(#[from] PersistError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert an SQLite error into a proper NoResults one if the query
|
/// Convert an SQLite error into a proper NoResults one if the query
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
//! Provide search funcitonality for calibre.
|
//! Provide search funcitonality for calibre.
|
||||||
//!
|
//!
|
||||||
//! Because the calibre database can not be disturbed (it is treated as read-only)
|
//! Because the calibre database can not be disturbed (it is treated as read-only)
|
||||||
//! it attaches an in-memory database and inserts the relevant data into a
|
//! it attaches a temporary database and inserts the relevant data into a
|
||||||
//! virtual table leveraging fts5 (https://www.sqlite.org/fts5.html). Full-text search is run on
|
//! virtual table leveraging fts5 (https://www.sqlite.org/fts5.html). Full-text search is run on
|
||||||
//! that virtual table.
|
//! that virtual table.
|
||||||
|
|
||||||
use r2d2::{Pool, PooledConnection};
|
use r2d2::{Pool, PooledConnection};
|
||||||
use r2d2_sqlite::SqliteConnectionManager;
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
use rusqlite::named_params;
|
use rusqlite::named_params;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
use crate::data::{book::Book, error::DataStoreError};
|
use crate::data::{book::Book, error::DataStoreError};
|
||||||
|
|
||||||
@ -31,11 +32,16 @@ const SEARCH_INIT_QUERY: &str = "INSERT INTO search.fts(book_id, data)
|
|||||||
LEFT JOIN main.series AS s ON b2s.series = s.id
|
LEFT JOIN main.series AS s ON b2s.series = s.id
|
||||||
GROUP BY b.id";
|
GROUP BY b.id";
|
||||||
|
|
||||||
/// Attach the fts in-memory database to the read-only calibre database.
|
/// Attach the fts temporary database to the read-only calibre database.
|
||||||
pub(crate) fn attach(pool: &Pool<SqliteConnectionManager>) -> Result<(), DataStoreError> {
|
pub(crate) fn attach(pool: &Pool<SqliteConnectionManager>) -> Result<(), DataStoreError> {
|
||||||
let conn = pool.get()?;
|
let conn = pool.get()?;
|
||||||
|
let tmpfile = NamedTempFile::new()?;
|
||||||
|
let (_, path) = tmpfile.keep()?;
|
||||||
|
|
||||||
conn.execute("ATTACH DATABASE ':memory:' AS search", [])?;
|
conn.execute(
|
||||||
|
&format!("ATTACH DATABASE '{}' AS search", path.to_string_lossy()),
|
||||||
|
[],
|
||||||
|
)?;
|
||||||
init(&conn)?;
|
init(&conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "little-hesinde"
|
name = "little-hesinde"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
|
@ -76,7 +76,7 @@ pub mod opds {
|
|||||||
pub mod templates;
|
pub mod templates;
|
||||||
|
|
||||||
pub const APP_NAME: &str = "little-hesinde";
|
pub const APP_NAME: &str = "little-hesinde";
|
||||||
pub const VERSION: &str = "0.2.1";
|
pub const VERSION: &str = "0.2.3";
|
||||||
|
|
||||||
/// Internal marker data in lieu of a proper `Accept` header.
|
/// Internal marker data in lieu of a proper `Accept` header.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
Loading…
Reference in New Issue
Block a user