Skip to content

Commit a772843

Browse files
spolukeelerm84
authored andcommitted
chore: Add status information and return connection tuple
1 parent cc4ae52 commit a772843

File tree

7 files changed

+127
-18
lines changed

7 files changed

+127
-18
lines changed

contract-tests/src/bin/sse-test-api/main.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,25 @@ struct Config {
5050
#[derive(Serialize, Debug)]
5151
#[serde(tag = "kind", rename_all = "camelCase")]
5252
enum EventType {
53-
Connected {},
54-
Event { event: Event },
55-
Comment { comment: String },
56-
Error { error: String },
53+
Connected {
54+
status: u16,
55+
headers: HashMap<String, String>,
56+
},
57+
Event {
58+
event: Event,
59+
},
60+
Comment {
61+
comment: String,
62+
},
63+
Error {
64+
error: String,
65+
},
5766
}
5867

5968
impl From<es::SSE> for EventType {
6069
fn from(event: es::SSE) -> Self {
6170
match event {
71+
es::SSE::Connected((status, headers)) => Self::Connected { status, headers },
6272
es::SSE::Event(evt) => Self::Event {
6373
event: Event {
6474
event_type: evt.event_type,
@@ -67,7 +77,6 @@ impl From<es::SSE> for EventType {
6777
},
6878
},
6979
es::SSE::Comment(comment) => Self::Comment { comment },
70-
es::SSE::Connected(_) => Self::Connected {},
7180
}
7281
}
7382
}

contract-tests/src/bin/sse-test-api/stream_entity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Inner {
3636
match stream.try_next().await {
3737
Ok(Some(event)) => {
3838
let event_type: EventType = event.into();
39-
if let EventType::Connected {} = event_type {
39+
if matches!(event_type, EventType::Connected { .. }) {
4040
continue;
4141
}
4242

eventsource-client/examples/tail.rs

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ fn tail_events(client: impl es::Client) -> impl Stream<Item = Result<(), ()>> {
4040
client
4141
.stream()
4242
.map_ok(|event| match event {
43+
es::SSE::Connected((status, _)) => {
44+
println!("got connected: \nstatus={}", status)
45+
}
4346
es::SSE::Event(ev) => {
4447
println!("got an event: {}\n{}", ev.event_type, ev.data)
4548
}

eventsource-client/src/client.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use log::{debug, info, trace, warn};
1313
use pin_project::pin_project;
1414
use std::{
1515
boxed,
16+
collections::HashMap,
1617
fmt::{self, Debug, Display, Formatter},
1718
future::Future,
1819
io::ErrorKind,
@@ -27,8 +28,8 @@ use tokio::{
2728
time::Sleep,
2829
};
2930

30-
use crate::config::ReconnectOptions;
3131
use crate::error::{Error, Result};
32+
use crate::{config::ReconnectOptions, ResponseWrapper};
3233

3334
use hyper::client::HttpConnector;
3435
use hyper_timeout::TimeoutConnector;
@@ -393,6 +394,7 @@ where
393394
let this = self.as_mut().project();
394395
if let Some(event) = this.event_parser.get_event() {
395396
return match event {
397+
SSE::Connected(_) => Poll::Ready(Some(Ok(event))),
396398
SSE::Event(ref evt) => {
397399
*this.last_event_id = evt.id.clone();
398400

@@ -437,15 +439,27 @@ where
437439
debug!("HTTP response: {:#?}", resp);
438440

439441
if resp.status().is_success() {
440-
let reply =
441-
Poll::Ready(Some(Ok(SSE::Connected(resp.headers().to_owned()))));
442442
self.as_mut().project().retry_strategy.reset(Instant::now());
443443
self.as_mut().reset_redirects();
444+
445+
let headers = resp.headers();
446+
let mut map = HashMap::new();
447+
for (key, value) in headers.iter() {
448+
let key = key.to_string();
449+
let value = match value.to_str() {
450+
Ok(value) => value.to_string(),
451+
Err(_) => String::from(""),
452+
};
453+
map.insert(key, value);
454+
}
455+
let status = resp.status().as_u16();
456+
444457
self.as_mut()
445458
.project()
446459
.state
447460
.set(State::Connected(resp.into_body()));
448-
return reply;
461+
462+
return Poll::Ready(Some(Ok(SSE::Connected((status, map)))));
449463
}
450464

451465
if resp.status() == 301 || resp.status() == 307 {
@@ -470,7 +484,10 @@ where
470484

471485
self.as_mut().reset_redirects();
472486
self.as_mut().project().state.set(State::New);
473-
return Poll::Ready(Some(Err(Error::UnexpectedResponse(resp.status()))));
487+
488+
return Poll::Ready(Some(Err(Error::UnexpectedResponse(
489+
ResponseWrapper::new(resp),
490+
))));
474491
}
475492
Err(e) => {
476493
// This seems basically impossible. AFAIK we can only get this way if we

eventsource-client/src/error.rs

+79-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,77 @@
1-
use hyper::StatusCode;
1+
use std::collections::HashMap;
2+
3+
use hyper::{body::Buf, Body, Response};
4+
5+
pub struct ResponseWrapper {
6+
response: Response<Body>,
7+
}
8+
9+
impl ResponseWrapper {
10+
pub fn new(response: Response<Body>) -> Self {
11+
Self { response }
12+
}
13+
pub fn status(&self) -> u16 {
14+
self.response.status().as_u16()
15+
}
16+
pub fn headers(&self) -> std::result::Result<HashMap<&str, &str>, HeaderError> {
17+
let headers = self.response.headers();
18+
let mut map = HashMap::new();
19+
for (key, value) in headers.iter() {
20+
let key = key.as_str();
21+
let value = match value.to_str() {
22+
Ok(value) => value,
23+
Err(err) => return Err(HeaderError::new(Box::new(err))),
24+
};
25+
map.insert(key, value);
26+
}
27+
Ok(map)
28+
}
29+
30+
pub async fn body_bytes(self) -> Result<Vec<u8>> {
31+
let body = self.response.into_body();
32+
33+
let buf = match hyper::body::aggregate(body).await {
34+
Ok(buf) => buf,
35+
Err(err) => return Err(Error::HttpStream(Box::new(err))),
36+
};
37+
38+
Ok(buf.chunk().to_vec())
39+
}
40+
}
41+
42+
impl std::fmt::Debug for ResponseWrapper {
43+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44+
f.debug_struct("ResponseWrapper")
45+
.field("status", &self.status())
46+
.finish()
47+
}
48+
}
49+
50+
/// Error type for invalid response headers encountered in ResponseWrapper.
51+
#[derive(Debug)]
52+
pub struct HeaderError {
53+
/// Wrapped inner error providing details about the header issue.
54+
inner_error: Box<dyn std::error::Error + Send + Sync + 'static>,
55+
}
56+
57+
impl HeaderError {
58+
/// Constructs a new `HeaderError` wrapping an existing error.
59+
pub fn new(err: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
60+
HeaderError { inner_error: err }
61+
}
62+
}
63+
64+
impl std::fmt::Display for HeaderError {
65+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66+
write!(f, "Invalid response header: {}", self.inner_error)
67+
}
68+
}
69+
70+
impl std::error::Error for HeaderError {
71+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
72+
Some(self.inner_error.as_ref())
73+
}
74+
}
275

376
/// Error type returned from this library's functions.
477
#[derive(Debug)]
@@ -8,7 +81,7 @@ pub enum Error {
881
/// An invalid request parameter
982
InvalidParameter(Box<dyn std::error::Error + Send + Sync + 'static>),
1083
/// The HTTP response could not be handled.
11-
UnexpectedResponse(StatusCode),
84+
UnexpectedResponse(ResponseWrapper),
1285
/// An error reading from the HTTP response body.
1386
HttpStream(Box<dyn std::error::Error + Send + Sync + 'static>),
1487
/// The HTTP response stream ended
@@ -32,7 +105,10 @@ impl std::fmt::Display for Error {
32105
TimedOut => write!(f, "timed out"),
33106
StreamClosed => write!(f, "stream closed"),
34107
InvalidParameter(err) => write!(f, "invalid parameter: {err}"),
35-
UnexpectedResponse(status_code) => write!(f, "unexpected response: {status_code}"),
108+
UnexpectedResponse(r) => {
109+
let status = r.status();
110+
write!(f, "unexpected response: {status}")
111+
}
36112
HttpStream(err) => write!(f, "http error: {err}"),
37113
Eof => write!(f, "eof"),
38114
UnexpectedEof => write!(f, "unexpected eof"),

eventsource-client/src/event_parser.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
use std::{collections::VecDeque, convert::TryFrom, str::from_utf8};
1+
use std::{
2+
collections::{HashMap, VecDeque},
3+
convert::TryFrom,
4+
str::from_utf8,
5+
};
26

3-
use hyper::{body::Bytes, http::HeaderValue, HeaderMap};
7+
use hyper::body::Bytes;
48
use log::{debug, log_enabled, trace};
59
use pin_project::pin_project;
610

@@ -32,7 +36,7 @@ impl EventData {
3236

3337
#[derive(Debug, Eq, PartialEq)]
3438
pub enum SSE {
35-
Connected(HeaderMap<HeaderValue>),
39+
Connected((u16, HashMap<String, String>)),
3640
Event(Event),
3741
Comment(String),
3842
}

eventsource-client/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! .map_ok(|event| match event {
1616
//! SSE::Comment(comment) => println!("got a comment event: {:?}", comment),
1717
//! SSE::Event(evt) => println!("got an event: {}", evt.event_type),
18-
//! SSE::Connected(headers) => println!("got connection start with headers: {:?}", headers)
18+
//! SSE::Connected(_) => println!("got connected")
1919
//! })
2020
//! .map_err(|e| println!("error streaming events: {:?}", e));
2121
//! # while let Ok(Some(_)) = stream.try_next().await {}

0 commit comments

Comments
 (0)