diff --git a/core/project.scala b/core/project.scala index e584f2965..f6f33e80a 100644 --- a/core/project.scala +++ b/core/project.scala @@ -1,6 +1,6 @@ //> using scala "3.3.1" -//> using options "-java-output-version:11", "-Ysafe-init", "-Xmax-inlines:64" -//> using options "-Wunused:all", "-feature" +//> using options "-java-output-version:11" "-Ysafe-init" "-Xmax-inlines:64" +//> using options "-feature" "-Werror" "-Wunused:all" //> using dep "org.virtuslab::besom-json:0.1.1-SNAPSHOT" diff --git a/core/src/main/scala/besom/internal/Language.scala b/core/src/main/scala/besom/internal/Language.scala new file mode 100644 index 000000000..2d945bad1 --- /dev/null +++ b/core/src/main/scala/besom/internal/Language.scala @@ -0,0 +1,116 @@ +package besom.internal + +import com.google.protobuf.* +import io.grpc.netty.NettyServerBuilder +import io.grpc.stub.StreamObserver +import io.grpc.{InsecureServerCredentials, MethodDescriptor, Server, Status} +import pulumirpc.language.* +import pulumirpc.language.LanguageRuntimeGrpc.LanguageRuntime +import pulumirpc.plugin.* + +import java.util.concurrent.TimeUnit +import scala.concurrent.{ExecutionContext, Future} + +trait LanguageRuntimeService extends LanguageRuntime: + def run(request: RunRequest): Future[RunResponse] = + request.getInfo + Future.successful(RunResponse()) + + // Unimplemented on purpose + def getRequiredPlugins(request: GetRequiredPluginsRequest): Future[GetRequiredPluginsResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_REQUIRED_PLUGINS) + + def getPluginInfo(request: empty.Empty): Future[PluginInfo] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_PLUGIN_INFO) + + def installDependencies(request: InstallDependenciesRequest, responseObserver: StreamObserver[InstallDependenciesResponse]): Unit = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_INSTALL_DEPENDENCIES, responseObserver) + + def about(request: empty.Empty): Future[AboutResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_ABOUT) + + def getProgramDependencies(request: GetProgramDependenciesRequest): Future[GetProgramDependenciesResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_PROGRAM_DEPENDENCIES) + + def runPlugin(request: RunPluginRequest, responseObserver: StreamObserver[RunPluginResponse]): Unit = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_RUN_PLUGIN, responseObserver) + + def generateProgram(request: GenerateProgramRequest): Future[GenerateProgramResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PROGRAM) + + def generateProject(request: GenerateProjectRequest): Future[GenerateProjectResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PROJECT) + + def generatePackage(request: GeneratePackageRequest): Future[GeneratePackageResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PACKAGE) + + def pack(request: PackRequest): Future[PackResponse] = + unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_PACK) + + private def unimplementedUnaryCall[A, B](methodDescriptor: MethodDescriptor[A, B]): Future[B] = + Future.failed( + Status.UNIMPLEMENTED.withDescription(s"Method ${methodDescriptor.getFullMethodName} is unimplemented").asRuntimeException() + ) + + private def unimplementedUnaryCall[A, B](methodDescriptor: MethodDescriptor[A, B], responseObserver: StreamObserver[B]): Unit = + responseObserver.onError( + Status.UNIMPLEMENTED.withDescription(s"Method ${methodDescriptor.getFullMethodName} is unimplemented").asRuntimeException() + ) + +end LanguageRuntimeService + +object LanguageRuntimeService extends LanguageRuntimeService + +object LanguageRuntimeServer: + def apply(service: LanguageRuntimeService)(using ExecutionContext): LanguageRuntimeServer = + // TODO: detect that nested stack operations are not supported https://github.com/pulumi/pulumi/issues/5058 + val server = NettyServerBuilder + .forPort(0 /* random port */, InsecureServerCredentials.create()) + .addService( + LanguageRuntimeGrpc.bindService(service, summon[ExecutionContext]) + ) + .build + new LanguageRuntimeServer(server) + +end LanguageRuntimeServer + +class LanguageRuntimeServer private (server: Server): + self => + + private val ShutdownTimeoutInSeconds = 30 + + def start(): Int = + try server.start() + catch + case e: java.io.IOException => + throw new RuntimeException("Failed to start LanguageRuntimeServer", e) + end try + + val _ = sys.addShutdownHook { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("Shutting down LanguageRuntimeServer gRPC server since JVM is shutting down") + self.stop() + } + + val port = server.getPort + println(s"LanguageRuntimeServer started, listening on $port") + port + + end start + + def stop(): Unit = + try server.shutdown().awaitTermination(ShutdownTimeoutInSeconds, TimeUnit.SECONDS) + catch + case e: InterruptedException => + throw new RuntimeException("Error while awaiting for termination of LanguageRuntimeServer", e) + end try + println("LanguageRuntimeServer shut down"); + + end stop + + def port: Int = + val port = server.getPort + if (port == -1) throw UnsupportedOperationException("Cannot get LanguageRuntimeServer port, got -1") + port + +end LanguageRuntimeServer diff --git a/core/src/main/scala/besom/rpc/pulumirpc/language/LanguageRuntimeGrpc.scala b/core/src/main/scala/besom/rpc/pulumirpc/language/LanguageRuntimeGrpc.scala index 680a14a0e..941f43074 100644 --- a/core/src/main/scala/besom/rpc/pulumirpc/language/LanguageRuntimeGrpc.scala +++ b/core/src/main/scala/besom/rpc/pulumirpc/language/LanguageRuntimeGrpc.scala @@ -132,7 +132,7 @@ object LanguageRuntimeGrpc { .addMethod(METHOD_GENERATE_PACKAGE) .addMethod(METHOD_PACK) .build() - + /** LanguageRuntime is the interface that the planning monitor uses to drive execution of an interpreter responsible * for confguring and creating resource objects. */