1use std::fmt;
2
3use reqwest::Method;
4
5use crate::auth::CredentialKind;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum ProtocolSurface {
9 OfficialApi,
10 SessionWeb,
11}
12
13impl fmt::Display for ProtocolSurface {
14 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 Self::OfficialApi => formatter.write_str("OfficialApi"),
17 Self::SessionWeb => formatter.write_str("SessionWeb"),
18 }
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum ApiVersion {
24 V0,
25 V1,
26 NotApplicable,
27}
28
29impl fmt::Display for ApiVersion {
30 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Self::V0 => formatter.write_str("v0"),
33 Self::V1 => formatter.write_str("v1"),
34 Self::NotApplicable => formatter.write_str("n/a"),
35 }
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub enum ParserShape {
41 JsonEnvelope,
42 Html,
43 Stream,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub enum HttpMethod {
48 Get,
49 Post,
50}
51
52impl HttpMethod {
53 pub(crate) fn as_reqwest(self) -> Method {
54 match self {
55 Self::Get => Method::GET,
56 Self::Post => Method::POST,
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62pub enum EndpointId {
63 OfficialSearch,
64 OfficialEnrichWeb,
65 OfficialEnrichNews,
66 OfficialSummarizeGet,
67 OfficialSummarizePost,
68 OfficialFastGpt,
69 OfficialSmallwebFeed,
70 SessionHtmlSearch,
71 SessionSummaryLabsGet,
72 SessionSummaryLabsPost,
73}
74
75impl fmt::Display for EndpointId {
76 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77 formatter.write_str(self.spec().name)
78 }
79}
80
81#[derive(Debug, Clone, Copy)]
82pub struct EndpointSpec {
83 pub name: &'static str,
84 pub surface: ProtocolSurface,
85 pub method: HttpMethod,
86 pub route: &'static str,
87 pub version: ApiVersion,
88 pub parser: ParserShape,
89 pub allowed_credential: CredentialKind,
90}
91
92impl EndpointId {
93 pub fn spec(self) -> EndpointSpec {
94 match self {
95 Self::OfficialSearch => EndpointSpec {
96 name: "official.search",
97 surface: ProtocolSurface::OfficialApi,
98 method: HttpMethod::Get,
99 route: "/api/v0/search",
100 version: ApiVersion::V0,
101 parser: ParserShape::JsonEnvelope,
102 allowed_credential: CredentialKind::BotToken,
103 },
104 Self::OfficialEnrichWeb => EndpointSpec {
105 name: "official.enrich_web",
106 surface: ProtocolSurface::OfficialApi,
107 method: HttpMethod::Get,
108 route: "/api/v0/enrich/web",
109 version: ApiVersion::V0,
110 parser: ParserShape::JsonEnvelope,
111 allowed_credential: CredentialKind::BotToken,
112 },
113 Self::OfficialEnrichNews => EndpointSpec {
114 name: "official.enrich_news",
115 surface: ProtocolSurface::OfficialApi,
116 method: HttpMethod::Get,
117 route: "/api/v0/enrich/news",
118 version: ApiVersion::V0,
119 parser: ParserShape::JsonEnvelope,
120 allowed_credential: CredentialKind::BotToken,
121 },
122 Self::OfficialSummarizeGet => EndpointSpec {
123 name: "official.summarize_get",
124 surface: ProtocolSurface::OfficialApi,
125 method: HttpMethod::Get,
126 route: "/api/v0/summarize",
127 version: ApiVersion::V0,
128 parser: ParserShape::JsonEnvelope,
129 allowed_credential: CredentialKind::BotToken,
130 },
131 Self::OfficialSummarizePost => EndpointSpec {
132 name: "official.summarize_post",
133 surface: ProtocolSurface::OfficialApi,
134 method: HttpMethod::Post,
135 route: "/api/v0/summarize",
136 version: ApiVersion::V0,
137 parser: ParserShape::JsonEnvelope,
138 allowed_credential: CredentialKind::BotToken,
139 },
140 Self::OfficialFastGpt => EndpointSpec {
141 name: "official.fastgpt",
142 surface: ProtocolSurface::OfficialApi,
143 method: HttpMethod::Post,
144 route: "/api/v0/fastgpt",
145 version: ApiVersion::V0,
146 parser: ParserShape::JsonEnvelope,
147 allowed_credential: CredentialKind::BotToken,
148 },
149 Self::OfficialSmallwebFeed => EndpointSpec {
150 name: "official.smallweb_feed",
151 surface: ProtocolSurface::OfficialApi,
152 method: HttpMethod::Get,
153 route: "/api/v1/smallweb/feed",
154 version: ApiVersion::V1,
155 parser: ParserShape::JsonEnvelope,
156 allowed_credential: CredentialKind::BotToken,
157 },
158 Self::SessionHtmlSearch => EndpointSpec {
159 name: "session.html_search",
160 surface: ProtocolSurface::SessionWeb,
161 method: HttpMethod::Get,
162 route: "/html/search",
163 version: ApiVersion::NotApplicable,
164 parser: ParserShape::Html,
165 allowed_credential: CredentialKind::SessionToken,
166 },
167 Self::SessionSummaryLabsGet => EndpointSpec {
168 name: "session.summary_labs_get",
169 surface: ProtocolSurface::SessionWeb,
170 method: HttpMethod::Get,
171 route: "/mother/summary_labs",
172 version: ApiVersion::NotApplicable,
173 parser: ParserShape::Stream,
174 allowed_credential: CredentialKind::SessionToken,
175 },
176 Self::SessionSummaryLabsPost => EndpointSpec {
177 name: "session.summary_labs_post",
178 surface: ProtocolSurface::SessionWeb,
179 method: HttpMethod::Post,
180 route: "/mother/summary_labs/",
181 version: ApiVersion::NotApplicable,
182 parser: ParserShape::Stream,
183 allowed_credential: CredentialKind::SessionToken,
184 },
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::{ApiVersion, EndpointId};
192
193 #[test]
194 fn official_endpoints_cover_both_v0_and_v1_routes() {
195 let v0 = EndpointId::OfficialSearch.spec();
196 let v1 = EndpointId::OfficialSmallwebFeed.spec();
197
198 assert_eq!(v0.version, ApiVersion::V0);
199 assert_eq!(v0.route, "/api/v0/search");
200 assert_eq!(v1.version, ApiVersion::V1);
201 assert_eq!(v1.route, "/api/v1/smallweb/feed");
202 }
203}