use crate::response; use disk::events::PlainEventsJsonQuery; use err::Error; use futures_core::Stream; use futures_util::StreamExt; use http::{header, Method, Request, Response, StatusCode}; use hyper::Body; use netpod::query::RawEventsQuery; use netpod::{get_url_query_pairs, log::*, Channel, NanoRange}; use netpod::{NodeConfigCached, APP_JSON_LINES}; use serde::Serialize; use url::Url; fn json_lines_stream(stream: S) -> impl Stream, Error>> where S: Stream>, I: Serialize, { stream.map(|k| { k.map(|k| { let mut a = serde_json::to_vec(&k).unwrap(); a.push(0xa); a }) }) } pub struct ListIndexFilesHttpFunction {} impl ListIndexFilesHttpFunction { pub fn prefix() -> &'static str { "/api/4/channelarchiver/list/indexfiles" } pub fn name() -> &'static str { "ListIndexFilesHttpFunction" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let s = archapp_wrap::archapp::archeng::indexfiles::list_index_files(conf); let s = futures_util::stream::unfold(s, |mut st| async move { let x = st.next().await; match x { Some(x) => match x { Ok(x) => { let mut x = serde_json::to_vec(&x).unwrap(); x.push(b'\n'); Some((Ok::<_, Error>(x), st)) } Err(e) => { error!("{:?}", e); None } }, None => None, } }); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } } pub struct ScanIndexFiles {} impl ScanIndexFiles { pub fn prefix() -> &'static str { "/api/4/channelarchiver/scan/indexfiles" } pub fn name() -> &'static str { "ScanIndexFiles" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let s = archapp_wrap::archapp::archeng::indexfiles::scan_index_files(conf.clone()); let s = json_lines_stream(s); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } } pub struct ScanChannels {} impl ScanChannels { pub fn prefix() -> &'static str { "/api/4/channelarchiver/scan/channels" } pub fn name() -> &'static str { "ScanChannels" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let s = archapp_wrap::archapp::archeng::indexfiles::scan_channels(conf.clone()); let s = json_lines_stream(s); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } } pub struct BlockRefStream {} impl BlockRefStream { pub fn prefix() -> &'static str { "/api/4/channelarchiver/blockrefstream" } pub fn name() -> &'static str { "BlockRefStream" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let range = NanoRange { beg: 0, end: u64::MAX }; let channel = Channel { backend: "".into(), name: "ARIDI-PCT:CURRENT".into(), }; let s = archapp_wrap::archapp::archeng::blockrefstream::blockref_stream(channel, range, conf.clone()); let s = s.map(|item| match item { Ok(item) => { use archapp_wrap::archapp::archeng::blockrefstream::BlockrefItem::*; match item { Blockref(_k, jsval) => Ok(jsval), JsVal(jsval) => Ok(jsval), } } Err(e) => Err(e), }); let s = json_lines_stream(s); let s = s.map(|item| match item { Ok(k) => Ok(k), Err(e) => { error!("observe error: {}", e); Err(e) } }); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } } pub struct BlockStream {} impl BlockStream { pub fn prefix() -> &'static str { "/api/4/channelarchiver/blockstream" } pub fn name() -> &'static str { "BlockStream" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let range = NanoRange { beg: 0, end: u64::MAX }; let channel = Channel { backend: "".into(), name: "ARIDI-PCT:CURRENT".into(), }; let url = Url::parse(&format!("dummy:{}", req.uri()))?; let pairs = get_url_query_pairs(&url); let read_queue = pairs.get("readQueue").unwrap_or(&"1".to_string()).parse()?; let s = archapp_wrap::archapp::archeng::blockrefstream::blockref_stream(channel, range.clone(), conf.clone()); let s = Box::pin(s); let s = archapp_wrap::archapp::archeng::blockstream::BlockStream::new(s, range.clone(), read_queue); let s = s.map(|item| match item { Ok(item) => { //use archapp_wrap::archapp::archeng::blockstream::BlockItem::*; Ok(item) } Err(e) => Err(e), }); let s = json_lines_stream(s); let s = s.map(|item| match item { Ok(k) => Ok(k), Err(e) => { error!("observe error: {}", e); Err(e) } }); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } } pub struct ListChannelsHttpFunction {} impl ListChannelsHttpFunction { pub fn prefix() -> &'static str { "/api/4/channelarchiver/list/channels" } pub fn name() -> &'static str { "ListChannelsHttpFunction" } pub fn should_handle(path: &str) -> Option { if path.starts_with(Self::prefix()) { Some(Self {}) } else { None } } pub async fn handle(&self, req: Request, node_config: &NodeConfigCached) -> Result, Error> { if req.method() != Method::GET { return Ok(response(StatusCode::NOT_ACCEPTABLE).body(Body::empty())?); } info!("{} handle uri: {:?}", Self::name(), req.uri()); let conf = node_config .node .channel_archiver .as_ref() .ok_or(Error::with_msg_no_trace( "this node is not configured as channel archiver", ))?; let s = archapp_wrap::archapp::archeng::list_all_channels(conf); let s = futures_util::stream::unfold(s, |mut st| async move { let x = st.next().await; match x { Some(x) => match x { Ok(x) => { let mut x = serde_json::to_vec(&x).unwrap(); x.push(b'\n'); Some((Ok::<_, Error>(x), st)) } Err(e) => { error!("{:?}", e); None } }, None => None, } }); Ok(response(StatusCode::OK) .header(header::CONTENT_TYPE, APP_JSON_LINES) .body(Body::wrap_stream(s))?) } }