Skip to content

Commit

Permalink
feat: add peer id filter to interests (#456)
Browse files Browse the repository at this point in the history
* feat: add peer id filter to interests

Add simple ability to filter interests by a peer. Useful in debugging
the interests for a local node.

* fix: camelCase peerId
  • Loading branch information
nathanielc authored Aug 1, 2024
1 parent 21aa37e commit 1eae647
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 18 deletions.
2 changes: 1 addition & 1 deletion api-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To see how to make this your own, look here:
[README]((https://openapi-generator.tech))

- API version: 0.30.0
- Build date: 2024-07-30T18:32:38.681994-06:00[America/Denver]
- Build date: 2024-08-01T13:09:32.848445379-06:00[America/Denver]



Expand Down
18 changes: 18 additions & 0 deletions api-server/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ paths:
summary: cors
/experimental/interests:
get:
parameters:
- description: Only return interests from the specified peer ID.
explode: true
in: query
name: peerId
required: false
schema:
type: string
style: form
responses:
"200":
content:
Expand All @@ -307,6 +316,15 @@ paths:
description: Internal server error
summary: Get the interests stored on the node
options:
parameters:
- description: Only return interests from the specified peer ID.
explode: true
in: query
name: peerId
required: false
schema:
type: string
style: form
responses:
"200":
description: cors
Expand Down
28 changes: 24 additions & 4 deletions api-server/docs/default_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,21 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# ****
> models::InterestsGet ()
> models::InterestsGet (optional)
Get the interests stored on the node

### Required Parameters
This endpoint does not need any parameter.

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**optional** | **map[string]interface{}** | optional parameters | nil if no parameters

### Optional Parameters
Optional parameters are passed through a map[string]interface{}.

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**peer_id** | **String**| Only return interests from the specified peer ID. |

### Return type

Expand All @@ -304,11 +314,21 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# ****
> ()
> (optional)
cors

### Required Parameters
This endpoint does not need any parameter.

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**optional** | **map[string]interface{}** | optional parameters | nil if no parameters

### Optional Parameters
Optional parameters are passed through a map[string]interface{}.

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**peer_id** | **String**| Only return interests from the specified peer ID. |

### Return type

Expand Down
7 changes: 5 additions & 2 deletions api-server/examples/client/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,18 @@ fn main() {
);
}
Some("ExperimentalInterestsGet") => {
let result = rt.block_on(client.experimental_interests_get());
let result =
rt.block_on(client.experimental_interests_get(Some("peer_id_example".to_string())));
info!(
"{:?} (X-Span-ID: {:?})",
result,
(client.context() as &dyn Has<XSpanIdString>).get().clone()
);
}
Some("ExperimentalInterestsOptions") => {
let result = rt.block_on(client.experimental_interests_options());
let result = rt.block_on(
client.experimental_interests_options(Some("peer_id_example".to_string())),
);
info!(
"{:?} (X-Span-ID: {:?})",
result,
Expand Down
8 changes: 6 additions & 2 deletions api-server/examples/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,12 @@ where
/// Get the interests stored on the node
async fn experimental_interests_get(
&self,
peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsGetResponse, ApiError> {
info!(
"experimental_interests_get() - X-Span-ID: {:?}",
"experimental_interests_get({:?}) - X-Span-ID: {:?}",
peer_id,
context.get().0.clone()
);
Err(ApiError("Generic failure".into()))
Expand All @@ -255,10 +257,12 @@ where
/// cors
async fn experimental_interests_options(
&self,
peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsOptionsResponse, ApiError> {
info!(
"experimental_interests_options() - X-Span-ID: {:?}",
"experimental_interests_options({:?}) - X-Span-ID: {:?}",
peer_id,
context.get().0.clone()
);
Err(ApiError("Generic failure".into()))
Expand Down
8 changes: 8 additions & 0 deletions api-server/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,7 @@ where

async fn experimental_interests_get(
&self,
param_peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsGetResponse, ApiError> {
let mut client_service = self.client_service.clone();
Expand All @@ -1326,6 +1327,9 @@ where
// Query parameters
let query_string = {
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
if let Some(param_peer_id) = param_peer_id {
query_string.append_pair("peerId", &param_peer_id);
}
query_string.finish()
};
if !query_string.is_empty() {
Expand Down Expand Up @@ -1428,6 +1432,7 @@ where

async fn experimental_interests_options(
&self,
param_peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsOptionsResponse, ApiError> {
let mut client_service = self.client_service.clone();
Expand All @@ -1436,6 +1441,9 @@ where
// Query parameters
let query_string = {
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
if let Some(param_peer_id) = param_peer_id {
query_string.append_pair("peerId", &param_peer_id);
}
query_string.finish()
};
if !query_string.is_empty() {
Expand Down
14 changes: 12 additions & 2 deletions api-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,12 +302,14 @@ pub trait Api<C: Send + Sync> {
/// Get the interests stored on the node
async fn experimental_interests_get(
&self,
peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsGetResponse, ApiError>;

/// cors
async fn experimental_interests_options(
&self,
peer_id: Option<String>,
context: &C,
) -> Result<ExperimentalInterestsOptionsResponse, ApiError>;

Expand Down Expand Up @@ -445,11 +447,13 @@ pub trait ApiNoContext<C: Send + Sync> {
/// Get the interests stored on the node
async fn experimental_interests_get(
&self,
peer_id: Option<String>,
) -> Result<ExperimentalInterestsGetResponse, ApiError>;

/// cors
async fn experimental_interests_options(
&self,
peer_id: Option<String>,
) -> Result<ExperimentalInterestsOptionsResponse, ApiError>;

/// Get all new event keys since resume token
Expand Down Expand Up @@ -625,17 +629,23 @@ impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for Contex
/// Get the interests stored on the node
async fn experimental_interests_get(
&self,
peer_id: Option<String>,
) -> Result<ExperimentalInterestsGetResponse, ApiError> {
let context = self.context().clone();
self.api().experimental_interests_get(&context).await
self.api()
.experimental_interests_get(peer_id, &context)
.await
}

/// cors
async fn experimental_interests_options(
&self,
peer_id: Option<String>,
) -> Result<ExperimentalInterestsOptionsResponse, ApiError> {
let context = self.context().clone();
self.api().experimental_interests_options(&context).await
self.api()
.experimental_interests_options(peer_id, &context)
.await
}

/// Get all new event keys since resume token
Expand Down
56 changes: 54 additions & 2 deletions api-server/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,33 @@ where

// ExperimentalInterestsGet - GET /experimental/interests
hyper::Method::GET if path.matched(paths::ID_EXPERIMENTAL_INTERESTS) => {
let result = api_impl.experimental_interests_get(&context).await;
// Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response)
let query_params =
form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes())
.collect::<Vec<_>>();
let param_peer_id = query_params
.iter()
.filter(|e| e.0 == "peerId")
.map(|e| e.1.clone())
.next();
let param_peer_id = match param_peer_id {
Some(param_peer_id) => {
let param_peer_id =
<String as std::str::FromStr>::from_str(&param_peer_id);
match param_peer_id {
Ok(param_peer_id) => Some(param_peer_id),
Err(e) => return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from(format!("Couldn't parse query parameter peerId - doesn't match schema: {}", e)))
.expect("Unable to create Bad Request response for invalid query parameter peerId")),
}
}
None => None,
};

let result = api_impl
.experimental_interests_get(param_peer_id, &context)
.await;
let mut response = Response::new(Body::empty());
response.headers_mut().insert(
HeaderName::from_static("x-span-id"),
Expand Down Expand Up @@ -988,7 +1014,33 @@ where

// ExperimentalInterestsOptions - OPTIONS /experimental/interests
hyper::Method::OPTIONS if path.matched(paths::ID_EXPERIMENTAL_INTERESTS) => {
let result = api_impl.experimental_interests_options(&context).await;
// Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response)
let query_params =
form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes())
.collect::<Vec<_>>();
let param_peer_id = query_params
.iter()
.filter(|e| e.0 == "peerId")
.map(|e| e.1.clone())
.next();
let param_peer_id = match param_peer_id {
Some(param_peer_id) => {
let param_peer_id =
<String as std::str::FromStr>::from_str(&param_peer_id);
match param_peer_id {
Ok(param_peer_id) => Some(param_peer_id),
Err(e) => return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from(format!("Couldn't parse query parameter peerId - doesn't match schema: {}", e)))
.expect("Unable to create Bad Request response for invalid query parameter peerId")),
}
}
None => None,
};

let result = api_impl
.experimental_interests_options(param_peer_id, &context)
.await;
let mut response = Response::new(Body::empty());
response.headers_mut().insert(
HeaderName::from_static("x-span-id"),
Expand Down
14 changes: 14 additions & 0 deletions api/ceramic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,25 @@ paths:
/experimental/interests:
options:
summary: cors
parameters:
- name: peerId
in: query
required: false
description: Only return interests from the specified peer ID.
schema:
type: string
responses:
"200":
description: cors
get:
summary: Get the interests stored on the node
parameters:
- name: peerId
in: query
required: false
description: Only return interests from the specified peer ID.
schema:
type: string
responses:
"200":
description: success
Expand Down
32 changes: 28 additions & 4 deletions api/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,10 @@ where
))
}

pub async fn get_interests(&self) -> Result<ExperimentalInterestsGetResponse, ErrorResponse> {
pub async fn get_interests(
&self,
peer_id: Option<String>,
) -> Result<ExperimentalInterestsGetResponse, ErrorResponse> {
let interests = self
.interest
.range(
Expand All @@ -510,12 +513,31 @@ where
.await
.map_err(|e| ErrorResponse::new(format!("failed to get interests: {e}")))?;

let peer_id = peer_id
.map(|id| PeerId::from_str(&id))
.transpose()
.map_err(|e| ErrorResponse::new(format!("failed to parse peer_id: {e}")))?;

Ok(ExperimentalInterestsGetResponse::Success(
models::InterestsGet {
interests: interests
.into_iter()
.map(|i| models::InterestsGetInterestsInner {
data: i.to_string(),
.filter_map(|i| {
if peer_id.is_some() {
// return only matching interests
if i.peer_id() == peer_id {
Some(models::InterestsGetInterestsInner {
data: i.to_string(),
})
} else {
None
}
} else {
// return all interests
Some(models::InterestsGetInterestsInner {
data: i.to_string(),
})
}
})
.collect(),
},
Expand Down Expand Up @@ -841,9 +863,10 @@ where

async fn experimental_interests_get(
&self,
peer_id: Option<String>,
_context: &C,
) -> Result<ExperimentalInterestsGetResponse, ApiError> {
self.get_interests()
self.get_interests(peer_id)
.await
.or_else(|err| Ok(ExperimentalInterestsGetResponse::InternalServerError(err)))
}
Expand Down Expand Up @@ -982,6 +1005,7 @@ where
/// cors
async fn experimental_interests_options(
&self,
_peer_id: Option<String>,
_context: &C,
) -> Result<ceramic_api_server::ExperimentalInterestsOptionsResponse, ApiError> {
Ok(ceramic_api_server::ExperimentalInterestsOptionsResponse::Cors)
Expand Down
Loading

0 comments on commit 1eae647

Please sign in to comment.