Skip to main content

git_remote_iroh/
lib.rs

1use std::{fmt::Display, str::FromStr};
2
3mod client;
4mod keys;
5mod server;
6
7pub use client::{Client, ClientArgs};
8pub use server::{Server, ServerArgs};
9
10/// ALPN for git-remote-iroh connections.
11pub const GIT_IROH_ALPN: &[u8] = b"git/iroh/0";
12
13/// Stream header sent at the start of a git stream.
14/// Identifies whether this is a push (receive-pack) or fetch (upload-pack).
15#[derive(Debug, Clone, Copy, PartialEq)]
16pub enum GitOp {
17    /// Client wants to push (server runs git-receive-pack)
18    Push,
19    /// Client wants to fetch (server runs git-upload-pack)
20    Fetch,
21}
22
23impl GitOp {
24    pub fn to_byte(self) -> u8 {
25        match self {
26            GitOp::Push => 1,
27            GitOp::Fetch => 2,
28        }
29    }
30
31    pub fn from_byte(b: u8) -> Option<Self> {
32        match b {
33            1 => Some(GitOp::Push),
34            2 => Some(GitOp::Fetch),
35            _ => None,
36        }
37    }
38}
39
40impl FromStr for GitOp {
41    type Err = anyhow::Error;
42
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        Ok(match s {
45            "git-upload-pack" => GitOp::Push,
46            "git-receive-pack" => GitOp::Fetch,
47            _ => anyhow::bail!("unsupported command {s}"),
48        })
49    }
50}
51
52impl Display for GitOp {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        match self {
55            GitOp::Fetch => f.write_str("git-receive-pack"),
56            GitOp::Push => f.write_str("git-upload-pack"),
57        }
58    }
59}
60
61/// Parses `iroh://<node-id>` URL.
62fn parse_iroh_url(url: &str) -> Result<iroh::PublicKey, anyhow::Error> {
63    let node_id_str = url.strip_prefix("iroh://").ok_or(anyhow::anyhow!(
64        "invalid iroh URL (expected iroh://): {}",
65        url
66    ))?;
67
68    Ok(node_id_str.parse::<iroh::PublicKey>()?)
69}