Skip to content

Commit 3a7438c

Browse files
committed
Added tests, corrected some behaviour
1 parent ebf2f12 commit 3a7438c

File tree

13 files changed

+185
-85
lines changed

13 files changed

+185
-85
lines changed

build.sc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class FS2Module(versionKey: String) extends define.Module {
7070
def crossScalaVersion = crossVersion
7171
def targetPlatform: Platform = Platform.JVM
7272
def ivyDeps = T(super.ivyDeps() ++ crossPlatformIvyDeps())
73-
object test extends Tests
73+
object test extends WeaverTests
7474
}
7575

7676
object js extends ScalaJSModule with RpcCrossScalaModule {
@@ -79,7 +79,7 @@ class FS2Module(versionKey: String) extends define.Module {
7979
def targetPlatform: Platform = Platform.JS
8080
def scalaJSVersion = versions.scalaJSVersion
8181
def ivyDeps = T(super.ivyDeps() ++ crossPlatformIvyDeps())
82-
object test extends Tests
82+
object test extends WeaverTests
8383
}
8484
}
8585

@@ -99,6 +99,11 @@ trait RpcCrossScalaModule extends CrossPlatformScalaModule {
9999
trait Tests extends super.Tests with TestModule.Munit {
100100
def ivyDeps = Agg(ivy"org.scalameta::munit:$munitVersion")
101101
}
102+
103+
trait WeaverTests extends Tests {
104+
def ivyDeps = Agg(ivy"com.disneystreaming::weaver-cats:0.7.13")
105+
def testFramework = "weaver.framework.CatsEffect"
106+
}
102107
}
103108

104109
trait CrossPlatformScalaModule extends ScalaModule with CrossModuleBase {

core/src/jsonrpclib/Channel.scala

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
package jsonrpclib
22

3-
import jsonrpclib.EndpointTemplate.NotificationTemplate
4-
import jsonrpclib.EndpointTemplate.RequestResponseTemplate
3+
import jsonrpclib.StubTemplate.NotificationTemplate
4+
import jsonrpclib.StubTemplate.RequestResponseTemplate
55

66
trait Channel[F[_]] {
77
def mountEndpoint(endpoint: Endpoint[F]): F[Unit]
88
def unmountEndpoint(method: String): F[Unit]
99

10-
def notificationStub[In](method: String)(implicit inCodec: Codec[In]): In => F[Unit]
11-
def requestResponseStub[In, Err, Out](
12-
method: String
13-
)(implicit inCodec: Codec[In], errCodec: ErrorCodec[Err], outCodec: Codec[Out]): In => F[Either[Err, Out]]
14-
15-
def clientStub[In, Err, Out](template: EndpointTemplate[In, Err, Out]): In => F[Either[Err, Out]]
10+
def notificationStub[In: Codec](method: String): In => F[Unit]
11+
def simpleStub[In: Codec, Out: Codec](method: String): In => F[Out]
12+
def stub[In: Codec, Err: ErrorCodec, Out: Codec](method: String): In => F[Either[Err, Out]]
13+
def stub[In, Err, Out](template: StubTemplate[In, Err, Out]): In => F[Either[Err, Out]]
1614
}
1715

1816
object Channel {
1917

2018
protected[jsonrpclib] abstract class MonadicChannel[F[_]](implicit F: Monadic[F]) extends Channel[F] {
2119

22-
final def clientStub[In, Err, Out](template: EndpointTemplate[In, Err, Out]): In => F[Either[Err, Out]] =
20+
final def stub[In, Err, Out](template: StubTemplate[In, Err, Out]): In => F[Either[Err, Out]] =
2321
template match {
2422
case NotificationTemplate(method, inCodec) =>
2523
val stub = notificationStub(method)(inCodec)
2624
(in: In) => F.doFlatMap(stub(in))(unit => F.doPure(Right(unit)))
2725
case RequestResponseTemplate(method, inCodec, errCodec, outCodec) =>
28-
requestResponseStub(method)(inCodec, errCodec, outCodec)
26+
stub(method)(inCodec, errCodec, outCodec)
2927
}
28+
29+
final def simpleStub[In: Codec, Out: Codec](method: String): In => F[Out] = {
30+
val s = stub[In, ErrorPayload, Out](method)
31+
(in: In) =>
32+
F.doFlatMap(s(in)) {
33+
case Left(e) => F.doRaiseError(e)
34+
case Right(a) => F.doPure(a)
35+
}
36+
}
3037
}
3138

3239
}

core/src/jsonrpclib/EndpointTemplate.scala

Lines changed: 0 additions & 15 deletions
This file was deleted.

core/src/jsonrpclib/ErrorPayload.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec
44
import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker
55

66
private[jsonrpclib] case class ErrorPayload(code: Int, message: String, data: Option[Payload]) extends Throwable {
7-
override def getMessage(): String = message
7+
override def getMessage(): String = s"JsonRPC Error $code: $message"
88
}
99

1010
private[jsonrpclib] object ErrorPayload {

core/src/jsonrpclib/Monadic.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ trait Monadic[F[_]] {
77
def doFlatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
88
def doPure[A](a: A): F[A]
99
def doAttempt[A](fa: F[A]): F[Either[Throwable, A]]
10+
def doRaiseError[A](e: Throwable): F[A]
1011
}
1112

1213
object Monadic {
@@ -16,5 +17,7 @@ object Monadic {
1617
def doPure[A](a: A): Future[A] = Future.successful(a)
1718

1819
def doAttempt[A](fa: Future[A]): Future[Either[Throwable, A]] = fa.map(Right(_)).recover(Left(_))
20+
21+
def doRaiseError[A](e: Throwable): Future[A] = Future.failed(e)
1922
}
2023
}

core/src/jsonrpclib/ProtocolError.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sealed abstract class ProtocolError(val code: Int, message: String) extends Thro
77
object ProtocolError {
88
final case class ParseError(message: String) extends ProtocolError(-32700, message)
99
final case class InvalidRequest(message: String) extends ProtocolError(-32600, message)
10-
final case class MethodNotFound(message: String) extends ProtocolError(-32601, message)
10+
final case class MethodNotFound(method: String) extends ProtocolError(-32601, s"Method $method not found")
1111
final case class InvalidParams(message: String) extends ProtocolError(-32602, message)
1212
final case class InternalError(message: String) extends ProtocolError(-32603, message)
1313
final case class ServerError(override val code: Int, message: String) extends ProtocolError(code, message)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package jsonrpclib
2+
3+
sealed trait StubTemplate[In, Err, Out]
4+
object StubTemplate {
5+
def notification[In](method: String)(implicit inCodec: Codec[In]): StubTemplate[In, Nothing, Unit] =
6+
NotificationTemplate[In](method, inCodec)
7+
8+
def simple[In, Out](
9+
method: String
10+
)(implicit inCodec: Codec[In], outCodec: Codec[Out]): StubTemplate[In, ErrorPayload, Out] =
11+
RequestResponseTemplate[In, ErrorPayload, Out](method, inCodec, ErrorCodec.errorPayloadCodec, outCodec)
12+
13+
final case class NotificationTemplate[In](
14+
method: String,
15+
inCodec: Codec[In]
16+
) extends StubTemplate[In, Nothing, Unit]
17+
final case class RequestResponseTemplate[In, Err, Out](
18+
method: String,
19+
inCodec: Codec[In],
20+
errCodec: ErrorCodec[Err],
21+
outCodec: Codec[Out]
22+
) extends StubTemplate[In, Err, Out]
23+
}

core/src/jsonrpclib/internals/CallId.scala

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,14 @@
11
package jsonrpclib.internals
22

3-
import io.circe.Json
43
import com.github.plokhotnyuk.jsoniter_scala.core._
54
import scala.util.Try
6-
import io.circe.Codec
7-
import io.circe.{Decoder, HCursor}
8-
import io.circe.JsonNumber
9-
import io.circe.JsonObject
10-
import io.circe.DecodingFailure
115

12-
private[jsonrpclib] sealed trait CallId
13-
private[jsonrpclib] object CallId {
6+
sealed trait CallId
7+
object CallId {
148
final case class NumberId(long: Long) extends CallId
159
final case class StringId(string: String) extends CallId
1610
case object NullId extends CallId
1711

18-
implicit val callIdCodec: Codec[CallId] = new Codec[CallId] {
19-
def apply(c: HCursor): Decoder.Result[CallId] = c.value.foldWith(
20-
new Json.Folder[Decoder.Result[CallId]] {
21-
val error = Left(DecodingFailure("Expected string, integer or null", c.history))
22-
def onNull: Decoder.Result[CallId] = Right(NullId)
23-
def onString(value: String): Decoder.Result[CallId] = Right(StringId(value))
24-
def onNumber(value: JsonNumber): Decoder.Result[CallId] = value.toLong match {
25-
case None => error
26-
case Some(value) => Right(NumberId(value))
27-
}
28-
def onBoolean(value: Boolean): Decoder.Result[CallId] = error
29-
def onArray(value: Vector[Json]): Decoder.Result[CallId] = error
30-
def onObject(value: JsonObject): Decoder.Result[CallId] = error
31-
}
32-
)
33-
def apply(a: CallId): Json = a match {
34-
case NumberId(long) => Json.fromLong(long)
35-
case StringId(string) => Json.fromString(string)
36-
case NullId => Json.Null
37-
}
38-
}
39-
4012
implicit val callIdRW: JsonValueCodec[CallId] = new JsonValueCodec[CallId] {
4113
def decodeValue(in: JsonReader, default: CallId): CallId =
4214
Try(in.readLong())

core/src/jsonrpclib/internals/Message.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec
55
import com.github.plokhotnyuk.jsoniter_scala.core.JsonReader
66
import com.github.plokhotnyuk.jsoniter_scala.core.JsonWriter
77

8-
private[jsonrpclib] sealed trait Message { def maybeCallId: Option[CallId] }
8+
sealed trait Message { def maybeCallId: Option[CallId] }
99
private[jsonrpclib] sealed trait InputMessage extends Message { def method: String }
1010
private[jsonrpclib] sealed trait OutputMessage extends Message {
1111
def callId: CallId; final override def maybeCallId: Option[CallId] = Some(callId)
@@ -31,14 +31,14 @@ private[jsonrpclib] object OutputMessage {
3131
private[jsonrpclib] object Message {
3232

3333
implicit val messageJsonValueCodecs: JsonValueCodec[Message] = new JsonValueCodec[Message] {
34-
val rawMessageCodec = implicitly[JsonValueCodec[RawMessage]]
34+
val rawMessageCodec = implicitly[JsonValueCodec[internals.RawMessage]]
3535
def decodeValue(in: JsonReader, default: Message): Message =
3636
rawMessageCodec.decodeValue(in, null).toMessage match {
3737
case Left(error) => throw error
3838
case Right(value) => value
3939
}
4040
def encodeValue(x: Message, out: JsonWriter): Unit =
41-
rawMessageCodec.encodeValue(RawMessage.from(x), out)
41+
rawMessageCodec.encodeValue(internals.RawMessage.from(x), out)
4242
def nullValue: Message = null
4343
}
4444
}

core/src/jsonrpclib/internals/MessageDispatcher.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import scala.concurrent.Promise
1010
import java.util.concurrent.atomic.AtomicLong
1111
import jsonrpclib.Endpoint.NotificationEndpoint
1212
import jsonrpclib.Endpoint.RequestResponseEndpoint
13-
import jsonrpclib.EndpointTemplate.NotificationTemplate
14-
import jsonrpclib.EndpointTemplate.RequestResponseTemplate
13+
import jsonrpclib.StubTemplate.NotificationTemplate
14+
import jsonrpclib.StubTemplate.RequestResponseTemplate
1515
import jsonrpclib.internals.OutputMessage.ErrorMessage
1616
import jsonrpclib.internals.OutputMessage.ResponseMessage
1717
import scala.util.Try
@@ -20,6 +20,7 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
2020

2121
import F._
2222

23+
protected def background[A](fa: F[A]): F[Unit]
2324
protected def reportError(params: Option[Payload], error: ProtocolError, method: String): F[Unit]
2425
protected def getEndpoint(method: String): F[Option[Endpoint[F]]]
2526
protected def sendMessage(message: Message): F[Unit]
@@ -34,7 +35,7 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
3435
sendMessage(message)
3536
}
3637

37-
def requestResponseStub[In, Err, Out](
38+
def stub[In, Err, Out](
3839
method: String
3940
)(implicit inCodec: Codec[In], errCodec: ErrorCodec[Err], outCodec: Codec[Out]): In => F[Either[Err, Out]] = {
4041
(input: In) =>
@@ -43,7 +44,7 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
4344
val message = InputMessage.RequestMessage(method, callId, Some(encoded))
4445
doFlatMap(createPromise[Either[Err, Out]]()) { case (fulfill, future) =>
4546
val pc = createPendingCall(method, errCodec, outCodec, fulfill)
46-
doFlatMap(storePendingCall(callId, pc))(_ => future())
47+
doFlatMap(storePendingCall(callId, pc))(_ => doFlatMap(sendMessage(message))(_ => future()))
4748
}
4849
}
4950
}
@@ -52,7 +53,7 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
5253
Codec.decode[Message](Some(payload)).map {
5354
case im: InputMessage =>
5455
doFlatMap(getEndpoint(im.method)) {
55-
case Some(ep) => executeInputMessage(im, ep)
56+
case Some(ep) => background(executeInputMessage(im, ep))
5657
case None =>
5758
im.maybeCallId match {
5859
case None =>
@@ -63,7 +64,11 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
6364
sendProtocolError(callId, error)
6465
}
6566
}
66-
case im: OutputMessage => doPure(())
67+
case om: OutputMessage =>
68+
doFlatMap(removePendingCall(om.callId)) {
69+
case Some(pendingCall) => pendingCall(om)
70+
case None => doPure(()) // TODO do something
71+
}
6772
} match {
6873
case Left(error) =>
6974
sendProtocolError(error)
@@ -117,8 +122,8 @@ private[jsonrpclib] abstract class MessageDispatcher[F[_]](implicit F: Monadic[F
117122
message match {
118123
case ErrorMessage(_, errorPayload) =>
119124
errCodec.decode(errorPayload) match {
120-
case Left(decodeError) => fulfill(scala.util.Failure(decodeError))
121-
case Right(value) => fulfill(scala.util.Success(Left(value)))
125+
case Left(_) => fulfill(scala.util.Failure(errorPayload))
126+
case Right(value) => fulfill(scala.util.Success(Left(value)))
122127
}
123128
case ResponseMessage(_, data) =>
124129
outCodec.decode(Some(data)) match {

0 commit comments

Comments
 (0)