Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions aries/src/service/relay_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use std::net::SocketAddr;
use std::str::FromStr;
use std::time::{Duration, SystemTime};

use axum::extract::{Query, State};
use axum::extract::{Path, Query, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::routing::{get, post};
use axum::{Json, Router};
use callisto::{ztm_node, ztm_repo_info};
use clap::Parser;
use serde_json::Value;
use common::config::Config;
use gemini::ztm::hub::{LocalHub, ZTMUserPermit, ZTMCA};
use gemini::{Node, RelayGetParams, RelayResultRes, RepoInfo};
Expand Down Expand Up @@ -104,7 +105,8 @@ pub fn routers() -> Router<AppState> {
.route("/ping", get(ping))
.route("/node_list", get(node_list))
.route("/repo_provide", post(repo_provide))
.route("/repo_list", get(repo_list));
.route("/repo_list", get(repo_list))
.route("/github/webhook/:peer_id", post(github_webhook));

Router::new().merge(router)
}
Expand Down Expand Up @@ -220,6 +222,15 @@ pub async fn repo_list(
Ok(Json(repo_info_list_result))
}

/// Forwards the GitHub webhook to the corresponding peer.
async fn github_webhook(
Path(peer_id): Path<String>,
Json(payload): Json<Value>,
) -> Result<String, (StatusCode, String)> {
tracing::info!("GitHub Webhook Event: {:?} \n {:?}", peer_id, payload);
unimplemented!();
}

async fn loop_running(context: Context) {
let mut interval = tokio::time::interval(Duration::from_secs(60));

Expand Down
3 changes: 2 additions & 1 deletion gateway/src/api/api_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ceres::model::{
};
use common::model::CommonResult;

use crate::api::mr_router;
use crate::api::{github_router, mr_router};
use crate::api::ApiServiceState;

use super::ztm_router;
Expand All @@ -34,6 +34,7 @@ pub fn routers() -> Router<ApiServiceState> {
.merge(router)
.merge(mr_router::routers())
.merge(ztm_router::routers())
.merge(github_router::routers())
}

async fn get_blob_object(
Expand Down
82 changes: 82 additions & 0 deletions gateway/src/api/github_router.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use axum::{Json, Router};
use axum::http::{HeaderMap, StatusCode};
use axum::response::IntoResponse;
use axum::routing::post;
use lazy_static::lazy_static;
use reqwest::Client;
use serde_json::Value;
use taurus::event::github_webhook::{GithubWebhookEvent, WebhookType};
use crate::api::ApiServiceState;

lazy_static! {
static ref CLIENT: Client = Client::builder()
.user_agent("Mega/0.0.1") // IMPORTANT, or 403 Forbidden
.build()
.unwrap();
}

pub fn routers() -> Router<ApiServiceState> {
Router::new()
.route("/github/webhook", post(webhook))
}

/// Handle the GitHub webhook event. <br>
/// For more details, see https://docs.github.com/zh/webhooks/webhook-events-and-payloads.
async fn webhook(
headers: HeaderMap,
Json(mut payload): Json<Value>
) -> Result<impl IntoResponse, (StatusCode, String)> {
let event_type = headers
.get("X-GitHub-Event")
.and_then(|v| v.to_str().ok())
.expect("Missing X-GitHub-Event header");
payload["event_type"] = event_type.into();

let event_type = WebhookType::from(event_type);
match event_type {
WebhookType::PullRequest => {
let action = payload["action"].as_str().unwrap();
tracing::debug!("PR action: {}", action);

if ["opened", "reopened", "synchronize"].contains(&action) { // contents changed
let url = payload["pull_request"]["url"].as_str().unwrap();
let files = get_pr_files(url).await;
let commits = get_pr_commits(url).await;
// Add details to the payload
payload["files"] = files;
payload["commits"] = commits;
} else if action == "edited" { // PR title or body edited
let _ = payload["pull_request"]["title"].as_str().unwrap();
let _ = payload["pull_request"]["body"].as_str().unwrap();
}

GithubWebhookEvent::notify(WebhookType::PullRequest, payload);
}
WebhookType::Issues => {
GithubWebhookEvent::notify(WebhookType::Issues, payload);
}
WebhookType::Unknown(_type) => {
tracing::warn!("Unknown event type: {}", _type);
GithubWebhookEvent::notify(WebhookType::Unknown(_type), payload);
}
}

Ok("WebHook OK")
}

/// GitHub API: Get the files change of a pull request. <br>
/// For read-only operation of public repos, no authentication is required.
pub async fn get_pr_files(pr_url: &str) -> Value {
get_request(&format!("{}/files", pr_url)).await
}

/// GitHub API: Get the commits of a pull request.
pub async fn get_pr_commits(pr_url: &str) -> Value {
get_request(&format!("{}/commits", pr_url)).await
}

/// Send a GET request to the given URL and return the JSON response.
async fn get_request(url: &str) -> Value {
let resp = CLIENT.get(url).send().await.unwrap();
resp.json().await.unwrap()
}
1 change: 1 addition & 0 deletions gateway/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod api_router;
pub mod mr_router;
pub mod oauth;
pub mod ztm_router;
mod github_router;

#[derive(Clone)]
pub struct ApiServiceState {
Expand Down
68 changes: 68 additions & 0 deletions taurus/src/event/github_webhook.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::event::{EventBase, EventType};
use crate::queue::get_mq;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GithubWebhookEvent {
pub _type: WebhookType,
pub payload: Value,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum WebhookType {
PullRequest,
Issues,
Unknown(String),
}

impl From<&str> for WebhookType {
fn from(value: &str) -> Self {
match value {
"pull_request" => WebhookType::PullRequest,
"issues" => WebhookType::Issues,
_ => WebhookType::Unknown(value.to_string()),
}
}
}

impl std::fmt::Display for GithubWebhookEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "GitHub Webhook Event: {:?}", self._type)
}
}

#[async_trait]
impl EventBase for GithubWebhookEvent {
async fn process(&self) {
tracing::info!("Processing: [{}]", &self);
tracing::info!("Payload: {:#?}", &self.payload);
}
}

impl GithubWebhookEvent {
// Create and enqueue this event.
pub fn notify(_type: WebhookType, payload: Value) {
get_mq().send(EventType::GithubWebhook(GithubWebhookEvent {
_type,
payload,
}));
}
}

// For storing the data into database.
impl From<GithubWebhookEvent> for Value {
fn from(value: GithubWebhookEvent) -> Self {
serde_json::to_value(value).unwrap()
}
}

impl TryFrom<Value> for GithubWebhookEvent {
type Error = crate::event::Error;

fn try_from(value: Value) -> Result<Self, Self::Error> {
let res: GithubWebhookEvent = serde_json::from_value(value)?;
Ok(res)
}
}
5 changes: 5 additions & 0 deletions taurus/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
use github_webhook::GithubWebhookEvent;

pub mod api_request;
pub mod github_webhook;

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EventType {
ApiRequest(ApiRequestEvent),
GithubWebhook(GithubWebhookEvent),

// Reserved
ErrorEvent,
Expand Down Expand Up @@ -54,6 +57,8 @@ impl EventType {
EventType::ApiRequest(evt) => evt.process().await,
// EventType::SomeOtherEvent(xxx) => xxx.process().await,

EventType::GithubWebhook(evt) => evt.process().await,

// This won't happen unless failed to load events from database.
// And that's because of a event conversion error.
// You should recheck yout conversion code logic.
Expand Down