rmcp_openapi/
spec_location.rs

1use crate::error::OpenApiError;
2use crate::openapi_spec::OpenApiSpec;
3use std::fmt;
4use std::path::PathBuf;
5use std::str::FromStr;
6use url::Url;
7
8#[derive(Debug, Clone)]
9pub enum OpenApiSpecLocation {
10    File(PathBuf),
11    Url(Url),
12}
13
14impl FromStr for OpenApiSpecLocation {
15    type Err = OpenApiError;
16
17    fn from_str(s: &str) -> Result<Self, Self::Err> {
18        if s.starts_with("http://") || s.starts_with("https://") {
19            let url =
20                Url::parse(s).map_err(|e| OpenApiError::InvalidUrl(format!("Invalid URL: {e}")))?;
21            Ok(OpenApiSpecLocation::Url(url))
22        } else {
23            let path = PathBuf::from(s);
24            Ok(OpenApiSpecLocation::File(path))
25        }
26    }
27}
28
29impl OpenApiSpecLocation {
30    pub async fn load_spec(&self) -> Result<OpenApiSpec, OpenApiError> {
31        match self {
32            OpenApiSpecLocation::File(path) => {
33                OpenApiSpec::from_file(path.to_str().ok_or_else(|| {
34                    OpenApiError::InvalidPath("Invalid file path encoding".to_string())
35                })?)
36                .await
37            }
38            OpenApiSpecLocation::Url(url) => OpenApiSpec::from_url(url).await,
39        }
40    }
41}
42
43impl fmt::Display for OpenApiSpecLocation {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        match self {
46            OpenApiSpecLocation::File(path) => write!(f, "{}", path.display()),
47            OpenApiSpecLocation::Url(url) => write!(f, "{url}"),
48        }
49    }
50}