From 36813bc6f6441c85278d6bb153090f04326796b8 Mon Sep 17 00:00:00 2001 From: EdwinBetanc0urt Date: Mon, 9 Dec 2024 12:26:40 -0400 Subject: [PATCH] feat: Add version with system info. --- .github/workflows/publish.yml | 10 ++ build.gradle | 18 ++-- .../adempiere-processors-service.dsc | Bin 86431 -> 93478 bytes src/main/java/org/spin/base/Version.java | 94 ++++++++++++++++++ .../spin/processor/controller/Processors.java | 22 +++- .../processor/server/ProcessorServer.java | 71 +++++++++---- .../org/spin/processor/service/Service.java | 36 ++++++- src/main/proto/service/processor.proto | 20 +++- 8 files changed, 238 insertions(+), 33 deletions(-) create mode 100644 src/main/java/org/spin/base/Version.java diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dc3633c..a153200 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -27,6 +27,15 @@ jobs: java-version: 11 architecture: x64 + - name: Set Main Version + run: echo "MAIN_VERSION=${{ github.event.release.name }}" >> src/main/java/org/spin/base/version.properties + + - name: Set Release Date + run: echo "DATE_VERSION=$(date +'%Y-%m-%d')" >> src/main/java/org/spin/base/version.properties + + - name: Set Implementation Version + run: echo "IMPLEMENTATION_VERSION=${{ github.event.release.tag_name }}" >> src/main/java/org/spin/base/version.properties + - name: Build with Gradle uses: gradle/actions/setup-gradle@v3 with: @@ -45,6 +54,7 @@ jobs: with: name: adempiere-processors-service.dsc path: build/descriptors/adempiere-processors-service.dsc + retention-days: 1 - name: Upload dist app zip artifact uses: actions/upload-artifact@v4 diff --git a/build.gradle b/build.gradle index 8501a93..4c981fb 100644 --- a/build.gradle +++ b/build.gradle @@ -82,13 +82,17 @@ protobuf { } sourceSets { - main { - java { - srcDirs 'build/generated/source/proto/main/grpc' - srcDirs 'build/generated/source/proto/main/java' - srcDirs 'src/main/proto' - } - } + main { + java { + srcDirs 'build/generated/source/proto/main/grpc' + srcDirs 'build/generated/source/proto/main/java' + srcDirs 'src/main/proto' + } + resources { + srcDirs 'src/main/java' + include 'org/spin/base/version.properties' + } + } } // Copy proto descriptor another folder diff --git a/docker-compose/envoy/definitions/adempiere-processors-service.dsc b/docker-compose/envoy/definitions/adempiere-processors-service.dsc index 98238b21418ca4168e0dd15fa1363361d8d0ddef..21e46e247893cfc43a4b654c19e603e0ec99746a 100644 GIT binary patch delta 6567 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 Y>&>~lAq1|sh8_f5djqb(gvaH-0q2v>uK)l5 delta 1094 zcmX|8VMvCcmYZpBszqssCWbZvz~GJ&6)GfKWFCsPyg*Z|J5gU<2L_o68@CkO4wLkpmL6= zmM=R(TcKJ*+ddtK(HOOEYg`h|?uk+cR9JO2SWG>31dC~R^ad`&jVycBWao&rrX0J< zYBn2AcZuvs0SFb@*?_PyvLgjS7uk_=a#Yl8Yyh-X>|H=q%bPR>2yK<6vhHb~!Nab2 zY&-dT#CqY1GP`(NRQ2n7jxdNu_*jQJOFQL< zZ(risN+Y%6{bJQhvSYUVgd)X3$#&9Tip+Ms9 z+$v!0&aDF0?%XP1-JDy6wbII3nphgyQ. * + ************************************************************************************/ + +package org.spin.base; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.util.Properties; + +import org.compiere.util.CLogger; + +/** + * @author Edwin Betancourt, EdwinBetanc0urt@outlook.com, https://github.com/EdwinBetanc0urt + * Service for backend of Version + */ +public final class Version +{ + + private static CLogger log = CLogger.getCLogger(Version.class); + + /** Main Version String */ + // Conventions for naming second number is even for stable, and odd for unstable + // the releases will have a suffix (a) for alpha - (b) for beta - (t) for trunk - (s) for stable - and (LTS) for long term support + public static String MAIN_VERSION = "1.0.0-dev"; + + /** Detail Version as date Used for Client/Server */ + public static String DATE_VERSION = (new SimpleDateFormat("yyyy-MM-dd")).format( + new Date( + System.currentTimeMillis() + ) + ); + + public static String IMPLEMENTATION_VERSION = "1.0.0-dev"; + + static { + ClassLoader loader = Version.class.getClassLoader(); + InputStream inputStream = loader.getResourceAsStream("org/spin/base/version.properties"); + if (inputStream != null) { + Properties properties = new Properties(); + try { + properties.load(inputStream); + + if (properties.containsKey("MAIN_VERSION")) { + MAIN_VERSION = properties.getProperty("MAIN_VERSION"); + } + if (properties.containsKey("DATE_VERSION")) { + DATE_VERSION = properties.getProperty("DATE_VERSION"); + } + if (properties.containsKey("IMPLEMENTATION_VERSION")) { + IMPLEMENTATION_VERSION = properties.getProperty("IMPLEMENTATION_VERSION"); + } + } catch (IOException e) { + // file does not exists + log.warning("File version.properties does no exists"); + } + } + } + + /** + * Get Product Version + * @return Application Version + */ + public static String getVersion() + { + return MAIN_VERSION + " @ " + DATE_VERSION; + } // getVersion + + public static String getMainVersion() { + return MAIN_VERSION; + } + + public static String getDateVersion() { + return DATE_VERSION; + } + + public static String getImplementationVersion() { + return IMPLEMENTATION_VERSION; + } + +} // Adempiere diff --git a/src/main/java/org/spin/processor/controller/Processors.java b/src/main/java/org/spin/processor/controller/Processors.java index 92221f6..0ecddad 100644 --- a/src/main/java/org/spin/processor/controller/Processors.java +++ b/src/main/java/org/spin/processor/controller/Processors.java @@ -17,7 +17,9 @@ import org.compiere.util.CLogger; import org.spin.proto.processor.RunProcessorRequest; import org.spin.proto.processor.RunProcessorResponse; +import org.spin.proto.processor.SystemInfo; import org.spin.processor.service.Service; +import org.spin.proto.processor.GetSystemInfoRequest; import org.spin.proto.processor.ProcessorsGrpc.ProcessorsImplBase; import io.grpc.Status; @@ -27,8 +29,24 @@ public class Processors extends ProcessorsImplBase { /** Logger */ private CLogger log = CLogger.getCLogger(Processors.class); - - + + + @Override + public void getSystemInfo(GetSystemInfoRequest request, StreamObserver responseObserver) { + try { + SystemInfo.Builder builder = Service.getSystemInfo(); + responseObserver.onNext(builder.build()); + responseObserver.onCompleted(); + } catch (Exception e) { + log.severe(e.getLocalizedMessage()); + responseObserver.onError(Status.INTERNAL + .withDescription(e.getLocalizedMessage()) + .withCause(e) + .asRuntimeException() + ); + } + } + @Override public void runAccounting(RunProcessorRequest request, StreamObserver responseObserver) { try { diff --git a/src/main/java/org/spin/processor/server/ProcessorServer.java b/src/main/java/org/spin/processor/server/ProcessorServer.java index a63dfca..a14461d 100644 --- a/src/main/java/org/spin/processor/server/ProcessorServer.java +++ b/src/main/java/org/spin/processor/server/ProcessorServer.java @@ -16,6 +16,8 @@ import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.logging.Logger; import org.compiere.util.Env; @@ -33,8 +35,30 @@ public class ProcessorServer { private static final Logger logger = Logger.getLogger(ProcessorServer.class.getName()); + private ServiceContextProvider contextProvider = new ServiceContextProvider(); + private Server server; + + /** Services/Methods allow request without Bearer token validation */ + private List ALLOW_REQUESTS_WITHOUT_TOKEN = Arrays.asList( + // proto package . proto service / proto method + "processor.Processors/GetSystemInfo" + ); + + /** Revoke session */ + private List REVOKE_TOKEN_SERVICES = Arrays.asList( + // proto package . proto service / proto method + ); + + private AuthorizationServerInterceptor getInterceptor() { + AuthorizationServerInterceptor interceptor = new AuthorizationServerInterceptor(); + interceptor.setAllowRequestsWithoutToken(this.ALLOW_REQUESTS_WITHOUT_TOKEN); + interceptor.setRevokeTokenServices(this.REVOKE_TOKEN_SERVICES); + return interceptor; + } + + /** * Get SSL / TLS context * @return @@ -48,10 +72,11 @@ private SslContextBuilder getSslContextBuilder() { } return GrpcSslContexts.configure(sslClientContextBuilder); } - + private void start() throws IOException { // Start based on provider - Env.setContextProvider(contextProvider); + Env.setContextProvider(contextProvider); + logger.info("Service Template added on " + SetupLoader.getInstance().getServer().getPort()); // ServerBuilder serverBuilder; @@ -60,8 +85,12 @@ private void start() throws IOException { .sslContext(getSslContextBuilder().build()); } else { serverBuilder = ServerBuilder.forPort(SetupLoader.getInstance().getServer().getPort()); - serverBuilder.intercept(new AuthorizationServerInterceptor()); } + + // Validate JWT on all requests + AuthorizationServerInterceptor interceptor = getInterceptor(); + serverBuilder.intercept(interceptor); + serverBuilder.addService(new Processors()); server = serverBuilder.build().start(); logger.info("Server started, listening on " + SetupLoader.getInstance().getServer().getPort()); @@ -75,22 +104,22 @@ public void run() { } }); } - + private void stop() { - if (server != null) { - server.shutdown(); - } + if (server != null) { + server.shutdown(); + } } - + /** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); - } + } } - + public static void main(String[] args) throws Exception { if (args == null) { throw new Exception("Arguments Not Found"); @@ -99,15 +128,15 @@ public static void main(String[] args) throws Exception { if (args.length == 0) { throw new Exception("Arguments Must Be: [property file name]"); } - String setupFileName = args[0]; - if(setupFileName == null || setupFileName.trim().length() == 0) { - throw new Exception("Setup File not found"); - } - SetupLoader.loadSetup(setupFileName); - // Validate load - SetupLoader.getInstance().validateLoad(); - final ProcessorServer server = new ProcessorServer(); - server.start(); - server.blockUntilShutdown(); - } + String setupFileName = args[0]; + if(setupFileName == null || setupFileName.trim().length() == 0) { + throw new Exception("Setup File not found"); + } + SetupLoader.loadSetup(setupFileName); + // Validate load + SetupLoader.getInstance().validateLoad(); + final ProcessorServer server = new ProcessorServer(); + server.start(); + server.blockUntilShutdown(); + } } diff --git a/src/main/java/org/spin/processor/service/Service.java b/src/main/java/org/spin/processor/service/Service.java index 247e806..08a18e6 100644 --- a/src/main/java/org/spin/processor/service/Service.java +++ b/src/main/java/org/spin/processor/service/Service.java @@ -24,6 +24,7 @@ import org.compiere.util.Msg; import org.compiere.util.Util; import org.eevolution.services.dsl.ProcessBuilder; +import org.spin.base.Version; import org.spin.eca46.process.AcctProcessor; import org.spin.eca46.process.AlertProcessor; import org.spin.eca46.process.ProjectProcessor; @@ -32,10 +33,37 @@ import org.spin.eca46.process.WorkflowProcessor; import org.spin.proto.processor.ProcessorLog; import org.spin.proto.processor.RunProcessorResponse; +import org.spin.proto.processor.SystemInfo; +import org.spin.service.grpc.util.value.StringManager; +import org.spin.service.grpc.util.value.TimeManager; import org.spin.service.grpc.util.value.ValueManager; public class Service { - + + public static SystemInfo.Builder getSystemInfo() { + SystemInfo.Builder builder = SystemInfo.newBuilder(); + // backend info + builder.setDateVersion( + ValueManager.getTimestampFromDate( + TimeManager.getTimestampFromString( + Version.DATE_VERSION + ) + ) + ) + .setMainVersion( + StringManager.getValidString( + Version.MAIN_VERSION + ) + ) + .setImplementationVersion( + StringManager.getValidString( + Version.IMPLEMENTATION_VERSION + ) + ) + ; + return builder; + } + public static RunProcessorResponse.Builder runAccounting(int clientId, int id) { return runProcess(AcctProcessor.getProcessId(), AcctProcessor.C_ACCTPROCESSOR_ID, clientId, id); } @@ -104,7 +132,11 @@ private static RunProcessorResponse.Builder runProcess(int processId, String par // Set error message String summary = Msg.parseTranslation(Env.getCtx(), result.getSummary()); if(Util.isEmpty(summary, true)) { - result.setSummary(ValueManager.validateNull(e.getLocalizedMessage())); + result.setSummary( + StringManager.getValidString( + e.getLocalizedMessage() + ) + ); } } // diff --git a/src/main/proto/service/processor.proto b/src/main/proto/service/processor.proto index 13007d6..50713c8 100644 --- a/src/main/proto/service/processor.proto +++ b/src/main/proto/service/processor.proto @@ -4,9 +4,20 @@ option java_package = "org.spin.proto.processor"; option java_multiple_files = true; import "google/api/annotations.proto"; +import "google/protobuf/timestamp.proto"; package processor; +message GetSystemInfoRequest { + // empty request +} +message SystemInfo { + // report service + google.protobuf.Timestamp date_version = 1; + string main_version = 2; + string implementation_version = 3; +} + // Delete Batch Entity Request message RunProcessorRequest { int32 id = 1; @@ -27,6 +38,13 @@ message ProcessorLog { // The greeting service definition. service Processors { + // system information + rpc GetSystemInfo(GetSystemInfoRequest) returns (SystemInfo) { + option (google.api.http) = { + get: "/v1/processors/system-info" + }; + } + // Accounting Processor rpc RunAccounting(RunProcessorRequest) returns (RunProcessorResponse) { option (google.api.http) = { post: "/v1/accounting/{client_id}/{id}" }; @@ -51,4 +69,4 @@ service Processors { rpc RunWorkflow(RunProcessorRequest) returns (RunProcessorResponse) { option (google.api.http) = { post: "/v1/workflow/{client_id}/{id}" }; } -} \ No newline at end of file +}