1pub mod backend;
19#[cfg(feature = "browser")]
20pub mod browser;
21pub mod cookie;
22pub mod engine;
23pub mod error;
24pub mod eval;
25pub mod fetch;
26#[cfg(feature = "js-host")]
27pub mod host;
28#[cfg(feature = "js")]
29mod js;
30pub mod model;
31pub mod source;
32#[cfg(feature = "js-host")]
33pub mod state;
34mod transform;
35pub mod verify;
36mod xpath;
37
38pub use engine::Engine;
41pub use error::{BookSourceError, ConfigError, EvalError, FetchError, Result};
42pub use fetch::{FetchRequest, FetchResponse, Fetcher, ReqwestFetcher, is_challenge};
43pub use model::{BookInfo, BookListItem, Chapter, Toc, Volume};
44pub use source::{BookSource, Category, FetchMode, UrlOrRule};
45pub use verify::{Check, CheckStatus, DiagnoseReport, VerifyReport, diagnose, verify_sample};
46
47#[cfg(feature = "browser")]
49pub use browser::{
50 AuthDecision, BrowserCookie, BrowserFetcher, BrowserOptions, BrowserUi, Clearance,
51 EscalatingFetcher, LoginCriteria, LoginOutcome, LoginSignal, detect_browser,
52};
53
54#[cfg(test)]
57pub(crate) mod testutil {
58 #![allow(dead_code)]
61
62 use crate::source::BookSource;
63 use std::io::{Read, Write};
64 use std::net::TcpListener;
65
66 pub(crate) fn book_source(base: &str) -> BookSource {
68 serde_json::from_value(serde_json::json!({
69 "schema": "trnovel-booksource/v2",
70 "name": "t",
71 "url": base,
72 "bookInfo": {},
73 "toc": {"list": {"via": "raw"}, "name": {"via": "raw"}, "url": {"via": "raw"}},
74 "content": {"value": {"via": "raw"}}
75 }))
76 .expect("minimal book source")
77 }
78
79 pub(crate) fn spawn_echo_server() -> (String, std::thread::JoinHandle<()>) {
81 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
82 let base = format!("http://{}", listener.local_addr().unwrap());
83 let handle = std::thread::spawn(move || {
84 if let Ok((mut stream, _)) = listener.accept() {
85 let mut buf = [0u8; 8192];
86 let n = stream.read(&mut buf).unwrap_or(0);
87 let body = buf[..n].to_vec();
88 let head = format!(
89 "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
90 body.len()
91 );
92 let _ = stream.write_all(head.as_bytes());
93 let _ = stream.write_all(&body);
94 let _ = stream.flush();
95 }
96 });
97 (base, handle)
98 }
99
100 pub(crate) fn spawn_fixed_server(
102 raw_response: String,
103 ) -> (String, std::thread::JoinHandle<()>) {
104 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
105 let base = format!("http://{}", listener.local_addr().unwrap());
106 let handle = std::thread::spawn(move || {
107 if let Ok((mut stream, _)) = listener.accept() {
108 let mut buf = [0u8; 4096];
109 let _ = stream.read(&mut buf);
110 let _ = stream.write_all(raw_response.as_bytes());
111 let _ = stream.flush();
112 }
113 });
114 (base, handle)
115 }
116}