aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Edgecumbe <git@esotericnonsense.com>2019-10-28 04:37:32 +0100
committerDaniel Edgecumbe <git@esotericnonsense.com>2019-10-28 04:37:32 +0100
commite15dc729da01f8b449e4dcc4ae0e6636ce2a5675 (patch)
tree85f72b3dffe450d28277043ae7e57a45769f0e3a
parent36d9a697adbc6bb4d749fe061a3988fe4f571097 (diff)
Initial work on deserializing JSONRPC exceptions
-rwxr-xr-xgenapi/main.py4
-rw-r--r--src/generated_methods.rs52
-rw-r--r--src/json_rpc.rs14
-rw-r--r--src/result.rs1
4 files changed, 40 insertions, 31 deletions
diff --git a/genapi/main.py b/genapi/main.py
index f8e198a..07f243b 100755
--- a/genapi/main.py
+++ b/genapi/main.py
@@ -649,7 +649,7 @@ let rpc_request: RpcRequest<{struct_name}> = RpcRequest::new(
\"SportsAPING/v1.0/{operation.name}\".to_owned(),
req
);
-self.req(rpc_request).map(|x| x.into_inner())
+self.req(rpc_request).map(|x| x.into_inner())?
"""
else:
# TODO this smells, repetition
@@ -658,7 +658,7 @@ let rpc_request: RpcRequest<()> = RpcRequest::new(
\"SportsAPING/v1.0/{operation.name}\".to_owned(),
()
);
-self.req(rpc_request).map(|x| x.into_inner())
+self.req(rpc_request).map(|x| x.into_inner())?
"""
function_signature = f"""fn {operation.name}({formatted_params_args}) ->
diff --git a/src/generated_methods.rs b/src/generated_methods.rs
index e72d329..edc9bd1 100644
--- a/src/generated_methods.rs
+++ b/src/generated_methods.rs
@@ -24,7 +24,7 @@ impl crate::client::BFClient {
listEventTypesRequest { filter, locale };
let rpc_request: RpcRequest<listEventTypesRequest> =
RpcRequest::new("SportsAPING/v1.0/listEventTypes".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of Competitions (i.e., World Cup 2013) associated with the markets selected by the MarketFilter. Currently only Football markets have an associated competition.
#[allow(dead_code)]
@@ -39,7 +39,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listCompetitions".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of time ranges in the granularity specified in the request (i.e. 3PM to 4PM, Aug 14th to Aug 15th) associated with the markets selected by the MarketFilter.
#[allow(dead_code)]
@@ -54,7 +54,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<listTimeRangesRequest> =
RpcRequest::new("SportsAPING/v1.0/listTimeRanges".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of Events (i.e, Reading vs. Man United) associated with the markets selected by the MarketFilter.
#[allow(dead_code)]
@@ -66,7 +66,7 @@ impl crate::client::BFClient {
let req: listEventsRequest = listEventsRequest { filter, locale };
let rpc_request: RpcRequest<listEventsRequest> =
RpcRequest::new("SportsAPING/v1.0/listEvents".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of market types (i.e. MATCH_ODDS, NEXT_GOAL) associated with the markets selected by the MarketFilter. The market types are always the same, regardless of locale.
#[allow(dead_code)]
@@ -81,7 +81,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listMarketTypes".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of Countries associated with the markets selected by the MarketFilter.
#[allow(dead_code)]
@@ -94,7 +94,7 @@ impl crate::client::BFClient {
listCountriesRequest { filter, locale };
let rpc_request: RpcRequest<listCountriesRequest> =
RpcRequest::new("SportsAPING/v1.0/listCountries".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of Venues (i.e. Cheltenham, Ascot) associated with the markets selected by the MarketFilter. Currently, only Horse Racing markets are associated with a Venue.
#[allow(dead_code)]
@@ -106,7 +106,7 @@ impl crate::client::BFClient {
let req: listVenuesRequest = listVenuesRequest { filter, locale };
let rpc_request: RpcRequest<listVenuesRequest> =
RpcRequest::new("SportsAPING/v1.0/listVenues".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of information about markets that does not change (or changes very rarely). You use listMarketCatalogue to retrieve the name of the market, the names of selections and other information about markets.
#[allow(dead_code)]
@@ -130,7 +130,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listMarketCatalogue".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of dynamic data about markets. Dynamic data includes prices, the status of the market, the status of selections, the traded volume, and the status of any orders you have placed in the market.
#[allow(dead_code)]
@@ -163,7 +163,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<listMarketBookRequest> =
RpcRequest::new("SportsAPING/v1.0/listMarketBook".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of dynamic data about a market and a specified runner. Dynamic data includes prices, the status of the market, the status of selections, the traded volume, and the status of any orders you have placed in the market.
#[allow(dead_code)]
@@ -200,7 +200,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<listRunnerBookRequest> =
RpcRequest::new("SportsAPING/v1.0/listRunnerBook".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a list of your current orders. Optionally you can filter and sort your current orders using the various parameters, setting none of the parameters will return all of your current orders, up to a maximum of 1000 bets, ordered BY_BET and sorted EARLIEST_TO_LATEST. To retrieve more than 1000 orders, you need to make use of the fromRecord and recordCount parameters.
#[allow(dead_code)]
@@ -236,7 +236,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listCurrentOrders".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Returns a List of bets based on the bet status, ordered by settled date
#[allow(dead_code)]
@@ -280,7 +280,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listClearedOrders".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Place new orders into market. LIMIT orders below the minimum bet size are allowed if there is an unmatched bet at the same price in the market. This operation is atomic in that all orders will be placed or none will be placed.
#[allow(dead_code)]
@@ -303,7 +303,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<placeOrdersRequest> =
RpcRequest::new("SportsAPING/v1.0/placeOrders".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Cancel all bets OR cancel all bets on a market OR fully or partially cancel particular orders on a market. Only LIMIT orders an be cancelled or partially cancelled once placed.
#[allow(dead_code)]
@@ -320,7 +320,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<cancelOrdersRequest> =
RpcRequest::new("SportsAPING/v1.0/cancelOrders".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// This operation is logically a bulk cancel followed by a bulk place. The cancel is completed first then the new orders are placed. The new orders will be placed atomically in that they will all be placed or none will be placed. In the case where the new orders cannot be placed the cancellations will not be rolled back. See ReplaceInstruction.
#[allow(dead_code)]
@@ -341,7 +341,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<replaceOrdersRequest> =
RpcRequest::new("SportsAPING/v1.0/replaceOrders".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Update non-exposure changing fields
#[allow(dead_code)]
@@ -358,7 +358,7 @@ impl crate::client::BFClient {
};
let rpc_request: RpcRequest<updateOrdersRequest> =
RpcRequest::new("SportsAPING/v1.0/updateOrders".to_owned(), req);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Retrieve profit and loss for a given list of markets. The values are calculated using matched bets and optionally settled bets. Only odds markets are implemented, markets of other types are silently ignored.
#[allow(dead_code)]
@@ -381,7 +381,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/listMarketProfitAndLoss".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Create/update default exposure limit for market groups of given type. New value and breach action will be immediately applied to existing instances of this type (unless overridden using setExposureLimitForMarketGroup). If default values are overridden for market groups (using setExposureLimitForMarketGroup), overrides will NOT be touched. In order to clear this limit "removeDefaultExposureLimitForMarketGroups" operation should be used. It's not allowed to set default limit to an empty limit (see type ExposureLimit).
#[allow(dead_code)]
@@ -402,7 +402,7 @@ impl crate::client::BFClient {
.to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Create/update exposure limit for a market group. New limit will be applied immediately (even if a default limit exists for this type). The limit will be deleted upon account action (see deleteMarketGroupExposureLimit) or when no active markets remain under market group. It is possible to "invalidate" default limit for a specific group by using a "empty" limit (see type ExposureLimit). Upon successful execution of the request, the effective limit for this group will be the one set by this request (Properties will NOT be inherited from default limit).
#[allow(dead_code)]
@@ -418,7 +418,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/setExposureLimitForMarketGroup".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Remove default exposure limit for a market group type. This operation will NOT remove/update any market group limits.
#[allow(dead_code)]
@@ -437,7 +437,7 @@ impl crate::client::BFClient {
.to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Delete exposure limit for a market group. If a default exposure limit exist for market type, it takes effect immediately.
#[allow(dead_code)]
@@ -453,7 +453,7 @@ impl crate::client::BFClient {
.to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Response to this request returns default group limit and group limits grouped by type. If marketGroupTypeFilter is not populated values for all types are returned. The response will always contain the default limit. It is possible to control which groups to return using marketGroupsFilter parameter. If marketGroupsFilter is not set all group limits are returned. If an emtpy list is passed only default limit(s) is returned. When marketGroupTypeFilter and marketGroupsFilter used together, all groups in marketGroupsFilter are required to be of same type (type used in marketGroupTypeFilter).
#[allow(dead_code)]
@@ -473,7 +473,7 @@ impl crate::client::BFClient {
.to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Unblock a market group after it has been blocked due to the breach of a previously set exposure limit.
#[allow(dead_code)]
@@ -488,7 +488,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/unblockMarketGroup".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Retrieves events from exposure reuse enabled events list. To edit this list use addExposureReuseEnabledEvents and removeExposureReuseEnabledEvents operations.
#[allow(dead_code)]
@@ -497,7 +497,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/getExposureReuseEnabledEvents".to_owned(),
(),
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Enables events for exposure reuse by appending them to the current list of events already enabled.
#[allow(dead_code)]
@@ -512,7 +512,7 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/addExposureReuseEnabledEvents".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
/// Removes events from exposure reuse enabled events list.
#[allow(dead_code)]
@@ -527,6 +527,6 @@ impl crate::client::BFClient {
"SportsAPING/v1.0/removeExposureReuseEnabledEvents".to_owned(),
req,
);
- self.req(rpc_request).map(|x| x.into_inner())
+ self.req(rpc_request).map(|x| x.into_inner())?
}
}
diff --git a/src/json_rpc.rs b/src/json_rpc.rs
index cd8ab1b..30520cc 100644
--- a/src/json_rpc.rs
+++ b/src/json_rpc.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with botfair. If not, see <http://www.gnu.org/licenses/>.
+use crate::result::{Error, Result};
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
@@ -39,7 +40,6 @@ impl<T> RpcRequest<T> {
#[derive(Debug, Deserialize)]
pub struct RpcError {
code: i32,
- // TODO: parse these. e.g. ANGX-0003 is exception 3
message: String,
}
@@ -47,15 +47,23 @@ pub struct RpcError {
pub struct RpcResponse<T> {
jsonrpc: String,
result: Option<T>,
+ // TODO custom serde deserializer?
error: Option<RpcError>,
id: String,
}
impl<T> RpcResponse<T> {
- pub fn into_inner(self) -> T {
+ // TODO: rustic way to perform this?
+ pub fn into_inner(self) -> Result<T> {
// TODO check these? do we care?
let _ = self.jsonrpc;
let _ = self.id;
- self.result.expect("unhandled API exception")
+ match self.error {
+ Some(rpc_error) => {
+ // parse out the error. ANGX-0001
+ Err(Error::APINGException(rpc_error.message))
+ }
+ None => Ok(self.result.expect("unhandled API exception")),
+ }
}
}
diff --git a/src/result.rs b/src/result.rs
index 285cea5..d885312 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -18,6 +18,7 @@
pub enum Error {
Io(std::io::Error),
Reqwest(reqwest::Error),
+ APINGException(String), // TODO generated_exceptions.rs
BFLoginFailure(String),
BFKeepAliveFailure(crate::client::KeepAliveError), // could be an enum
General(String),