Skip to content

Commit

Permalink
Update jsonrpc4s (via a fork)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexarchambault committed Mar 14, 2024
1 parent 0e2c96b commit 12a823a
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 1 deletion.
7 changes: 6 additions & 1 deletion build.sc
Expand Up @@ -48,6 +48,7 @@ object Dependencies {
ivy"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core:$jsoniterVersion"
def jsoniterMacros =
ivy"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVersion"
def jsonrpc4s = ivy"io.github.alexarchambault.bleep::jsonrpc4s:0.1.1"
def junit = ivy"com.github.sbt:junit-interface:0.13.3"
def libdaemonjvm = ivy"io.github.alexarchambault.libdaemon::libdaemon:0.0.11"
def libraryManagement = ivy"org.scala-sbt::librarymanagement-ivy:1.9.3"
Expand Down Expand Up @@ -158,7 +159,11 @@ class Shared(val crossScalaVersion: String) extends BloopCrossSbtModule with Pub
emptyZip()
}
def ivyDeps = super.ivyDeps() ++ Agg(
Dependencies.bsp4s.exclude(("com.github.plokhotnyuk.jsoniter-scala", "*")),
Dependencies.bsp4s
.exclude(("com.github.plokhotnyuk.jsoniter-scala", "*"))
.exclude(("me.vican.jorge", "jsonrpc4s_2.12"))
.exclude(("me.vican.jorge", "jsonrpc4s_2.13")),
Dependencies.jsonrpc4s,
Dependencies.coursierInterface,
Dependencies.jsoniterCore,
Dependencies.log4j,
Expand Down
134 changes: 134 additions & 0 deletions integration/test/src/bloop/cli/integration/BspTests.scala
@@ -0,0 +1,134 @@
package bloop.cli.integration

import java.net.{StandardProtocolFamily, UnixDomainSocketAddress}
import java.nio.channels.SocketChannel
import java.nio.charset.StandardCharsets
import java.nio.ByteBuffer

class BspTests extends munit.FunSuite {

test("no JSON junk in errors") {
TmpDir.fromTmpDir { root =>
val dirArgs = Seq[os.Shellable]("--daemon-dir", root / "daemon")
val bspFile = root / "bsp-socket"

val dummyMsg =
"""{
| "jsonrpc": "2.0",
| "method": "workspace/buildTargetz",
| "params": null,
| "id": 2
|}""".stripMargin

var bspProc: os.SubProcess = null
var socket: SocketChannel = null

try {
os.proc(Launcher.launcher, dirArgs, "about")
.call(cwd = root, stdin = os.Inherit, stdout = os.Inherit, env = Launcher.extraEnv)

bspProc =
os.proc(Launcher.launcher, dirArgs, "bsp", "--protocol", "local", "--socket", bspFile)
.spawn(cwd = root, stdin = os.Inherit, stdout = os.Inherit)

val addr = UnixDomainSocketAddress.of(bspFile.toNIO)
var connected = false
var attemptCount = 0

while (!connected && bspProc.isAlive() && attemptCount < 10) {
if (attemptCount > 0)
Thread.sleep(1000L)
attemptCount += 1

if (os.exists(bspFile)) {
socket = SocketChannel.open(StandardProtocolFamily.UNIX)
socket.connect(addr)
socket.finishConnect()
connected = true
}
}

if (!connected)
sys.error("Not connected to Bloop server via BSP :|")

def sendMsg(msg: String): Unit = {
val bytes = msg.getBytes(StandardCharsets.UTF_8)

def doWrite(buf: ByteBuffer): Unit =
if (buf.position() < buf.limit()) {
val written = socket.write(buf)
if (written == 0)
Thread.sleep(100L)
doWrite(buf)
}

doWrite(ByteBuffer.wrap(
(s"Content-Length: ${bytes.length}" + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)
))
doWrite(ByteBuffer.wrap(bytes))
}

sendMsg(dummyMsg)

val arr = Array.ofDim[Byte](10 * 1024)
val buf = ByteBuffer.wrap(arr)

// seems to do the job…
def doRead(buf: ByteBuffer, count: Int): Int = {
val read = socket.read(buf)
if (read <= 0 && count < 100) {
Thread.sleep(100L)
doRead(buf, count + 1)
}
else
read
}

val read = doRead(buf, 0)
assert(read > 0)

val resp = new String(arr, 0, read, StandardCharsets.UTF_8)

def validateJson(content: String): Boolean = {
assert(content.startsWith("{"))
assert(content.endsWith("}"))
val chars = content.toCharArray
val objCount = Array.ofDim[Int](chars.length)
for (i <- 0 until chars.length) {
val previous = if (i == 0) 0 else objCount(i - 1)
val count = previous + (if (chars(i) == '{') 1 else if (chars(i) == '}') -1 else 0)
objCount(i) = count
}
objCount.dropRight(1).forall(_ > 0)
}

resp.linesWithSeparators.toVector match {
case Seq(cl, empty, other @ _*)
if cl.startsWith("Content-Length:") && empty.trim.isEmpty =>
val json = other.mkString
val validated = validateJson(json)
if (!validated)
pprint.err.log(json)
assert(validated, "Unexpected JSON response shape")
case _ =>
pprint.err.log(resp)
sys.error("Unexpected response shape")
}
}
finally {
if (socket != null)
socket.close()

if (bspProc != null) {
bspProc.waitFor(1000L)
if (bspProc.isAlive())
bspProc.close()

os.proc(Launcher.launcher, dirArgs, "exit")
.call(cwd = root, stdin = os.Inherit, stdout = os.Inherit, check = false)
}
}
}
}

}

0 comments on commit 12a823a

Please sign in to comment.