@@ -16,6 +16,7 @@ import jsonrpclib.internals.MessageDispatcher
16
16
import jsonrpclib .internals ._
17
17
18
18
import scala .util .Try
19
+ import java .util .regex .Pattern
19
20
20
21
trait FS2Channel [F [_]] extends Channel [F ] {
21
22
@@ -52,7 +53,7 @@ object FS2Channel {
52
53
): Stream [F , FS2Channel [F ]] = {
53
54
for {
54
55
supervisor <- Stream .resource(Supervisor [F ])
55
- ref <- Ref [F ].of(State [F ](Map .empty, Map .empty, Map .empty, 0 )).toStream
56
+ ref <- Ref [F ].of(State [F ](Map .empty, Map .empty, Map .empty, Vector .empty, 0 )).toStream
56
57
queue <- cats.effect.std.Queue .bounded[F , Payload ](bufferSize).toStream
57
58
impl = new Impl (queue, ref, supervisor, cancelTemplate)
58
59
@@ -73,6 +74,7 @@ object FS2Channel {
73
74
runningCalls : Map [CallId , Fiber [F , Throwable , Unit ]],
74
75
pendingCalls : Map [CallId , OutputMessage => F [Unit ]],
75
76
endpoints : Map [String , Endpoint [F ]],
77
+ globEndpoints : Vector [(Pattern , Endpoint [F ])],
76
78
counter : Long
77
79
) {
78
80
def nextCallId : (State [F ], CallId ) = (this .copy(counter = counter + 1 ), CallId .NumberId (counter))
@@ -82,11 +84,27 @@ object FS2Channel {
82
84
val result = pendingCalls.get(callId)
83
85
(this .copy(pendingCalls = pendingCalls.removed(callId)), result)
84
86
}
85
- def mountEndpoint (endpoint : Endpoint [F ]): Either [ConflictingMethodError , State [F ]] =
86
- endpoints.get(endpoint.method) match {
87
- case None => Right (this .copy(endpoints = endpoints + (endpoint.method -> endpoint)))
88
- case Some (_) => Left (ConflictingMethodError (endpoint.method))
87
+ def mountEndpoint (endpoint : Endpoint [F ]): Either [ConflictingMethodError , State [F ]] = {
88
+ import endpoint .method
89
+ if (method.contains(" *" )) {
90
+ val parts = method
91
+ .split(" \\ *" , - 1 )
92
+ .map { // Don't discard trailing empty string, if any.
93
+ case " " => " "
94
+ case str => Pattern .quote(str)
95
+ }
96
+ val glob = Pattern .compile(parts.mkString(" .*" ))
97
+ Right (this .copy(globEndpoints = globEndpoints :+ (glob -> endpoint)))
98
+ } else {
99
+ endpoints.get(endpoint.method) match {
100
+ case None => Right (this .copy(endpoints = endpoints + (endpoint.method -> endpoint)))
101
+ case Some (_) => Left (ConflictingMethodError (endpoint.method))
102
+ }
89
103
}
104
+ }
105
+ def getEndpoint (method : String ): Option [Endpoint [F ]] = {
106
+ endpoints.get(method).orElse(globEndpoints.find(_._1.matcher(method).matches()).map(_._2))
107
+ }
90
108
def removeEndpoint (method : String ): State [F ] =
91
109
copy(endpoints = endpoints.removed(method))
92
110
@@ -135,7 +153,7 @@ object FS2Channel {
135
153
}
136
154
}
137
155
protected def reportError (params : Option [Payload ], error : ProtocolError , method : String ): F [Unit ] = ???
138
- protected def getEndpoint (method : String ): F [Option [Endpoint [F ]]] = state.get.map(_.endpoints.get (method))
156
+ protected def getEndpoint (method : String ): F [Option [Endpoint [F ]]] = state.get.map(_.getEndpoint (method))
139
157
protected def sendMessage (message : Message ): F [Unit ] = queue.offer(Codec .encode(message))
140
158
141
159
protected def nextCallId (): F [CallId ] = state.modify(_.nextCallId)
0 commit comments