diff --git a/src/main/java/org/caosdb/server/grpc/ServerSideScriptingServiceImpl.java b/src/main/java/org/caosdb/server/grpc/ServerSideScriptingServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..ea68d8f7fbbdbcc630d6987ae2531dd5366e405b --- /dev/null +++ b/src/main/java/org/caosdb/server/grpc/ServerSideScriptingServiceImpl.java @@ -0,0 +1,123 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2025 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2025 Joscha Schmiedt <joscha@schmiedt.dev> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.caosdb.server.grpc; + +import com.google.protobuf.Timestamp; +import io.grpc.Status; +import io.grpc.StatusException; +import io.grpc.stub.StreamObserver; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authz.UnauthorizedException; +import org.apache.shiro.subject.Subject; +import org.caosdb.api.scripting.v1alpha1.ExecuteServerSideScriptRequest; +import org.caosdb.api.scripting.v1alpha1.ExecuteServerSideScriptResponse; +import org.caosdb.api.scripting.v1alpha1.ServerSideScriptExecutionId; +import org.caosdb.api.scripting.v1alpha1.ServerSideScriptExecutionResult; +import org.caosdb.api.scripting.v1alpha1.ServerSideScriptingServiceGrpc.ServerSideScriptingServiceImplBase; +import org.caosdb.server.accessControl.AuthenticationUtils; +import org.caosdb.server.utils.ServerMessages; + +/** + * Main entry point for the server-side scripting service of the server's GRPC API. + * + * @author Joscha Schmiedt <joscha@schmiedt.dev> + */ +public class ServerSideScriptingServiceImpl extends ServerSideScriptingServiceImplBase { + + @Override + public void executeServerSideScript( + ExecuteServerSideScriptRequest request, + io.grpc.stub.StreamObserver<org.caosdb.api.scripting.v1alpha1.ExecuteServerSideScriptResponse> + responseObserver) { + // ServerSideScriptingCaller caller = new ServerSideScriptingCaller() + // caller.executeServerSideScript(request, responseObserver); + try { + AuthInterceptor.bindSubject(); + ExecuteServerSideScriptResponse response = executeScript(request); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + } catch (final Exception e) { + ServerSideScriptingServiceImpl.handleException(responseObserver, e); + } + } + + private ExecuteServerSideScriptResponse executeScript(ExecuteServerSideScriptRequest request) { + + String scriptExecutionId = ""; + String scriptFilename = ""; + ServerSideScriptExecutionResult result = + ServerSideScriptExecutionResult.SERVER_SIDE_SCRIPT_EXECUTION_RESULT_GENERAL_FAILURE; + int returnCode = 1; + String stdout = ""; + String stderr = ""; + Timestamp startTime = Timestamp.newBuilder().setSeconds(0).setNanos(0).build(); + Timestamp endTime = Timestamp.newBuilder().setSeconds(0).setNanos(0).build(); + int duration_ms = 0; + + final ExecuteServerSideScriptResponse response = + ExecuteServerSideScriptResponse.newBuilder() + .setScriptExecutionId( + ServerSideScriptExecutionId.newBuilder() + .setScriptExecutionId(scriptExecutionId) + .build()) + .setScriptFilename(scriptFilename) + .setResult(result) + .setReturnCode(returnCode) + .setStdout(stdout) + .setStderr(stderr) + .setStartTime(startTime) + .setEndTime(endTime) + .setDurationMs(duration_ms) + .build(); + return response; + } + + public static void handleException(StreamObserver<?> responseObserver, Exception e) { + String description = e.getMessage(); + if (description == null || description.isBlank()) { + description = "Unknown Error. Please Report!"; + } + if (e instanceof UnauthorizedException) { + Subject subject = SecurityUtils.getSubject(); + if (AuthenticationUtils.isAnonymous(subject)) { + responseObserver.onError(new StatusException(AuthInterceptor.PLEASE_LOG_IN)); + return; + } else { + responseObserver.onError( + new StatusException( + Status.PERMISSION_DENIED.withCause(e).withDescription(description))); + return; + } + } else if (e == ServerMessages.ROLE_DOES_NOT_EXIST + || e == ServerMessages.ACCOUNT_DOES_NOT_EXIST) { + responseObserver.onError( + new StatusException(Status.NOT_FOUND.withDescription(description).withCause(e))); + return; + } + // TODO: SERVER_SIDE_DOES_NOT_EXIST, SERVER_SIDE_SCRIPT_NOT_EXECUTABLE, + // SERVER_SIDE_SCRIPT_ERROR, SERVER_SIDE_SCRIPT_SETUP_ERROR, + // SERVER_SIDE_SCRIPT_TIMEOUT, SERVER_SIDE_SCRIPT_MISSING_CALL + e.printStackTrace(); + responseObserver.onError( + new StatusException(Status.UNKNOWN.withDescription(description).withCause(e))); + } +}