master
go 265 lines 7.77 KB
Raw
1 package config
2
3 import (
4 "encoding/json"
5 "fmt"
6 "os"
7 "runtime"
8 "slices"
9 "strings"
10 )
11
12 const (
13 DefaultAcceleratedDHTClient = false
14 DefaultLoopbackAddressesOnLanDHT = false
15 DefaultRoutingType = "auto"
16 CidContactRoutingURL = "https://cid.contact"
17 PublicGoodDelegatedRoutingURL = "https://delegated-ipfs.dev" // cid.contact + amino dht (incl. IPNS PUTs)
18 EnvHTTPRouters = "IPFS_HTTP_ROUTERS"
19 EnvHTTPRoutersFilterProtocols = "IPFS_HTTP_ROUTERS_FILTER_PROTOCOLS"
20 )
21
22 var (
23 // Default filter-protocols to pass along with delegated routing requests (as defined in IPIP-484)
24 // and also filter out locally
25 DefaultHTTPRoutersFilterProtocols = getEnvOrDefault(EnvHTTPRoutersFilterProtocols, []string{
26 "unknown", // allow results without protocol list, we can do libp2p identify to test them
27 "transport-bitswap",
28 // http is added dynamically in routing/delegated.go.
29 // 'transport-ipfs-gateway-http'
30 })
31 )
32
33 // Routing defines configuration options for libp2p routing.
34 type Routing struct {
35 // Type sets default daemon routing mode.
36 //
37 // Can be one of "auto", "autoclient", "dht", "dhtclient", "dhtserver", "none", "delegated", or "custom".
38 // When unset or set to "auto", DHT and implicit routers are used.
39 // When "delegated" is set, only HTTP delegated routers and IPNS publishers are used (no DHT).
40 // When "custom" is set, user-provided Routing.Routers is used.
41 Type *OptionalString `json:",omitempty"`
42
43 AcceleratedDHTClient Flag `json:",omitempty"`
44
45 LoopbackAddressesOnLanDHT Flag `json:",omitempty"`
46
47 IgnoreProviders []string `json:",omitempty"`
48
49 // Simplified configuration used by default when Routing.Type=auto|autoclient
50 DelegatedRouters []string
51
52 // Advanced configuration used when Routing.Type=custom
53 Routers Routers `json:",omitempty"`
54 Methods Methods `json:",omitempty"`
55 }
56
57 type Router struct {
58 // Router type ID. See RouterType for more info.
59 Type RouterType
60
61 // Parameters are extra configuration that this router might need.
62 // A common one for HTTP router is "Endpoint".
63 Parameters any
64 }
65
66 type (
67 Routers map[string]RouterParser
68 Methods map[MethodName]Method
69 )
70
71 func (m Methods) Check() error {
72 // Check supported methods
73 for _, mn := range MethodNameList {
74 _, ok := m[mn]
75 if !ok {
76 return fmt.Errorf("method name %q is missing from Routing.Methods config param", mn)
77 }
78 }
79
80 // Check unsupported methods
81 for k := range m {
82 seen := slices.Contains(MethodNameList, k)
83
84 if seen {
85 continue
86 }
87
88 return fmt.Errorf("method name %q is not a supported method on Routing.Methods config param", k)
89 }
90
91 return nil
92 }
93
94 type RouterParser struct {
95 Router
96 }
97
98 func (r *RouterParser) UnmarshalJSON(b []byte) error {
99 out := Router{}
100 out.Parameters = &json.RawMessage{}
101 if err := json.Unmarshal(b, &out); err != nil {
102 return err
103 }
104 raw := out.Parameters.(*json.RawMessage)
105
106 var p any
107 switch out.Type {
108 case RouterTypeHTTP:
109 p = &HTTPRouterParams{}
110 case RouterTypeDHT:
111 p = &DHTRouterParams{}
112 case RouterTypeSequential:
113 p = &ComposableRouterParams{}
114 case RouterTypeParallel:
115 p = &ComposableRouterParams{}
116 }
117
118 if err := json.Unmarshal(*raw, &p); err != nil {
119 return err
120 }
121
122 r.Router.Type = out.Type
123 r.Router.Parameters = p
124
125 return nil
126 }
127
128 // Type is the routing type.
129 // Depending of the type we need to instantiate different Routing implementations.
130 type RouterType string
131
132 const (
133 RouterTypeHTTP RouterType = "http" // HTTP JSON API for delegated routing systems (IPIP-337).
134 RouterTypeDHT RouterType = "dht" // DHT router.
135 RouterTypeSequential RouterType = "sequential" // Router helper to execute several routers sequentially.
136 RouterTypeParallel RouterType = "parallel" // Router helper to execute several routers in parallel.
137 )
138
139 type DHTMode string
140
141 const (
142 DHTModeServer DHTMode = "server"
143 DHTModeClient DHTMode = "client"
144 DHTModeAuto DHTMode = "auto"
145 )
146
147 type MethodName string
148
149 const (
150 MethodNameProvide MethodName = "provide"
151 MethodNameFindProviders MethodName = "find-providers"
152 MethodNameFindPeers MethodName = "find-peers"
153 MethodNameGetIPNS MethodName = "get-ipns"
154 MethodNamePutIPNS MethodName = "put-ipns"
155 )
156
157 var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, MethodNameFindProviders, MethodNameGetIPNS, MethodNamePutIPNS}
158
159 type HTTPRouterParams struct {
160 // Endpoint is the URL where the routing implementation will point to get the information.
161 Endpoint string
162
163 // MaxProvideBatchSize determines the maximum amount of CIDs sent per batch.
164 // Servers might not accept more than 100 elements per batch. 100 elements by default.
165 MaxProvideBatchSize int
166
167 // MaxProvideConcurrency determines the number of threads used when providing content. GOMAXPROCS by default.
168 MaxProvideConcurrency int
169 }
170
171 func (hrp *HTTPRouterParams) FillDefaults() {
172 if hrp.MaxProvideBatchSize == 0 {
173 hrp.MaxProvideBatchSize = 100
174 }
175
176 if hrp.MaxProvideConcurrency == 0 {
177 hrp.MaxProvideConcurrency = runtime.GOMAXPROCS(0)
178 }
179 }
180
181 type DHTRouterParams struct {
182 Mode DHTMode
183 AcceleratedDHTClient bool `json:",omitempty"`
184 PublicIPNetwork bool
185 }
186
187 type ComposableRouterParams struct {
188 Routers []ConfigRouter
189 Timeout *OptionalDuration `json:",omitempty"`
190 }
191
192 type ConfigRouter struct {
193 RouterName string
194 Timeout Duration
195 IgnoreErrors bool
196 ExecuteAfter *OptionalDuration `json:",omitempty"`
197 }
198
199 type Method struct {
200 RouterName string
201 }
202
203 // getEnvOrDefault reads space or comma separated strings from env if present,
204 // and uses provided defaultValue as a fallback
205 func getEnvOrDefault(key string, defaultValue []string) []string {
206 if value, exists := os.LookupEnv(key); exists {
207 splitFunc := func(r rune) bool { return r == ',' || r == ' ' }
208 return strings.FieldsFunc(value, splitFunc)
209 }
210 return defaultValue
211 }
212
213 // HasHTTPProviderConfigured checks if the node is configured to use HTTP routers
214 // for providing content announcements. This is used when determining if the node
215 // can provide content even when not connected to libp2p peers.
216 //
217 // Note: Right now we only support delegated HTTP content providing if Routing.Type=custom
218 // and Routing.Routers are configured according to:
219 // https://github.com/ipfs/kubo/blob/master/docs/delegated-routing.md#configuration-file-example
220 //
221 // This uses the `ProvideBitswap` request type that is not documented anywhere,
222 // because we hoped something like IPIP-378 (https://github.com/ipfs/specs/pull/378)
223 // would get finalized and we'd switch to that. It never happened due to politics,
224 // and now we are stuck with ProvideBitswap being the only API that works.
225 // Some people have reverse engineered it (example:
226 // https://discuss.ipfs.tech/t/only-peers-found-from-dht-seem-to-be-getting-used-as-relays-so-cant-use-http-routers/19545/9)
227 // and use it, so what we do here is the bare minimum to ensure their use case works
228 // using this old API until something better is available.
229 func (c *Config) HasHTTPProviderConfigured() bool {
230 if len(c.Routing.Routers) == 0 {
231 // No "custom" routers
232 return false
233 }
234 method, ok := c.Routing.Methods[MethodNameProvide]
235 if !ok {
236 // No provide method configured
237 return false
238 }
239 return c.routerSupportsHTTPProviding(method.RouterName)
240 }
241
242 // routerSupportsHTTPProviding checks if the supplied custom router is or
243 // includes an HTTP-based router.
244 func (c *Config) routerSupportsHTTPProviding(routerName string) bool {
245 rp, ok := c.Routing.Routers[routerName]
246 if !ok {
247 // Router configured for providing doesn't exist
248 return false
249 }
250
251 switch rp.Type {
252 case RouterTypeHTTP:
253 return true
254 case RouterTypeParallel, RouterTypeSequential:
255 // Check if any child router supports HTTP
256 if children, ok := rp.Parameters.(*ComposableRouterParams); ok {
257 for _, childRouter := range children.Routers {
258 if c.routerSupportsHTTPProviding(childRouter.RouterName) {
259 return true
260 }
261 }
262 }
263 }
264 return false
265 }