@@ -16,50 +16,45 @@ import jsonrpclib.internals.MessageDispatcher
16
16
import jsonrpclib .internals ._
17
17
18
18
import scala .util .Try
19
- import _root_ .fs2 .concurrent .SignallingRef
20
19
21
20
trait FS2Channel [F [_]] extends Channel [F ] {
21
+
22
+ def input : Pipe [F , Payload , Unit ]
23
+ def output : Stream [F , Payload ]
24
+
22
25
def withEndpoint (endpoint : Endpoint [F ])(implicit F : Functor [F ]): Resource [F , FS2Channel [F ]] =
23
26
Resource .make(mountEndpoint(endpoint))(_ => unmountEndpoint(endpoint.method)).map(_ => this )
24
27
25
28
def withEndpointStream (endpoint : Endpoint [F ])(implicit F : MonadCancelThrow [F ]): Stream [F , FS2Channel [F ]] =
26
29
Stream .resource(withEndpoint(endpoint))
27
30
28
31
def withEndpoints (endpoint : Endpoint [F ], rest : Endpoint [F ]* )(implicit F : Monad [F ]): Resource [F , FS2Channel [F ]] =
29
- (endpoint :: rest.toList).traverse_(withEndpoint).as(this )
32
+ withEndpoints(endpoint +: rest)
33
+
34
+ def withEndpoints (endpoints : Seq [Endpoint [F ]])(implicit F : Monad [F ]): Resource [F , FS2Channel [F ]] =
35
+ endpoints.toList.traverse_(withEndpoint).as(this )
30
36
31
37
def withEndpointStream (endpoint : Endpoint [F ], rest : Endpoint [F ]* )(implicit
32
38
F : MonadCancelThrow [F ]
33
39
): Stream [F , FS2Channel [F ]] =
34
40
Stream .resource(withEndpoints(endpoint, rest : _* ))
35
41
36
- def open : Resource [ F , Unit ]
37
- def openStream : Stream [ F , Unit ]
38
- def openStreamForever : Stream [ F , Nothing ]
42
+ def withEndpointsStream ( endpoints : Seq [ Endpoint [ F ]])( implicit F : MonadCancelThrow [ F ]) : Stream [ F , FS2Channel [ F ]] =
43
+ Stream .resource(withEndpoints(endpoints))
44
+
39
45
}
40
46
41
47
object FS2Channel {
42
48
43
- def lspCompliant [F [_]: Concurrent ](
44
- byteStream : Stream [F , Byte ],
45
- byteSink : Pipe [F , Byte , Unit ],
46
- bufferSize : Int = 512 ,
47
- cancelTemplate : Option [CancelTemplate ] = None
48
- ): Stream [F , FS2Channel [F ]] = internals.LSP .writeSink(byteSink, bufferSize).flatMap { sink =>
49
- apply[F ](internals.LSP .readStream(byteStream), sink, cancelTemplate)
50
- }
51
-
52
49
def apply [F [_]: Concurrent ](
53
- payloadStream : Stream [F , Payload ],
54
- payloadSink : Payload => F [Unit ],
50
+ bufferSize : Int = 2048 ,
55
51
cancelTemplate : Option [CancelTemplate ] = None
56
52
): Stream [F , FS2Channel [F ]] = {
57
53
for {
58
54
supervisor <- Stream .resource(Supervisor [F ])
59
55
ref <- Ref [F ].of(State [F ](Map .empty, Map .empty, Map .empty, 0 )).toStream
60
- isOpen <- SignallingRef [F ].of(false ).toStream
61
- awaitingSink = isOpen.waitUntil(identity) >> payloadSink(_ : Payload )
62
- impl = new Impl (awaitingSink, ref, isOpen, supervisor, cancelTemplate)
56
+ queue <- cats.effect.std.Queue .bounded[F , Payload ](bufferSize).toStream
57
+ impl = new Impl (queue, ref, supervisor, cancelTemplate)
63
58
64
59
// Creating a bespoke endpoint to receive cancelation requests
65
60
maybeCancelEndpoint : Option [Endpoint [F ]] = cancelTemplate.map { ct =>
@@ -71,10 +66,6 @@ object FS2Channel {
71
66
}
72
67
// mounting the cancelation endpoint
73
68
_ <- maybeCancelEndpoint.traverse_(ep => impl.mountEndpoint(ep)).toStream
74
- _ <- Stream (()).concurrently {
75
- // Gatekeeping the pull until the channel is actually marked as open
76
- payloadStream.pauseWhen(isOpen.map(b => ! b)).evalMap(impl.handleReceivedPayload)
77
- }
78
69
} yield impl
79
70
}
80
71
@@ -107,15 +98,17 @@ object FS2Channel {
107
98
}
108
99
109
100
private class Impl [F [_]](
110
- private val sink : Payload => F [ Unit ],
101
+ private val queue : cats.effect.std. Queue [ F , Payload ],
111
102
private val state : Ref [F , FS2Channel .State [F ]],
112
- private val isOpen : SignallingRef [F , Boolean ],
113
103
supervisor : Supervisor [F ],
114
104
maybeCancelTemplate : Option [CancelTemplate ]
115
105
)(implicit F : Concurrent [F ])
116
106
extends MessageDispatcher [F ]
117
107
with FS2Channel [F ] {
118
108
109
+ def output : Stream [F , Payload ] = Stream .fromQueueUnterminated(queue)
110
+ def input : Pipe [F , Payload , Unit ] = _.evalMap(handleReceivedPayload)
111
+
119
112
def mountEndpoint (endpoint : Endpoint [F ]): F [Unit ] = state
120
113
.modify(s =>
121
114
s.mountEndpoint(endpoint) match {
@@ -127,10 +120,6 @@ object FS2Channel {
127
120
128
121
def unmountEndpoint (method : String ): F [Unit ] = state.update(_.removeEndpoint(method))
129
122
130
- def open : Resource [F , Unit ] = Resource .make[F , Unit ](isOpen.set(true ))(_ => isOpen.set(false ))
131
- def openStream : Stream [F , Unit ] = Stream .resource(open)
132
- def openStreamForever : Stream [F , Nothing ] = openStream.evalMap(_ => F .never)
133
-
134
123
protected [fs2] def cancel (callId : CallId ): F [Unit ] = state.get.map(_.runningCalls.get(callId)).flatMap {
135
124
case None => F .unit
136
125
case Some (fiber) => fiber.cancel
@@ -147,7 +136,7 @@ object FS2Channel {
147
136
}
148
137
protected def reportError (params : Option [Payload ], error : ProtocolError , method : String ): F [Unit ] = ???
149
138
protected def getEndpoint (method : String ): F [Option [Endpoint [F ]]] = state.get.map(_.endpoints.get(method))
150
- protected def sendMessage (message : Message ): F [Unit ] = sink (Codec .encode(message))
139
+ protected def sendMessage (message : Message ): F [Unit ] = queue.offer (Codec .encode(message))
151
140
152
141
protected def nextCallId (): F [CallId ] = state.modify(_.nextCallId)
153
142
protected def createPromise [A ](callId : CallId ): F [(Try [A ] => F [Unit ], () => F [A ])] = Deferred [F , Try [A ]].map {
0 commit comments