Skip to content

Commit

Permalink
added user_id as an option parameter to getappointments cli command
Browse files Browse the repository at this point in the history
Signed-off-by: aruokhai <[email protected]>

removed todo

Signed-off-by: aruokhai <[email protected]>
  • Loading branch information
aruokhai committed Dec 21, 2023
1 parent 818f756 commit 143b826
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 14 deletions.
3 changes: 2 additions & 1 deletion teos/proto/teos/v2/appointment.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ package teos.v2;
import "common/teos/v2/appointment.proto";

message GetAppointmentsRequest {
// Request the information of appointments with specific locator.
// Request the information of appointments with specific locator and user_id (optional) .

bytes locator = 1;
optional bytes user_id_option = 2;
}

message GetAppointmentsResponse {
Expand Down
125 changes: 112 additions & 13 deletions teos/src/api/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::sync::{Arc, Condvar, Mutex};
use tonic::{Code, Request, Response, Status};
use triggered::Trigger;

use crate::extended_appointment::UUID;
use crate::protos as msgs;
use crate::protos::private_tower_services_server::PrivateTowerServices;
use crate::protos::public_tower_services_server::PublicTowerServices;
Expand Down Expand Up @@ -280,27 +279,40 @@ impl PrivateTowerServices for Arc<InternalAPI> {
.map_or("an unknown address".to_owned(), |a| a.to_string())
);

let mut matching_appointments = vec![];
let locator = Locator::from_slice(&request.into_inner().locator).map_err(|_| {
let req_data = request.into_inner();
let locator = Locator::from_slice(&req_data.locator).map_err(|_| {
Status::new(
Code::InvalidArgument,
"The provided locator does not match the expected format (16-byte hexadecimal string)",
)
})?;

for (_, appointment) in self
let mut appointments: Vec<(UserId, Appointment)> = self
.watcher
.get_watcher_appointments_with_locator(locator)
.into_values()
.map(|appointment| (appointment.user_id, appointment.inner))
.collect();

let user_id_option = req_data.user_id_option;
if let Some(user_id_slice) = user_id_option {
let user_id = UserId::from_slice(&user_id_slice).map_err(|_| {
Status::new(
Code::InvalidArgument,
"The Provided user_id does not match expected format (33-byte hex string)",
)
})?;
appointments.retain(|(appointment_user_id, _)| *appointment_user_id == user_id);
}

let mut matching_appointments: Vec<common_msgs::AppointmentData> = appointments
.into_iter()
{
matching_appointments.push(common_msgs::AppointmentData {
.map(|(_, appointment)| common_msgs::AppointmentData {
appointment_data: Some(
common_msgs::appointment_data::AppointmentData::Appointment(
appointment.inner.into(),
),
common_msgs::appointment_data::AppointmentData::Appointment(appointment.into()),
),
})
}
.collect();

for (_, tracker) in self
.watcher
Expand Down Expand Up @@ -390,7 +402,6 @@ impl PrivateTowerServices for Arc<InternalAPI> {
Some((info, locators)) => Ok(Response::new(msgs::GetUserResponse {
available_slots: info.available_slots,
subscription_expiry: info.subscription_expiry,
// TODO: Should make `get_appointments` queryable using the (user_id, locator) pair for consistency.
appointments: locators
.into_iter()
.map(|locator| locator.to_vec())
Expand Down Expand Up @@ -511,14 +522,97 @@ mod tests_private_api {

let locator = Locator::new(get_random_tx().txid()).to_vec();
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest { locator }))
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator,
user_id_option: None,
}))
.await
.unwrap()
.into_inner();

assert!(matches!(response, msgs::GetAppointmentsResponse { .. }));
}

#[tokio::test]
async fn test_get_appointments_with_and_without_user_id() {
// setup
let (internal_api, _s) = create_api().await;
let random_txn = get_random_tx();
let (user_sk1, user_pk1) = get_random_keypair();
let user_id1 = UserId(user_pk1);
let (user_sk2, user_pk2) = get_random_keypair();
let user_id2 = UserId(user_pk2);
internal_api.watcher.register(user_id1).unwrap();
internal_api.watcher.register(user_id2).unwrap();
let appointment1 =
generate_dummy_appointment_with_user(user_id1, Some(&random_txn.clone().txid()))
.1
.inner;
let signature1 = cryptography::sign(&appointment1.to_vec(), &user_sk1).unwrap();
let appointment2 =
generate_dummy_appointment_with_user(user_id2, Some(&random_txn.clone().txid()))
.1
.inner;
let signature2 = cryptography::sign(&appointment2.to_vec(), &user_sk2).unwrap();
internal_api
.watcher
.add_appointment(appointment1.clone(), signature1)
.unwrap();
internal_api
.watcher
.add_appointment(appointment2.clone(), signature2)
.unwrap();

let locator = &appointment1.locator;

// returns all appointments if user_id is absent
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator: locator.clone().to_vec(),
user_id_option: None,
}))
.await
.unwrap()
.into_inner();
let dummy_appointments = response.appointments;
assert_eq!(&dummy_appointments.len(), &2);
let responses: Vec<Vec<u8>> = dummy_appointments
.into_iter()
.filter_map(|data| {
if let Some(common_msgs::appointment_data::AppointmentData::Appointment(
appointment,
)) = data.appointment_data
{
return Some(appointment.locator);
}
None
})
.collect();
assert_eq!(responses[0], locator.clone().to_vec());
assert_eq!(responses[1], locator.clone().to_vec());

// returns specific appointments if user_id is absent
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator: locator.clone().to_vec(),
user_id_option: Some(user_id1.clone().to_vec()),
}))
.await
.unwrap()
.into_inner();
let dummy_appointments = response.appointments;
assert_eq!(&dummy_appointments.len(), &1);
let dummy_appointmnets_data = &dummy_appointments[0].appointment_data;
assert!(
matches!(dummy_appointmnets_data.clone(), Some(common_msgs::appointment_data::AppointmentData::Appointment(
common_msgs::Appointment {
locator: ref app_loc,
..
}
)) if app_loc.clone() == locator.to_vec() )
)
}

#[tokio::test]
async fn test_get_appointments_watcher() {
let (internal_api, _s) = create_api().await;
Expand Down Expand Up @@ -548,6 +642,7 @@ mod tests_private_api {
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator: locator.to_vec(),
user_id_option: None,
}))
.await
.unwrap()
Expand Down Expand Up @@ -599,6 +694,7 @@ mod tests_private_api {
let response = internal_api
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator: locator.to_vec(),
user_id_option: None,
}))
.await
.unwrap()
Expand Down Expand Up @@ -747,7 +843,10 @@ mod tests_private_api {

assert_eq!(response.available_slots, SLOTS - 1);
assert_eq!(response.subscription_expiry, START_HEIGHT as u32 + DURATION);
assert_eq!(response.appointments, Vec::from([appointment.inner.locator.to_vec()]));
assert_eq!(
response.appointments,
Vec::from([appointment.inner.locator.to_vec()])
);
}

#[tokio::test]
Expand Down
10 changes: 10 additions & 0 deletions teos/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,21 @@ async fn main() {
println!("{}", pretty_json(&appointments.into_inner()).unwrap());
}
Command::GetAppointments(appointments_data) => {
let mut user_id_option = None;
if let Some(i) = &appointments_data.user_id {
match UserId::from_str(i.as_str()) {
Ok(parsed_user_id) => {
user_id_option = Some(parsed_user_id.to_vec());
}
Err(err) => handle_error(err),
}
}
match Locator::from_hex(&appointments_data.locator) {
Ok(locator) => {
match client
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
locator: locator.to_vec(),
user_id_option,
}))
.await
{
Expand Down
2 changes: 2 additions & 0 deletions teos/src/cli_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct GetUserData {
pub struct GetAppointmentsData {
/// The locator of the appointments (16-byte hexadecimal string).
pub locator: String,
/// The user identifier (33-byte compressed public key).
pub user_id: Option<String>,
}

/// Holds all the command line options and commands.
Expand Down

0 comments on commit 143b826

Please sign in to comment.