initProtocol endpoint returns success when already initialized (#10542)

* initProtocol endpoint returns success when already initialized

* Fix test

* Docs and return error when clientId differs

* fmt

* fix: session management test

* misc: json connection controller

---------

Co-authored-by: Dmitry Bushev <bushevdv@gmail.com>

Issue with Vector nothing to do with this.
This commit is contained in:
Adam Obuchowicz 2024-07-23 08:45:53 +02:00 committed by GitHub
parent 8bce22a122
commit 71bae7e4b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 63 additions and 17 deletions

View File

@ -1440,6 +1440,9 @@ This message initializes the connection used to send the textual protocol
messages. This initialization is important such that the client identifier can
be correlated between the textual and data connections.
The subsequent `session/initProtocolConnection` calls with same clientId will
immediately return success message.
- **Type:** Request
- **Direction:** Client -> Server
- **Connection:** Protocol
@ -1464,7 +1467,7 @@ interface SessionInitProtocolConnectionResult {
#### Errors
- [`SessionAlreadyInitialisedError`](#sessionalreadyinitializederror) to signal
that the session is already initialized.
that the session is already initialized with different clientId.
- [`ResourcesInitializationError`](#resourcesinitializationerror) to signal
about the error during the initialization of Language Server resources.

View File

@ -284,17 +284,18 @@ class JsonConnectionController(
cancellable.cancel()
unstashAll()
val allContentRoots = allRoots.map(_.toContentRoot).toSet
receiver ! ResponseResult(
InitProtocolConnection,
request.id,
InitProtocolConnection.Result(
buildinfo.Info.ensoVersion,
buildinfo.Info.currentEdition,
allRoots.map(_.toContentRoot).toSet
allContentRoots
)
)
initialize(webActor, rpcSession)
initialize(webActor, rpcSession, allContentRoots)
} else {
context.become(
waitingForContentRoots(
@ -303,7 +304,7 @@ class JsonConnectionController(
request = request,
receiver = receiver,
cancellable = cancellable,
rootsSoFar = roots ++ rootsSoFar
rootsSoFar = allRoots
)
)
}
@ -319,10 +320,11 @@ class JsonConnectionController(
private def initialize(
webActor: ActorRef,
rpcSession: JsonSession
rpcSession: JsonSession,
roots: Set[ContentRoot]
): Unit = {
val requestHandlers = createRequestHandlers(rpcSession)
context.become(initialised(webActor, rpcSession, requestHandlers))
context.become(initialised(webActor, rpcSession, requestHandlers, roots))
context.system.eventStream
.subscribe(self, classOf[Api.ProgressNotification])
@ -331,10 +333,27 @@ class JsonConnectionController(
private def initialised(
webActor: ActorRef,
rpcSession: JsonSession,
requestHandlers: Map[Method, Props]
requestHandlers: Map[Method, Props],
roots: Set[ContentRoot]
): Receive = LoggingReceive {
case Request(InitProtocolConnection, id, _) =>
sender() ! ResponseError(Some(id), SessionAlreadyInitialisedError)
case Request(
InitProtocolConnection,
id,
InitProtocolConnection.Params(clientId)
) =>
if (clientId == rpcSession.clientId) {
sender() ! ResponseResult(
InitProtocolConnection,
id,
InitProtocolConnection.Result(
buildinfo.Info.ensoVersion,
buildinfo.Info.currentEdition,
roots
)
)
} else {
sender() ! ResponseError(Some(id), SessionAlreadyInitialisedError)
}
case MessageHandler.Disconnected(_) =>
logger.info("Session terminated [{}].", rpcSession.clientId)

View File

@ -65,25 +65,49 @@ class SessionManagementTest extends BaseServerTest with ReportLogsOnFailure {
"connection is initialised" must {
"reply with an error if client tries initialise connection second time" in {
"reply with a standard message if client tries initialise connection second time" in {
val (client, clientId) = getInitialisedWsClientAndId()
client.send(json"""
{ "jsonrpc": "2.0",
"method": "session/initProtocolConnection",
"id": 1,
"params": {
"clientId": $clientId
}
}
""")
val response = client.expectSomeJson().asObject.value
response("jsonrpc") shouldEqual Some("2.0".asJson)
response("id") shouldEqual Some(1.asJson)
val result = response("result").value.asObject.value
result("contentRoots").value.asArray.value should contain(
json"""
{
"id" : $testContentRootId,
"type" : "Project"
}
"""
)
}
"reply with an error if client tries initialise connection second time with different clientId" in {
val client = getInitialisedWsClient()
client.send(json"""
{ "jsonrpc": "2.0",
"method": "session/initProtocolConnection",
"id": 1,
"params": {
"clientId": "e3d99192-2edc-4613-bdf4-db35e4b9b956"
"clientId": "f3d99192-2edc-4613-bdf4-db35e4b9b957"
}
}
""")
client.expectJson(json"""
{ "jsonrpc":"2.0",
"id":1,
"error": { "code": 6002, "message": "Session already initialised" }
}
""")
{ "jsonrpc":"2.0",
"id":1,
"error": { "code": 6002, "message": "Session already initialised" }
}
""")
}
}
}