Adds push improvements
This commit is contained in:
Родитель
212b6fcfa7
Коммит
fbfa83c025
|
@ -27,6 +27,9 @@ open class TranscodingError(msg: String) : PushError(msg)
|
|||
open class RecordNotFoundError(msg: String) : PushError(msg)
|
||||
open class UrlParseError(msg: String) : PushError(msg)
|
||||
open class GeneralError(msg: String) : PushError(msg)
|
||||
open class JSONDeserializeError(msg: String) : PushError(msg)
|
||||
open class UAIDNotRecognizedError(msg: String) : PushError(msg)
|
||||
open class RequestError(msg: String) : PushError(msg)
|
||||
|
||||
/**
|
||||
* This should be considered private, but it needs to be public for JNA.
|
||||
|
@ -73,6 +76,9 @@ open class RustError : Structure() {
|
|||
31 -> return TranscodingError(message)
|
||||
32 -> return RecordNotFoundError(message)
|
||||
33 -> return UrlParseError(message)
|
||||
34 -> return JSONDeserializeError(message)
|
||||
35 -> return UAIDNotRecognizedError(message)
|
||||
36 -> return RequestError(message)
|
||||
-1 -> return InternalPanic(message)
|
||||
// Note: `1` is used as a generic catch all, but we
|
||||
// might as well handle the others the same way.
|
||||
|
|
|
@ -20,13 +20,17 @@ use viaduct::{header_names, status_codes, Headers, Request};
|
|||
use crate::config::PushConfiguration;
|
||||
use crate::error::{
|
||||
self,
|
||||
ErrorKind::{AlreadyRegisteredError, CommunicationError, CommunicationServerError},
|
||||
ErrorKind::{
|
||||
AlreadyRegisteredError, CommunicationError, CommunicationServerError,
|
||||
UAIDNotRecognizedError,
|
||||
},
|
||||
};
|
||||
use crate::storage::Store;
|
||||
|
||||
mod rate_limiter;
|
||||
pub use rate_limiter::PersistedRateLimiter;
|
||||
|
||||
const UAID_NOT_FOUND_ERRNO: u32 = 103;
|
||||
#[derive(Debug)]
|
||||
pub struct RegisterResponse {
|
||||
/// The UAID associated with the request
|
||||
|
@ -140,6 +144,38 @@ impl ConnectHttp {
|
|||
};
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
fn handle_response_error(&self, response: &viaduct::Response) -> error::Result<()> {
|
||||
// An error response, the extended object structure is retrieved from
|
||||
// https://autopush.readthedocs.io/en/latest/http.html#response
|
||||
#[derive(Deserialize)]
|
||||
struct ResponseError {
|
||||
pub errno: u32,
|
||||
pub message: String,
|
||||
}
|
||||
if response.is_server_error() {
|
||||
let response_error = response.json::<ResponseError>()?;
|
||||
return Err(CommunicationServerError(format!(
|
||||
"General Server Error: {}",
|
||||
response_error.message
|
||||
))
|
||||
.into());
|
||||
}
|
||||
if response.is_client_error() {
|
||||
let response_error = response.json::<ResponseError>()?;
|
||||
if response.status == status_codes::CONFLICT {
|
||||
return Err(AlreadyRegisteredError.into());
|
||||
}
|
||||
if response.status == status_codes::GONE && response_error.errno == UAID_NOT_FOUND_ERRNO
|
||||
{
|
||||
return Err(UAIDNotRecognizedError(response_error.message).into());
|
||||
}
|
||||
return Err(
|
||||
CommunicationError(format!("Unhandled client error {:?}", response)).into(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Connection for ConnectHttp {
|
||||
|
@ -193,40 +229,12 @@ impl Connection for ConnectHttp {
|
|||
});
|
||||
}
|
||||
let url = Url::parse(&url)?;
|
||||
let requested = match Request::post(url)
|
||||
let response = Request::post(url)
|
||||
.headers(self.headers()?)
|
||||
.json(&body)
|
||||
.send()
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(
|
||||
CommunicationServerError(format!("Could not fetch endpoint: {}", e)).into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
if requested.is_server_error() {
|
||||
return Err(CommunicationServerError("General Server error".to_string()).into());
|
||||
}
|
||||
if requested.is_client_error() {
|
||||
if requested.status == status_codes::CONFLICT {
|
||||
return Err(AlreadyRegisteredError.into());
|
||||
}
|
||||
return Err(CommunicationError(format!(
|
||||
"Unhandled client error {} : {:?}",
|
||||
requested.status,
|
||||
String::from_utf8_lossy(&requested.body)
|
||||
))
|
||||
.into());
|
||||
}
|
||||
let response: Value = match requested.json() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(
|
||||
CommunicationServerError(format!("Could not parse response: {:?}", e)).into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
.send()?;
|
||||
self.handle_response_error(&response)?;
|
||||
let response: Value = response.json()?;
|
||||
|
||||
if self.uaid.is_none() {
|
||||
self.uaid = response["uaid"].as_str().map(ToString::to_string);
|
||||
|
@ -270,18 +278,14 @@ impl Connection for ConnectHttp {
|
|||
if &self.options.sender_id == "test" {
|
||||
return Ok(true);
|
||||
}
|
||||
match Request::delete(Url::parse(&url)?)
|
||||
let response = Request::delete(Url::parse(&url)?)
|
||||
.headers(self.headers()?)
|
||||
.send()
|
||||
{
|
||||
Ok(_) => {
|
||||
if channel_id.is_none() {
|
||||
self.uaid = None;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
Err(e) => Err(CommunicationServerError(format!("Could not unsubscribe: {}", e)).into()),
|
||||
.send()?;
|
||||
self.handle_response_error(&response)?;
|
||||
if channel_id.is_none() {
|
||||
self.uaid = None;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Update the push server with the new OS push authorization token
|
||||
|
@ -309,16 +313,12 @@ impl Connection for ConnectHttp {
|
|||
);
|
||||
let mut body = HashMap::new();
|
||||
body.insert("token", new_token);
|
||||
match Request::put(Url::parse(&url)?)
|
||||
let response = Request::put(Url::parse(&url)?)
|
||||
.json(&body)
|
||||
.headers(self.headers()?)
|
||||
.send()
|
||||
{
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) => {
|
||||
Err(CommunicationServerError(format!("Could not update token: {}", e)).into())
|
||||
}
|
||||
}
|
||||
.send()?;
|
||||
self.handle_response_error(&response)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Get a list of server known channels. If it differs from what we have, reset the UAID, and refresh channels.
|
||||
|
@ -349,7 +349,7 @@ impl Connection for ConnectHttp {
|
|||
&options.sender_id,
|
||||
&self.uaid.clone().unwrap(),
|
||||
);
|
||||
let request = match Request::get(Url::parse(&url)?)
|
||||
let response = match Request::get(Url::parse(&url)?)
|
||||
.headers(self.headers()?)
|
||||
.send()
|
||||
{
|
||||
|
@ -362,22 +362,8 @@ impl Connection for ConnectHttp {
|
|||
.into());
|
||||
}
|
||||
};
|
||||
if request.is_server_error() {
|
||||
return Err(CommunicationServerError("Server error".to_string()).into());
|
||||
}
|
||||
if request.is_client_error() {
|
||||
return Err(CommunicationError(format!("Unhandled client error {:?}", request)).into());
|
||||
}
|
||||
let payload: Payload = match request.json() {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
return Err(CommunicationServerError(format!(
|
||||
"Could not fetch channel_list: Bad Response {:?}",
|
||||
e
|
||||
))
|
||||
.into());
|
||||
}
|
||||
};
|
||||
self.handle_response_error(&response)?;
|
||||
let payload: Payload = response.json()?;
|
||||
if payload.uaid != self.uaid.clone().unwrap() {
|
||||
return Err(
|
||||
CommunicationServerError("Invalid Response from server".to_string()).into(),
|
||||
|
@ -411,7 +397,16 @@ impl Connection for ConnectHttp {
|
|||
return Ok(false);
|
||||
}
|
||||
let local_channels: HashSet<String> = channels.iter().cloned().collect();
|
||||
let remote_channels: HashSet<String> = HashSet::from_iter(self.channel_list()?);
|
||||
let remote_channels: HashSet<String> = match self.channel_list() {
|
||||
Ok(v) => HashSet::from_iter(v),
|
||||
Err(e) => match e.kind() {
|
||||
UAIDNotRecognizedError(_) => {
|
||||
self.uaid = None;
|
||||
return Ok(false);
|
||||
}
|
||||
_ => return Err(e),
|
||||
},
|
||||
};
|
||||
|
||||
// verify both lists match. Either side could have lost it's mind.
|
||||
if remote_channels != local_channels {
|
||||
|
|
|
@ -12,6 +12,8 @@ error_support::define_error! {
|
|||
ErrorKind {
|
||||
(StorageSqlError, rusqlite::Error),
|
||||
(UrlParseError, url::ParseError),
|
||||
(JSONDeserializeError, serde_json::Error),
|
||||
(RequestError, viaduct::Error),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +31,7 @@ pub enum ErrorKind {
|
|||
CommunicationError(String),
|
||||
|
||||
/// An error returned from the registration Server
|
||||
#[error("Communication Server Error: {0:?}")]
|
||||
#[error("Communication Server Error: {0}")]
|
||||
CommunicationServerError(String),
|
||||
|
||||
/// Channel is already registered, generate new channelID
|
||||
|
@ -56,6 +58,18 @@ pub enum ErrorKind {
|
|||
/// A failure to parse a URL.
|
||||
#[error("URL parse error: {0:?}")]
|
||||
UrlParseError(#[from] url::ParseError),
|
||||
|
||||
/// A failure deserializing json.
|
||||
#[error("Failed to parse json: {0}")]
|
||||
JSONDeserializeError(#[from] serde_json::Error),
|
||||
|
||||
/// The UAID was not recognized by the server
|
||||
#[error("Unrecognized UAID: {0}")]
|
||||
UAIDNotRecognizedError(String),
|
||||
|
||||
/// Was unable to send request to server
|
||||
#[error("Unable to send request to server: {0}")]
|
||||
RequestError(#[from] viaduct::Error),
|
||||
}
|
||||
|
||||
// Note, be sure to duplicate errors in the Kotlin side
|
||||
|
@ -74,6 +88,9 @@ impl ErrorKind {
|
|||
ErrorKind::TranscodingError(_) => 31,
|
||||
ErrorKind::RecordNotFoundError(_, _) => 32,
|
||||
ErrorKind::UrlParseError(_) => 33,
|
||||
ErrorKind::JSONDeserializeError(_) => 34,
|
||||
ErrorKind::UAIDNotRecognizedError(_) => 35,
|
||||
ErrorKind::RequestError(_) => 36,
|
||||
};
|
||||
ffi_support::ErrorCode::new(code)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче