11import com .comcast .ip4s .*
22
33import cats .data .NonEmptyList
4- import cats .effect .kernel .*
5- import cats .syntax .all .*
64
7- import io .circe .*
8- import io .circe .yaml .parser
5+ import cats .syntax .all .*
96
107object ProxyConfig :
118
12- def loadYaml [F [_]: Async ](content : String ): F [Equilibrium ] =
13- parser.parse(content).liftTo[F ].flatMap(_.as[Equilibrium ].liftTo[F ])
14-
159 case class Equilibrium (
16- http : Http
10+ http : HttpProxyConfig
1711 )
18- object Equilibrium :
19- implicit val decoder : Decoder [Equilibrium ] = new Decoder [Equilibrium ]:
20- def apply (c : HCursor ): Decoder .Result [Equilibrium ] = for http <- c.downField(" http" ).as[Http ]
21- yield Equilibrium (http)
22- end Equilibrium
23-
2412 sealed trait LocationMatcher
2513 object LocationMatcher :
2614 case class Exact (value : String ) extends LocationMatcher
@@ -30,120 +18,33 @@ object ProxyConfig:
3018 object ModifierSymbol :
3119 case object Exact extends ModifierSymbol
3220 case object Prefix extends ModifierSymbol
33-
34- implicit val decoder : Decoder [ModifierSymbol ] = Decoder [String ].emap {
35- case " =" => Exact .asRight
36- case _ => " Invalid Modifier" .asLeft
37- }
3821 end ModifierSymbol
39-
40- // Add Regex Support via dynamapath
41- // case object CaseSensitiveRegex(d: Path) extends LocationModifier // TODO Add CaseSenstive Option
4222 end LocationMatcher
4323
4424 case class Location (
4525 // key modifier defaults to Prefix, can override to =
4626 matcher : LocationMatcher ,
4727 proxyPass : String // Has Our variables
4828 )
49- object Location :
50- def decoder (
51- upstreams : Map [String , Upstream ]
52- ) = new Decoder [Location ]:
53- def apply (c : HCursor ): Decoder .Result [Location ] = for
54- modifier <- c
55- .downField(" modifier" )
56- .as[Option [LocationMatcher .ModifierSymbol ]]
57- .map(_.getOrElse(LocationMatcher .ModifierSymbol .Prefix ))
58- out <- modifier match
59- case LocationMatcher .ModifierSymbol .Exact =>
60- c.downField(" matcher" ).as[String ].map(LocationMatcher .Exact (_))
61- case LocationMatcher .ModifierSymbol .Prefix =>
62- c.downField(" matcher" ).as[String ].map(LocationMatcher .Prefix (_))
63- // TODO support all positions not only tail position
64- proxy <- c
65- .downField(" proxyPass" )
66- .as[String ](Decoder [String ].emap {
67- s =>
68- if ! s.contains(" $" ) then s.asRight
69- else
70- s.split('$' )
71- .lastOption
72- .toRight(" Value doesnt exist in split" )
73- .flatMap {
74- variable =>
75- if upstreams.contains(variable) then s.asRight
76- else s " Variable $variable not present in upstreams " .asLeft
77- }
78-
79- })
80- yield Location (out, proxy)
81- end Location
8229
8330 case class Server (
8431 listen : Port ,
8532 serverNames : List [String ],
8633 locations : List [Location ]
8734 )
88- object Server :
89- def decoder (
90- upstreams : Map [String , Upstream ]
91- ) = new Decoder [Server ]:
92- def apply (c : HCursor ): Decoder .Result [Server ] = for
93- listen <-
94- if ! c.downField(" listen" ).failed then
95- c.downField(" listen" )
96- .as[Int ]
97- .flatMap {
98- Port .fromInt(_).toRight(DecodingFailure (" Invalid Port" , List .empty))
99- }
100- else port " 8080 " .asRight
101- names <- c.downField(" serverNames" ).as[List [String ]]
102- locations <- c.downField(" locations" ).as[List [Location ]](Decoder .decodeList(Location .decoder(upstreams)))
103- yield Server (listen, names, locations)
104- end Server
105-
10635 case class UpstreamServer (
10736 host : Host ,
10837 port : Port ,
10938 weight : Int
11039 )
111- object UpstreamServer :
112- implicit val decoder : Decoder [UpstreamServer ] = new Decoder [UpstreamServer ]:
113- def apply (c : HCursor ): Decoder .Result [UpstreamServer ] = for
114- host <- c
115- .downField(" host" )
116- .as[String ]
117- .flatMap(s => Host .fromString(s).toRight(DecodingFailure (" Invalid Host" , List .empty)))
118- port <- c
119- .downField(" port" )
120- .as[Int ]
121- .flatMap(i => Port .fromInt(i).toRight(DecodingFailure (" Invalid Port" , List .empty)))
122- weight <- c.downField(" weight" ).as[Option [Int ]].map(_.getOrElse(1 ))
123- yield UpstreamServer (host, port, weight)
124- end UpstreamServer
12540 case class Upstream (
12641 name : String ,
12742 servers : NonEmptyList [UpstreamServer ]
12843 )
129- object Upstream :
130- implicit val decoder : Decoder [Upstream ] = new Decoder [Upstream ]:
131- def apply (c : HCursor ): Decoder .Result [Upstream ] = (
132- c.downField(" name" ).as[String ],
133- c.downField(" servers" ).as[NonEmptyList [UpstreamServer ]]
134- ).mapN(Upstream (_, _))
135- end Upstream
13644
137- case class Http (
45+ case class HttpProxyConfig (
13846 servers : NonEmptyList [Server ],
13947 upstreams : List [Upstream ]
14048 )
141- object Http :
142- implicit val decoder : Decoder [Http ] = new Decoder [Http ]:
143- def apply (c : HCursor ): Decoder .Result [Http ] = for
144- upstreams <- c.downField(" upstreams" ).as[List [Upstream ]]
145- map = upstreams.groupBy(_.name).map(t => t._1 -> t._2.head).toMap
146- servers <- c.downField(" servers" ).as[NonEmptyList [Server ]](Decoder .decodeNonEmptyList(Server .decoder(map)))
147- yield Http (servers, upstreams)
148- end Http
49+
14950end ProxyConfig
0 commit comments