Skip to content

Commit

Permalink
Fix:add examples
Browse files Browse the repository at this point in the history
  • Loading branch information
mertakman committed Nov 7, 2024
1 parent dee34fa commit 7ee31ac
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 40 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ httpmock = "0.7.0"
[dev-dependencies]
tokio = { version="1.41.0", features = ["full"] }
lambda_runtime = "0.13.0"
aws-config = "1.5.10"
aws-sdk-secretsmanager = "1.53.0"
worker = "0.4.2"
83 changes: 76 additions & 7 deletions examples/aws-lambda/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use lambda_runtime::{service_fn, LambdaEvent, Error};
use std::io::ErrorKind;

use aws_config::BehaviorVersion;
use aws_sdk_secretsmanager::Client as SecretsManagerClient;
use lambda_runtime::{service_fn, Error, LambdaEvent};
use qstash_rs::{client::QstashClient, errors::QstashError};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Deserialize)]
struct Request {
pub name: String,
pub message_id: String,
}

#[derive(Serialize)]
Expand All @@ -13,12 +20,74 @@ struct Response {

#[tokio::main]
async fn main() -> Result<(), Error> {
let func = service_fn(func_handler);
let secret_name = "QSTASH_APIKEY"; // Replace with your secret name
let region_provider =
aws_config::meta::region::RegionProviderChain::default_provider().or_else("eu-west-1");
let config = aws_config::defaults(BehaviorVersion::latest())
.region(region_provider)
.load()
.await;
let client = SecretsManagerClient::new(&config);

let secret_value = client
.get_secret_value()
.secret_id(secret_name)
.send()
.await?
.secret_string
.unwrap_or_default();

let qstash_client = QstashClient::new(secret_value).map_err(|e| Error::from(e.to_string()))?;

let app = App::new(qstash_client)?;
let func = service_fn(|event: LambdaEvent<Request>| app.func_handler(event));
lambda_runtime::run(func).await
}

async fn func_handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
let (request, _context) = event.into_parts();
let message = format!("Hello, {}!", request.name);
Ok(Response { message })
struct App {
qstash_client: QstashClient,
}

impl App {
fn new(qstash_client: QstashClient) -> Result<Self, Error> {
Ok(App { qstash_client })
}

async fn func_handler(&self, event: LambdaEvent<Request>) -> Result<Response, Error> {
match self
.qstash_client
.get_message(&event.payload.message_id)
.await
{
Ok(message) => {
return Ok(Response {
message: json!({ "message": message }).to_string(),
})
}
Err(e) => match e {
QstashError::RequestFailed(err) => match err.status() {
Some(StatusCode::BAD_REQUEST) => Err(Box::new(std::io::Error::new(
ErrorKind::Other,
"Bad request",
))),
Some(StatusCode::NOT_FOUND) => Err(Box::new(std::io::Error::new(
ErrorKind::NotFound,
"Message not found",
))),
Some(StatusCode::INTERNAL_SERVER_ERROR) => Err(Box::new(std::io::Error::new(
ErrorKind::Other,
"Internal server error",
))),
_ => Err(Box::new(std::io::Error::new(
ErrorKind::Other,
format!("Error getting message: {}", err),
))),
},
_ => Err(Box::new(std::io::Error::new(
ErrorKind::Other,
format!("Error getting message: {}", e),
))),
},
}
}
}
44 changes: 44 additions & 0 deletions examples/cloudflare-worker/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use reqwest::StatusCode;
use qstash_rs::{client::QstashClient, errors::QstashError};
use serde_json::json;
use worker::*;

#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let api_key = match env.secret("QSTASH_APIKEY") {
Ok(secret) => secret.to_string(),
Err(e) => return Response::error(&format!("Error getting API key: {}", e), 500),
};
let qstash_client = match QstashClient::new(api_key) {
Ok(client) => client,
Err(e) => return Response::error(&format!("Error creating Qstash client: {}", e), 500),
};

if !matches!(req.method(), Method::Get) {
return Response::error("Method Not Allowed", 405);
}

let url = &req.url()?;
let message_id = match url.query_pairs().find(|(key, _)| key == "message_id") {
Some((_, value)) => value.to_string(),
None => return Response::error("Query parameter 'message_id' is missing", 400),
};

match qstash_client.get_message(&message_id).await {
Ok(message) => {
let json_message = json!({ "message": message });
Response::from_json(&json_message)
}
Err(e) => match e {
QstashError::RequestFailed(err) => match err.status() {
Some(StatusCode::BAD_REQUEST) => return Response::error("Bad request", 400),
Some(StatusCode::NOT_FOUND) => return Response::error("Message not found", 404),
Some(StatusCode::INTERNAL_SERVER_ERROR) => {
return Response::error("Internal server error", 500)
}
_ => return Response::error(&format!("Error getting message: {}", err), 500),
},
_ => return Response::error(&format!("Error getting message: {}", e), 500),
},
}
}
1 change: 0 additions & 1 deletion examples/cloudlfare-workers/main.rs

This file was deleted.

4 changes: 2 additions & 2 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ impl QstashClient {
})
}

pub fn new(api_key: &str) -> Result<Self, QstashError> {
pub fn new(api_key: String) -> Result<Self, QstashError> {
// Create a default instance
let mut qstash_client = QstashClient::default()?;
// Create rate limited client with API Key
qstash_client.client = RateLimitedClient::new(api_key.to_string());
qstash_client.client = RateLimitedClient::new(api_key);

Ok(qstash_client)
}
Expand Down
3 changes: 1 addition & 2 deletions src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ impl QstashClient {
}

#[cfg(test)]
mod tests {
}
mod tests {}
26 changes: 12 additions & 14 deletions src/llm_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,15 @@ mod tests {
use crate::rate_limited_client::RateLimitedClient;

use super::*;
use reqwest::{Method, Url};
use httpmock::prelude::*;
use reqwest::{Method, Url};

#[tokio::test]
async fn test_send_request_success() {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(200);
});

Expand All @@ -308,8 +307,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("RateLimit-Limit", "1000")
.header("RateLimit-Reset", "3600");
Expand All @@ -335,8 +333,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("Burst-RateLimit-Limit", "100")
.header("Burst-RateLimit-Reset", "60");
Expand All @@ -362,8 +359,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("x-ratelimit-limit-requests", "100")
.header("x-ratelimit-reset-requests", "30")
Expand All @@ -379,10 +375,13 @@ mod tests {

// Assert
match result {
Err(QstashError::ChatRateLimitExceeded { reset_requests, reset_tokens }) => {
Err(QstashError::ChatRateLimitExceeded {
reset_requests,
reset_tokens,
}) => {
assert_eq!(reset_requests, 30);
assert_eq!(reset_tokens, 45);
},
}
_ => panic!("Expected ChatRateLimitExceeded error"),
}
mock.assert();
Expand All @@ -393,8 +392,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429);
});

Expand All @@ -412,4 +410,4 @@ mod tests {
}
mock.assert();
}
}
}
26 changes: 12 additions & 14 deletions src/rate_limited_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,15 @@ fn parse_reset_time(headers: &HeaderMap, header_name: &str) -> u64 {
#[cfg(test)]
mod tests {
use super::*;
use reqwest::Method;
use httpmock::prelude::*;
use reqwest::Method;

#[tokio::test]
async fn test_send_request_success() {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(200);
});

Expand All @@ -108,8 +107,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("RateLimit-Limit", "1000")
.header("RateLimit-Reset", "3600");
Expand All @@ -135,8 +133,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("Burst-RateLimit-Limit", "100")
.header("Burst-RateLimit-Reset", "60");
Expand All @@ -162,8 +159,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429)
.header("x-ratelimit-limit-requests", "100")
.header("x-ratelimit-reset-requests", "30")
Expand All @@ -179,10 +175,13 @@ mod tests {

// Assert
match result {
Err(QstashError::ChatRateLimitExceeded { reset_requests, reset_tokens }) => {
Err(QstashError::ChatRateLimitExceeded {
reset_requests,
reset_tokens,
}) => {
assert_eq!(reset_requests, 30);
assert_eq!(reset_tokens, 45);
},
}
_ => panic!("Expected ChatRateLimitExceeded error"),
}
mock.assert();
Expand All @@ -193,8 +192,7 @@ mod tests {
// Arrange
let server = MockServer::start_async().await;
let mock = server.mock(|when, then| {
when.method(GET)
.path("/test");
when.method(GET).path("/test");
then.status(429);
});

Expand All @@ -212,4 +210,4 @@ mod tests {
}
mock.assert();
}
}
}

0 comments on commit 7ee31ac

Please sign in to comment.