sourcehut-mirror-bridge/src/sourcehut.rs

143 lines
3.7 KiB
Rust

use anyhow::Result;
use cynic::{GraphQlResponse, MutationBuilder};
use log::error;
#[cynic::schema("sourcehut")]
mod schema {}
#[derive(cynic::QueryVariables, Debug)]
struct CreateWebhookVariables {
url: String,
}
#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Mutation", variables = "CreateWebhookVariables")]
struct CreateWebhook {
#[arguments(config: { events: ["REPO_UPDATE"], query: r#"query {
webhook {
... on RepositoryEvent {
repository {
name
}
}
}
}"#, url: $url })]
create_user_webhook: WebhookSubscription,
}
#[derive(cynic::QueryFragment, Debug)]
struct WebhookSubscription {
id: i32,
}
#[derive(cynic::QueryVariables, Debug)]
struct DeleteWebhookVariables {
id: i32,
}
#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Mutation", variables = "DeleteWebhookVariables")]
struct DeleteWebhook {
#[arguments(id: $id)]
#[allow(dead_code)]
delete_user_webhook: WebhookSubscription,
}
#[derive(cynic::QueryFragment, Debug)]
struct RepositoryEvent {
repository: Repository,
}
#[derive(cynic::QueryFragment, Debug)]
pub struct Repository {
pub name: String,
}
#[derive(serde::Deserialize, Debug)]
struct WebhookEventReceived {
webhook: RepositoryEvent,
}
#[derive(cynic::Enum, Clone, Copy, Debug)]
enum WebhookEvent {
RepoCreated,
RepoUpdate,
RepoDeleted,
}
#[derive(cynic::Scalar, Debug, Clone)]
pub struct Time(pub String);
pub struct SourcehutAPI {
api_endpoint: String,
token: String,
webhook_id: Option<i32>,
}
fn parse_gql_response<T>(response: GraphQlResponse<T>) -> Result<T> {
match response.data {
Some(data) => Ok(data),
None => {
// Check for errors
match response.errors {
Some(errors) => Err(anyhow::anyhow!(errors
.iter()
.map(|e| e.to_string())
.collect::<Vec<String>>()
.join("\n"))),
None => Err(anyhow::anyhow!("Unknown error")),
}
}
}
}
impl SourcehutAPI {
pub fn new(api_endpoint: &str, token: &str) -> Self {
Self {
api_endpoint: api_endpoint.to_string(),
token: token.to_string(),
webhook_id: None,
}
}
pub fn init_webhook(&mut self, url: &str) -> Result<()> {
let operation = CreateWebhook::build(CreateWebhookVariables {
url: url.to_string(),
});
let response = ureq::post(&self.api_endpoint)
.set("Authorization", &format!("Bearer {}", &self.token))
.send_json(operation)?
.into_json::<GraphQlResponse<CreateWebhook>>()?;
let webhook_ev = parse_gql_response(response)?;
self.webhook_id = Some(webhook_ev.create_user_webhook.id);
Ok(())
}
pub fn delete_webhook(&self) -> Result<()> {
if let Some(id) = self.webhook_id {
let operation = DeleteWebhook::build(DeleteWebhookVariables { id });
let response = ureq::post(&self.api_endpoint)
.set("Authorization", &format!("Bearer {}", &self.token))
.send_json(operation)?
.into_json::<GraphQlResponse<DeleteWebhook>>()?;
parse_gql_response(response)?;
}
Ok(())
}
pub fn read_webhook_payload(data: &str) -> Result<Repository> {
let data = serde_json::from_str::<GraphQlResponse<WebhookEventReceived>>(data)?;
parse_gql_response(data).map(|ev| ev.webhook.repository)
}
}
impl Drop for SourcehutAPI {
fn drop(&mut self) {
if let Err(e) = self.delete_webhook() {
error!("Failed to delete webhook: {}", e);
}
}
}