Skip to content

Commit 6cba215

Browse files
committed
add: RenameProjectEndpoint
1 parent c91ac60 commit 6cba215

File tree

3 files changed

+160
-2
lines changed

3 files changed

+160
-2
lines changed

engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import org.enso.languageserver.libraries._
2424
import org.enso.languageserver.monitoring.{
2525
HealthCheckEndpoint,
2626
IdlenessEndpoint,
27-
IdlenessMonitor
27+
IdlenessMonitor,
28+
RenameProjectEndpoint
2829
}
2930
import org.enso.languageserver.profiling.{EventsMonitorActor, ProfilingManager}
3031
import org.enso.languageserver.protocol.binary.{
@@ -448,6 +449,13 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: Level) {
448449
private val idlenessEndpoint =
449450
new IdlenessEndpoint(idlenessMonitor)
450451

452+
private val renameProjectEndpoint =
453+
RenameProjectEndpoint(
454+
timeout = 10.seconds,
455+
runtimeConnector = runtimeConnector,
456+
actorFactory = system
457+
)(serverConfig.computeExecutionContext)
458+
451459
private val jsonRpcProtocolFactory = new JsonRpcProtocolFactory
452460

453461
private val initializationComponent =
@@ -503,7 +511,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: Level) {
503511
lazyMessageTimeout = 10.seconds,
504512
secureConfig = secureConfig
505513
),
506-
List(healthCheckEndpoint, idlenessEndpoint),
514+
List(healthCheckEndpoint, idlenessEndpoint, renameProjectEndpoint),
507515
messagesCallback
508516
)(system, materializer)
509517
log.trace("Created JSON RPC Server [{}]", jsonRpcServer)

engine/language-server/src/main/scala/org/enso/languageserver/monitoring/ReadinessMonitor.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import org.enso.languageserver.event.InitializedEvent.{
88
}
99
import org.enso.languageserver.monitoring.MonitoringProtocol.{IsReady, KO, OK}
1010

11+
import java.util.concurrent.atomic.AtomicBoolean
12+
1113
/** An actor that monitors if the system is ready to accept requests. */
1214
class ReadinessMonitor() extends Actor with LazyLogging {
1315

@@ -26,6 +28,7 @@ class ReadinessMonitor() extends Actor with LazyLogging {
2628

2729
private def stateTransition(): Receive = {
2830
case InitializationFinished =>
31+
ReadinessMonitor.readyState.set(true)
2932
context.become(ready())
3033

3134
case InitializationFailed =>
@@ -37,6 +40,12 @@ class ReadinessMonitor() extends Actor with LazyLogging {
3740

3841
object ReadinessMonitor {
3942

43+
/** The readiness state. */
44+
private val readyState: AtomicBoolean = new AtomicBoolean(false)
45+
46+
/** Checks the readiness. */
47+
def isReady: Boolean = readyState.get()
48+
4049
/** Creates a configuration object used to create a
4150
* [[ReadinessMonitor]]
4251
*
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package org.enso.languageserver.monitoring
2+
3+
import akka.actor.{ActorRef, ActorRefFactory}
4+
import akka.http.scaladsl.model.StatusCodes
5+
import akka.http.scaladsl.server.Directives._
6+
import akka.http.scaladsl.server.Route
7+
import akka.pattern.ask
8+
import akka.util.Timeout
9+
import com.typesafe.scalalogging.LazyLogging
10+
import io.circe._
11+
import io.circe.generic.semiauto._
12+
import io.circe.parser._
13+
import org.enso.jsonrpc._
14+
import org.enso.languageserver.refactoring.RefactoringApi
15+
import org.enso.languageserver.requesthandler.refactoring.RenameProjectHandler
16+
17+
import java.util.UUID
18+
19+
import scala.concurrent.ExecutionContext
20+
import scala.concurrent.duration._
21+
import scala.util.{Failure, Success}
22+
23+
/** An HTTP endpoint that handles rename requests of the opened project.
24+
*
25+
* @param timeout the runtime request timeout
26+
* @param runtimeConnector the runtime connector
27+
* @param actorFactory the actor creation factory
28+
* @param ec the execution context
29+
*/
30+
class RenameProjectEndpoint(
31+
timeout: FiniteDuration,
32+
runtimeConnector: ActorRef,
33+
actorFactory: ActorRefFactory
34+
)(implicit ec: ExecutionContext)
35+
extends Endpoint
36+
with LazyLogging {
37+
38+
implicit private val askTimeout: Timeout = Timeout(timeout)
39+
40+
implicit val renameProjectParamsDecoder
41+
: Decoder[RefactoringApi.RenameProject.Params] =
42+
deriveDecoder[RefactoringApi.RenameProject.Params]
43+
44+
implicit val renameProjectParamsEncoder
45+
: Encoder[RefactoringApi.RenameProject.Params] =
46+
deriveEncoder[RefactoringApi.RenameProject.Params]
47+
48+
override def route: Route =
49+
renameProject
50+
51+
private val renameProject = {
52+
path("refactoring" / "renameProject") {
53+
post {
54+
entity(as[String]) { body =>
55+
if (ReadinessMonitor.isReady) {
56+
handleRenameProject(body)
57+
} else {
58+
complete(
59+
StatusCodes.InternalServerError,
60+
Json.obj("error" -> Json.fromString("Not initialized")).noSpaces
61+
)
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
private def handleRenameProject(body: String): Route = {
69+
parse(body).flatMap(_.as[RefactoringApi.RenameProject.Params]) match {
70+
case Right(params) =>
71+
val handler = actorFactory.actorOf(
72+
RenameProjectHandler.props(timeout, runtimeConnector),
73+
s"rename-project-handler-${UUID.randomUUID()}"
74+
)
75+
76+
val requestId = Id.String(UUID.randomUUID().toString)
77+
val request = Request(RefactoringApi.RenameProject, requestId, params)
78+
79+
val future = (handler ? request).map {
80+
case ResponseResult(
81+
RefactoringApi.RenameProject,
82+
`requestId`,
83+
Unused
84+
) =>
85+
StatusCodes.OK -> Json
86+
.obj("status" -> Json.fromString("success"))
87+
.noSpaces
88+
case ResponseError(Some(`requestId`), error) =>
89+
StatusCodes.BadRequest -> Json
90+
.obj("error" -> Json.fromString(error.message))
91+
.noSpaces
92+
case _ =>
93+
StatusCodes.InternalServerError -> Json
94+
.obj("error" -> Json.fromString("Unexpected response"))
95+
.noSpaces
96+
}
97+
98+
onComplete(future) {
99+
case Success((status, responseBody)) =>
100+
complete(status, responseBody)
101+
case Failure(ex) =>
102+
logger.error("Failed to rename project", ex)
103+
complete(
104+
StatusCodes.InternalServerError,
105+
Json.obj("error" -> Json.fromString(ex.getMessage)).noSpaces
106+
)
107+
}
108+
109+
case Left(error) =>
110+
logger.error(s"Failed to parse rename project request: $error")
111+
complete(
112+
StatusCodes.BadRequest,
113+
Json
114+
.obj(
115+
"error" -> Json.fromString(
116+
s"Invalid request format: ${error.getMessage}"
117+
)
118+
)
119+
.noSpaces
120+
)
121+
}
122+
}
123+
}
124+
125+
object RenameProjectEndpoint {
126+
127+
/** Create a new endpoint for renaming the opened project.
128+
*
129+
* @param timeout the runtime request timeout
130+
* @param runtimeConnector the runtime connector
131+
* @param actorFactory the actor creation factory
132+
* @param ec the execution context
133+
* @return an instance of [[RenameProjectEndpoint]]
134+
*/
135+
def apply(
136+
timeout: FiniteDuration,
137+
runtimeConnector: ActorRef,
138+
actorFactory: ActorRefFactory
139+
)(implicit ec: ExecutionContext): RenameProjectEndpoint =
140+
new RenameProjectEndpoint(timeout, runtimeConnector, actorFactory)
141+
}

0 commit comments

Comments
 (0)