diff --git a/.checkstyle b/.checkstyle
new file mode 100644
index 0000000..d6e04dd
--- /dev/null
+++ b/.checkstyle
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1f5659b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,64 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+out
+.idea
+
+# compiled output
+/dist
+/dist-server
+/tmp
+/out-tsc
+
+/front/dist
+
+config.env
+
+*.class
+
+dataPush
+node_modules
+
+# dependencies
+applicationFront/node_modules
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# e2e
+/e2e/*.js
+/e2e/*.map
+
+# System Files
+.DS_Store
+Thumbs.db
+
+backPY/env
+
+*.pyc
+
+__pycache__
+
+.design/
+.vscode/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..5f3781a
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,79 @@
+######################################################################################
+##
+## buyilding-end install applications:
+##
+######################################################################################
+FROM archlinux:base-devel AS builder
+# update system
+RUN pacman -Syu --noconfirm && pacman-db-upgrade \
+ && pacman -S --noconfirm jdk-openjdk maven npm \
+ && pacman -Scc --noconfirm
+
+ENV PATH /tmp/node_modules/.bin:$PATH
+WORKDIR /tmp
+
+######################################################################################
+##
+## Build back:
+##
+######################################################################################
+FROM builder AS buildBack
+COPY back/pom.xml /tmp
+COPY back/src /tmp/src/
+RUN mvn clean compile assembly:single
+
+######################################################################################
+##
+## Build front:
+##
+######################################################################################
+FROM builder AS buildFront
+
+ADD front/package-lock.json \
+ front/package.json \
+ front/karma.conf.js \
+ front/protractor.conf.js \
+ /tmp/
+
+# install and cache app dependencies
+RUN npm install
+
+ADD front/e2e \
+ front/tsconfig.json \
+ front/tslint.json \
+ front/angular.json \
+ /tmp/
+ADD front/src /tmp/src
+
+# generate build
+RUN ng build --output-path=dist --configuration=production --base-href=/karusic/ --deploy-url=/karusic/
+
+######################################################################################
+##
+## Production area:
+##
+######################################################################################
+
+FROM bellsoft/liberica-openjdk-alpine:latest
+# add wget to manage the health check...
+RUN apk add --no-cache wget
+
+#FROM archlinux:base
+#RUN pacman -Syu --noconfirm && pacman-db-upgrade
+## install package
+#RUN pacman -S --noconfirm jdk-openjdk wget
+## intall npm
+#RUN pacman -S --noconfirm npm
+## clean all the caches Need only on the release environment
+#RUN pacman -Scc --noconfirm
+
+ENV LANG=C.UTF-8
+
+COPY --from=buildBack /tmp/out/maven/*.jar /application/application.jar
+COPY --from=buildFront /tmp/dist /application/front/
+
+WORKDIR /application/
+
+EXPOSE 80
+
+CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]
diff --git a/back/CheckStyle.xml b/back/CheckStyle.xml
new file mode 100755
index 0000000..d68aedd
--- /dev/null
+++ b/back/CheckStyle.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/CleanUp.xml b/back/CleanUp.xml
new file mode 100644
index 0000000..9df98d2
--- /dev/null
+++ b/back/CleanUp.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/Dockerfile b/back/Dockerfile
new file mode 100644
index 0000000..8fc1c69
--- /dev/null
+++ b/back/Dockerfile
@@ -0,0 +1,21 @@
+FROM maven:3.6.3-openjdk-16 AS build
+
+COPY pom.xml /tmp/
+COPY src /tmp/src/
+WORKDIR /tmp/
+RUN mvn clean compile assembly:single
+
+
+
+FROM bellsoft/liberica-openjdk-alpine:latest
+ENV LANG=C.UTF-8
+
+
+RUN mkdir /application/
+COPY --from=build /tmp/out/maven/*.jar /application/application.jar
+WORKDIR /application/
+
+EXPOSE 18080
+
+CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]
+
diff --git a/back/Formatter.xml b/back/Formatter.xml
new file mode 100644
index 0000000..b775e22
--- /dev/null
+++ b/back/Formatter.xml
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/LICENSE b/back/LICENSE
new file mode 100644
index 0000000..a9d1e81
--- /dev/null
+++ b/back/LICENSE
@@ -0,0 +1,6 @@
+PROPIETARY licence
+==================
+
+Copyright at Edouard DUPIN
+
+you have no right
\ No newline at end of file
diff --git a/back/README.md b/back/README.md
new file mode 100644
index 0000000..db094e1
--- /dev/null
+++ b/back/README.md
@@ -0,0 +1,18 @@
+Generic backend for karanage in java
+===================================
+
+Kar manage is a tool to keep result of system inpection like docker, ros diagnostics, system status ...
+
+
+
+mvn install
+
+// create a single package jar
+mvn clean compile assembly:single
+
+
+
+java -cp out/maven/karanage-0.1.0-jar-with-dependencies.jar org.kar.karideo.WebLauncher
+
+
+
diff --git a/back/db.sql b/back/db.sql
new file mode 100644
index 0000000..fd40910
--- /dev/null
+++ b/back/db.sql
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/back/pom.xml b/back/pom.xml
new file mode 100644
index 0000000..0e5b697
--- /dev/null
+++ b/back/pom.xml
@@ -0,0 +1,174 @@
+
+ 4.0.0
+ org.kar
+ karanage
+ 0.1.0
+
+
+ 3.1
+ 17
+ 17
+
+ 3.1.1
+
+
+
+ gitea
+ https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven
+
+
+
+
+
+ kangaroo-and-rabbit
+ archidata
+ 0.1.3
+
+
+
+
+ src
+ test/src
+ ${project.basedir}/out/maven/
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven.compiler.version}
+
+
+ ${maven.compiler.target}
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.4.0
+
+ io.scenarium.oauth.WebLauncher
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M5
+
+
+ maven-assembly-plugin
+
+
+
+ fully.qualified.MainClass
+
+
+
+ jar-with-dependencies
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.2.0
+
+ private
+ true
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.2.0
+
+ public
+
+
+
+
+
+
\ No newline at end of file
diff --git a/back/src/org/kar/karanage/WebLauncher.java b/back/src/org/kar/karanage/WebLauncher.java
new file mode 100755
index 0000000..c73e4f3
--- /dev/null
+++ b/back/src/org/kar/karanage/WebLauncher.java
@@ -0,0 +1,118 @@
+package org.kar.karanage;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.kar.karanage.api.Front;
+import org.kar.karanage.api.HealthCheck;
+import org.kar.karanage.api.StateResource;
+import org.kar.karanage.api.UserResource;
+import org.kar.archidata.GlobalConfiguration;
+import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.UpdateJwtPublicKey;
+import org.kar.archidata.filter.AuthenticationFilter;
+import org.kar.archidata.filter.CORSFilter;
+import org.kar.archidata.filter.OptionFilter;
+import org.kar.archidata.util.ConfigBaseVariable;
+import org.kar.karanage.model.DataHistory;
+import org.kar.karanage.model.DataInstant;
+import org.kar.karanage.model.Group;
+
+public class WebLauncher {
+ private WebLauncher() {
+ }
+
+ private static URI getBaseURI() {
+ return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
+ }
+
+ public static void main(String[] args) {
+ ConfigBaseVariable.bdDatabase = "karanage";
+
+ // generate the BDD:
+ try {
+ String out = "";
+ out += SqlWrapper.createTable(DataInstant.class);
+ out += SqlWrapper.createTable(DataHistory.class);
+ out += SqlWrapper.createTable(Group.class);
+ System.out.println(out);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ // ===================================================================
+ // Configure resources
+ // ===================================================================
+ ResourceConfig rc = new ResourceConfig();
+
+ // add multipart models ..
+ rc.register(new MultiPartFeature());
+ // global authentication system
+ rc.register(new OptionFilter());
+ // remove cors ==> all time called by an other system...
+ rc.register(new CORSFilter());
+ // global authentication system
+ rc.registerClasses(AuthenticationFilter.class);
+ // add default resource:
+ rc.registerClasses(UserResource.class);
+ rc.registerClasses(StateResource.class);
+
+ rc.registerClasses(HealthCheck.class);
+ rc.registerClasses(Front.class);
+
+ // add jackson to be discovenr when we are ins standalone server
+ rc.register(JacksonFeature.class);
+ // enable this to show low level request
+ //rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
+
+ //System.out.println("Connect on the BDD:");
+ //System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
+ //System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
+ //System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
+ //System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
+ //System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
+ System.out.println(" ==> " + GlobalConfiguration.dbConfig);
+ System.out.println("OAuth service " + getBaseURI());
+ HttpServer server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("Stopping server..");
+ server.shutdownNow();
+ }
+ }, "shutdownHook"));
+
+ // ===================================================================
+ // start periodic update of the token ...
+ // ===================================================================
+ UpdateJwtPublicKey keyUpdater = new UpdateJwtPublicKey();
+ keyUpdater.start();
+
+ // ===================================================================
+ // run JERSEY
+ // ===================================================================
+ try {
+ server.start();
+ System.out.println("Jersey app started at " + getBaseURI());
+ System.out.println("Press CTRL^C to exit..");
+ Thread.currentThread().join();
+ } catch (Exception e) {
+ System.out.println("There was an error while starting Grizzly HTTP server.");
+ e.printStackTrace();
+ }
+ keyUpdater.kill();
+ try {
+ keyUpdater.join(4000, 0);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/back/src/org/kar/karanage/WebLauncherLocal.java b/back/src/org/kar/karanage/WebLauncherLocal.java
new file mode 100755
index 0000000..659f9ad
--- /dev/null
+++ b/back/src/org/kar/karanage/WebLauncherLocal.java
@@ -0,0 +1,16 @@
+package org.kar.karanage;
+
+import org.kar.archidata.util.ConfigBaseVariable;
+
+public class WebLauncherLocal {
+ private WebLauncherLocal() {}
+
+ public static void main(String[] args) throws InterruptedException {
+ if (true) {
+ // for local test:
+ ConfigBaseVariable.apiAdress = "http://0.0.0.0:20080/karanage/api/";
+ ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
+ }
+ WebLauncher.main(args);
+ }
+}
diff --git a/back/src/org/kar/karanage/api/Front.java b/back/src/org/kar/karanage/api/Front.java
new file mode 100644
index 0000000..b7018cd
--- /dev/null
+++ b/back/src/org/kar/karanage/api/Front.java
@@ -0,0 +1,22 @@
+package org.kar.karanage.api;
+
+import java.io.File;
+import java.util.List;
+
+import org.kar.archidata.annotation.security.PermitAll;
+import javax.ws.rs.*;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.kar.archidata.api.FrontGeneric;
+import org.kar.karanage.util.ConfigVariable;
+
+@Path("/karanage")
+public class Front extends FrontGeneric {
+ public Front() {
+ this.baseFrontFolder = ConfigVariable.getFrontFolder();
+
+ }
+}
diff --git a/back/src/org/kar/karanage/api/HealthCheck.java b/back/src/org/kar/karanage/api/HealthCheck.java
new file mode 100644
index 0000000..c71a77d
--- /dev/null
+++ b/back/src/org/kar/karanage/api/HealthCheck.java
@@ -0,0 +1,28 @@
+package org.kar.karanage.api;
+
+import org.kar.archidata.annotation.security.PermitAll;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+
+import org.kar.archidata.util.JWTWrapper;
+
+@Path("/health_check")
+@Produces(MediaType.APPLICATION_JSON)
+public class HealthCheck {
+ public class HealthResult {
+ public String value;
+ public HealthResult(String value) {
+ this.value = value;
+ }
+ }
+ // todo : do it better...
+ @GET
+ @PermitAll
+ public Response getHealth() {
+ if (JWTWrapper.getPublicKey() == null) {
+ return Response.status(500).entity(new HealthResult("Missing Jwt public token")).build();
+ }
+ return Response.status(200).entity(new HealthResult("alive and kicking")).build();
+ }
+}
diff --git a/back/src/org/kar/karanage/api/StateResource.java b/back/src/org/kar/karanage/api/StateResource.java
new file mode 100644
index 0000000..a19e36f
--- /dev/null
+++ b/back/src/org/kar/karanage/api/StateResource.java
@@ -0,0 +1,111 @@
+package org.kar.karanage.api;
+
+import org.kar.archidata.SqlWrapper;
+import org.kar.karanage.model.DataInstant;
+import org.kar.karanage.model.DataHistory;
+import org.kar.karanage.model.Group;
+import javax.ws.rs.core.Response;
+
+
+import org.kar.archidata.annotation.security.PermitAll;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.List;
+
+
+@Path("/state")
+@Produces({MediaType.APPLICATION_JSON})
+public class StateResource {
+
+ @GET
+ @Path("{group}/{topic:.*}")
+ //@RolesAllowed("USER")
+ @PermitAll
+ public static DataInstant getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
+ Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
+ if (group == null) {
+ throw new Exception("Missing Group !!!");
+ }
+ return SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic);
+ }
+
+ @GET
+ @Path("{group}")
+ //@RolesAllowed("USER")
+ @PermitAll
+ public List get(@PathParam("group") String groupName) throws Exception {
+ Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
+ if (group == null) {
+ throw new Exception("Missing Group !!!");
+ }
+ return SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id);
+ }
+
+ @POST
+ @Path("{group}/{topic:.*}")
+ //@RolesAllowed("ADMIN")
+ @PermitAll
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response post(@PathParam("group") String groupName, @PathParam("topic") String topic, String dataToInsert) throws Exception {
+ DataInstant previous = null;
+ Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
+ if (group != null) {
+ previous = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true);
+ }
+ if (previous == null) {
+ // insert new data
+ DataInstant data = new DataInstant();
+ data.group = group.id;
+ data.topic = topic;
+ data.data = dataToInsert;
+ previous = SqlWrapper.insert(data);
+ DataHistory dataHistory = new DataHistory(previous);
+ dataHistory.year = true;
+ dataHistory.month = true;
+ dataHistory.week = true;
+ dataHistory.day = true;
+ SqlWrapper.insert(dataHistory);
+ return Response.status(201).build();
+ }
+ // update Data
+ try {
+ previous.data = dataToInsert;
+ SqlWrapper.update(previous, previous.id, List.of("data"));
+ // add it in history:
+ DataHistory dataHistory = new DataHistory(previous);
+ OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
+ OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC);
+ //tstamp = Timestamp.valueOf(ofsdatetime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime())
+
+ now.getDayOfMonth();
+ if (sqlTime.getYear() != now.getYear()) {
+ dataHistory.year = true;
+ }
+ if (sqlTime.getMonth() != now.getMonth()) {
+ dataHistory.month = true;
+ }
+ if (!sqlTime.getDayOfWeek().equals(now.getDayOfWeek())) {
+ dataHistory.week = true;
+ }
+ if (sqlTime.getDayOfYear() != now.getDayOfYear()) {
+ dataHistory.day = true;
+ }
+ if (sqlTime.getHour() != now.getHour()) {
+ dataHistory.hour = true;
+ }
+ dataHistory.modify_date = Timestamp.valueOf(now.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());
+
+ SqlWrapper.insert(dataHistory);
+ } catch (Exception ex) {
+ System.out.print("get exception: " + ex);
+ }
+ return Response.status(204).build();
+ }
+
+}
+
diff --git a/back/src/org/kar/karanage/api/UserResource.java b/back/src/org/kar/karanage/api/UserResource.java
new file mode 100755
index 0000000..94f7cff
--- /dev/null
+++ b/back/src/org/kar/karanage/api/UserResource.java
@@ -0,0 +1,101 @@
+package org.kar.karanage.api;
+
+import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.filter.GenericContext;
+import org.kar.archidata.model.User;
+import org.kar.karanage.model.UserKaranage;
+
+import org.kar.archidata.annotation.security.RolesAllowed;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.SecurityContext;
+import java.util.List;
+
+
+@Path("/users")
+@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+public class UserResource {
+
+ public UserResource() {
+ }
+
+ // curl http://localhost:9993/api/users
+ @GET
+ @RolesAllowed("ADMIN")
+ public List getUsers() {
+ System.out.println("getUsers");
+ try {
+ return SqlWrapper.gets(UserKaranage.class, false);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ // curl http://localhost:9993/api/users/3
+ @GET
+ @Path("{id}")
+ @RolesAllowed("ADMIN")
+ public UserKaranage getUsers(@Context SecurityContext sc, @PathParam("id") long userId) {
+ System.out.println("getUser " + userId);
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ System.out.println("===================================================");
+ System.out.println("== USER ? " + gc.user);
+ System.out.println("===================================================");
+ try {
+ return SqlWrapper.get(UserKaranage.class, userId);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ // curl http://localhost:9993/api/users/3
+ @GET
+ @Path("me")
+ @RolesAllowed("USER")
+ public User getMe(@Context SecurityContext sc) {
+ System.out.println("getMe()");
+ GenericContext gc = (GenericContext) sc.getUserPrincipal();
+ System.out.println("===================================================");
+ System.out.println("== USER ? " + gc.user);
+ System.out.println("===================================================");
+ return gc.user;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/src/org/kar/karanage/internal/Log.java b/back/src/org/kar/karanage/internal/Log.java
new file mode 100644
index 0000000..a70acb7
--- /dev/null
+++ b/back/src/org/kar/karanage/internal/Log.java
@@ -0,0 +1,60 @@
+package org.kar.karanage.internal;
+
+//import io.scenarium.logger.LogLevel;
+//import io.scenarium.logger.Logger;
+
+public class Log {
+// private static final String LIB_NAME = "logger";
+// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
+// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
+// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
+// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
+// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
+// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
+// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
+// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
+// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
+//
+// private Log() {}
+//
+// public static void print(String data) {
+// if (PRINT_PRINT)
+// Logger.print(LIB_NAME_DRAW, data);
+// }
+//
+// public static void todo(String data) {
+// if (PRINT_TODO)
+// Logger.todo(LIB_NAME_DRAW, data);
+// }
+//
+// public static void critical(String data) {
+// if (PRINT_CRITICAL)
+// Logger.critical(LIB_NAME_DRAW, data);
+// }
+//
+// public static void error(String data) {
+// if (PRINT_ERROR)
+// Logger.error(LIB_NAME_DRAW, data);
+// }
+//
+// public static void warning(String data) {
+// if (PRINT_WARNING)
+// Logger.warning(LIB_NAME_DRAW, data);
+// }
+//
+// public static void info(String data) {
+// if (PRINT_INFO)
+// Logger.info(LIB_NAME_DRAW, data);
+// }
+//
+// public static void debug(String data) {
+// if (PRINT_DEBUG)
+// Logger.debug(LIB_NAME_DRAW, data);
+// }
+//
+// public static void verbose(String data) {
+// if (PRINT_VERBOSE)
+// Logger.verbose(LIB_NAME_DRAW, data);
+// }
+
+}
diff --git a/back/src/org/kar/karanage/model/ApplicationToken.java b/back/src/org/kar/karanage/model/ApplicationToken.java
new file mode 100644
index 0000000..1cbf82d
--- /dev/null
+++ b/back/src/org/kar/karanage/model/ApplicationToken.java
@@ -0,0 +1,37 @@
+package org.kar.karanage.model;
+/*
+CREATE TABLE `node` (
+ `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
+ `deleted` BOOLEAN NOT NULL DEFAULT false,
+ `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
+ `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
+ `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
+ `name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
+ `description` TEXT COLLATE 'utf8_general_ci',
+ `parent_id` bigint
+) AUTO_INCREMENT=10;
+*/
+
+import org.kar.archidata.annotation.SQLComment;
+import org.kar.archidata.annotation.SQLForeignKey;
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLLimitSize;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.model.GenericTable;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@SQLTableName ("applicationToken")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class ApplicationToken extends GenericTable {
+ @SQLComment("Group of the element")
+ @SQLForeignKey("group")
+ public long group;
+ @SQLLimitSize(256)
+ @SQLComment("Token Of the application (must be use by only one application)")
+ public String token = null;
+ @SQLComment("Description of the Group")
+ @SQLLimitSize(1024)
+ public String description;
+}
\ No newline at end of file
diff --git a/back/src/org/kar/karanage/model/DataHistory.java b/back/src/org/kar/karanage/model/DataHistory.java
new file mode 100644
index 0000000..64a364c
--- /dev/null
+++ b/back/src/org/kar/karanage/model/DataHistory.java
@@ -0,0 +1,74 @@
+package org.kar.karanage.model;
+/*
+CREATE TABLE `node` (
+ `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
+ `deleted` BOOLEAN NOT NULL DEFAULT false,
+ `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
+ `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
+ `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
+ `name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
+ `description` TEXT COLLATE 'utf8_general_ci',
+ `parent_id` bigint
+) AUTO_INCREMENT=10;
+*/
+
+import java.sql.Timestamp;
+
+import org.kar.archidata.annotation.SQLAutoIncrement;
+import org.kar.archidata.annotation.SQLComment;
+import org.kar.archidata.annotation.SQLDefault;
+import org.kar.archidata.annotation.SQLForeignKey;
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLLimitSize;
+import org.kar.archidata.annotation.SQLNotNull;
+import org.kar.archidata.annotation.SQLNotRead;
+import org.kar.archidata.annotation.SQLPrimaryKey;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.annotation.SQLUpdateTime;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+
+enum State {
+ OK, FAIL, UNSTABLE, RETREIVING, HAPPY, FULL, EMPTY
+}
+enum TypeData {
+ NUMBER, BOOLEAN, JSON, STRING
+}
+
+@SQLTableName ("dataHistory")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class DataHistory extends DataInstant {
+ // default constructor
+ public DataHistory() {
+
+ }
+ public DataHistory(DataInstant other) {
+ this.group = other.group;
+ this.topic = other.topic;
+ this.state = other.state;
+ this.data = other.data;
+ }
+
+ @SQLComment("First message of the years (in GMT time)")
+ @SQLNotNull
+ @SQLDefault("0")
+ public boolean year = false;
+ @SQLComment("First message of the month (in GMT time)")
+ @SQLNotNull
+ @SQLDefault("0")
+ public boolean month = false;
+ @SQLComment("First message of the week: monday (in GMT time)")
+ @SQLNotNull
+ @SQLDefault("0")
+ public boolean week = false;
+ @SQLComment("First message of the day (in GMT time)")
+ @SQLNotNull
+ @SQLDefault("0")
+ public boolean day = false;
+ @SQLComment("First message of the hour (in GMT time)")
+ @SQLNotNull
+ @SQLDefault("0")
+ public boolean hour = false;
+}
\ No newline at end of file
diff --git a/back/src/org/kar/karanage/model/DataInstant.java b/back/src/org/kar/karanage/model/DataInstant.java
new file mode 100644
index 0000000..98cbb2b
--- /dev/null
+++ b/back/src/org/kar/karanage/model/DataInstant.java
@@ -0,0 +1,59 @@
+package org.kar.karanage.model;
+/*
+CREATE TABLE `node` (
+ `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
+ `deleted` BOOLEAN NOT NULL DEFAULT false,
+ `create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
+ `modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
+ `type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
+ `name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
+ `description` TEXT COLLATE 'utf8_general_ci',
+ `parent_id` bigint
+) AUTO_INCREMENT=10;
+*/
+
+import java.sql.Timestamp;
+
+import org.kar.archidata.annotation.SQLAutoIncrement;
+import org.kar.archidata.annotation.SQLComment;
+import org.kar.archidata.annotation.SQLForeignKey;
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLLimitSize;
+import org.kar.archidata.annotation.SQLNotNull;
+import org.kar.archidata.annotation.SQLNotRead;
+import org.kar.archidata.annotation.SQLPrimaryKey;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.annotation.SQLUpdateTime;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@SQLTableName ("data")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class DataInstant {
+ @SQLAutoIncrement // Add AUTO_INCREMENT modifier
+ @SQLPrimaryKey // Create a PRIMARY KEY based on this field
+ @SQLNotNull
+ @SQLComment("Primary key of the base")
+ public Long id = null;
+
+ // TODO: werll managed of the not read and not set update time at @now() si c'est pas bon ..
+
+ //@SQLNotRead
+ @SQLUpdateTime
+ @SQLNotNull
+ @SQLComment("When update the object")
+ public Timestamp modify_date = null;
+ @SQLComment("Group of the element")
+ @SQLForeignKey("group")
+ public long group;
+ @SQLLimitSize(256)
+ @SQLComment("Topic of the message")
+ public String topic = null;
+ @SQLComment("State of the message")
+ @SQLLimitSize(25)
+ //public State state = null;
+ public String state = null;
+ @SQLComment("Message to store")
+ public String data = null;
+}
\ No newline at end of file
diff --git a/back/src/org/kar/karanage/model/Group.java b/back/src/org/kar/karanage/model/Group.java
new file mode 100644
index 0000000..43a8eb0
--- /dev/null
+++ b/back/src/org/kar/karanage/model/Group.java
@@ -0,0 +1,24 @@
+package org.kar.karanage.model;
+
+import org.kar.archidata.annotation.SQLComment;
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLLimitSize;
+import org.kar.archidata.annotation.SQLNotNull;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.model.GenericTable;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+
+@SQLTableName ("group")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class Group extends GenericTable {
+ @SQLNotNull
+ @SQLLimitSize(256)
+ @SQLComment("Name of the group.")
+ public String name;
+ @SQLComment("Description of the Group")
+ @SQLLimitSize(1024)
+ public String description;
+}
diff --git a/back/src/org/kar/karanage/model/UserKaranage.java b/back/src/org/kar/karanage/model/UserKaranage.java
new file mode 100644
index 0000000..9db6992
--- /dev/null
+++ b/back/src/org/kar/karanage/model/UserKaranage.java
@@ -0,0 +1,14 @@
+package org.kar.karanage.model;
+
+import org.kar.archidata.annotation.SQLIfNotExists;
+import org.kar.archidata.annotation.SQLTableName;
+import org.kar.archidata.model.User;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@SQLTableName ("user")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class UserKaranage extends User {
+
+}
diff --git a/back/src/org/kar/karanage/util/ConfigVariable.java b/back/src/org/kar/karanage/util/ConfigVariable.java
new file mode 100644
index 0000000..fd2ea5e
--- /dev/null
+++ b/back/src/org/kar/karanage/util/ConfigVariable.java
@@ -0,0 +1,15 @@
+package org.kar.karanage.util;
+
+public class ConfigVariable {
+ public static final String BASE_NAME = "ORG_KARUSIC_";
+
+
+ public static String getFrontFolder() {
+ String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
+ if (out == null) {
+ return "/application/front";
+ }
+ return out;
+ }
+
+}
diff --git a/device_script/.karanage.json b/device_script/.karanage.json
new file mode 100644
index 0000000..ae1a206
--- /dev/null
+++ b/device_script/.karanage.json
@@ -0,0 +1,18 @@
+{
+ "cpu": "auto",
+ "memory": "auto",
+ "swap": "auto",
+ "drive": {
+ "include": [
+ "/",
+ "/home",
+ "/home/heero/HDD1",
+ "/home/heero/HDD2"
+ ]
+ },
+ "network": {
+ "include": [
+ "enp34s0"
+ ]
+ }
+}
diff --git a/device_script/inspect.py b/device_script/inspect.py
new file mode 100755
index 0000000..5735919
--- /dev/null
+++ b/device_script/inspect.py
@@ -0,0 +1,177 @@
+#!/bin/python3
+# Importing the library
+import psutil
+import argparse
+import time
+import subprocess
+import json
+from pathlib import Path
+from typing import Dict, List
+import requests
+
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--config", type=str, default=".karanage.json", help="json configuration file")
+parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api/state", help="Base URL of the web service")
+parser.add_argument("-g", "--group", type=str, default="home", help="Group the the message")
+parser.add_argument("-t", "--topic", type=str, default="PC/system", help="Topic of the message")
+parser.add_argument("-s", "--sleep", type=int, default=10, help="Periodicity of the messages")
+args = parser.parse_args()
+
+if Path(args.config).exists():
+ f = open(args.config, "r")
+ configuration = json.loads(f.read())
+ f.close()
+else:
+ configuration = {
+ "cpu": "auto",
+ "memory": "auto",
+ "swap": "auto",
+ "drive": "auto",
+ "network": "auto",
+ }
+
+
+def send_to_server(data: Dict) -> None:
+ ret = requests.post(f"{args.url}/{args.group}/{args.topic}", json=out)
+ if 200 <= ret.status_code <= 299:
+ pass # print(f" ==> done {ret}")
+ else:
+ print(f" ==> An error occured in sending message to the server !! {ret}")
+
+
+cpu_core_count = psutil.cpu_count(logical=False)
+cpu_thread_count = psutil.cpu_count()
+
+
+def get_mounts() -> Dict:
+ process = subprocess.Popen(
+ ["mount", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
+ stdout, stderr = process.communicate()
+ """get data format:
+ $ mount -v
+ proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
+ sys on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
+ dev on /dev type devtmpfs (rw,nosuid,relatime,size=7049156k,nr_inodes=1762289,mode=755,inode64)
+ run on /run type tmpfs (rw,nosuid,nodev,relatime,mode=755,inode64)
+ efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime)
+ /dev/nvme0n1p5 on / type ext4 (rw,relatime,stripe=32)
+ """
+ out = {}
+ lines = stdout.decode("utf-8").split("\n")
+ for line in lines:
+ tmp = line.split(" ")
+ if len(tmp) <= 2:
+ continue
+ if tmp[0].startswith('/dev/'):
+ out[tmp[2]] = tmp[0][5:]
+ return out
+
+mounting_points = get_mounts();
+
+def filter(data: Dict, filter_list: List[str]) -> Dict:
+ out = {}
+ print(f"Request filter {data.keys()} with filter {filter_list}")
+ for key in data:
+ if key in filter_list:
+ out[key] = data[key]
+ return out
+
+def need_process(data: Dict) -> Dict:
+ return configuration["cpu"] == "auto" or "include" in configuration["cpu"]
+
+
+def create_cpu_data() -> Dict:
+ # scpufreq(current=1605.5205625000003, min=400.0, max=4372.0)
+ cpu_frequency = psutil.cpu_freq(percpu=False)
+ cpu_percent_use = psutil.cpu_percent()
+ return {
+ "core": cpu_core_count,
+ "thread": cpu_thread_count,
+ "frequency": cpu_frequency.current,
+ "use": cpu_percent_use,
+ "max": cpu_frequency.max,
+ }
+
+def create_memory_data() -> Dict:
+ # svmem(total=14473519104, available=8289726464, percent=42.7, used=5380497408, free=3276263424, active=1775763456, inactive=8335540224, buffers=361771008, cached=5454987264, shared=243720192, slab=544526336)
+ mem = psutil.virtual_memory()
+ return {
+ "used": mem.used,
+ "total": mem.total,
+ }
+
+def create_swap_data() -> Dict:
+ # sswap(total=17179865088, used=262144, free=17179602944, percent=0.0, sin=0, sout=0)
+ swap = psutil.swap_memory()
+ return {
+ "used": swap.used,
+ "total": swap.total,
+ }
+def create_drive_data() -> Dict:
+ tmp_elem = {}
+ # nvme0n1p1 => sdiskio(read_count=187, write_count=3, read_bytes=6002176, write_bytes=5120, read_time=36, write_time=7, read_merged_count=504, write_merged_count=0, busy_time=67)
+ drive_access = psutil.disk_io_counters(perdisk=True)
+ for elem in mounting_points:
+ # sdiskusage(total=255162540032, used=112077000704, free=130049380352, percent=46.3)
+ drive_usage = psutil.disk_usage(elem)
+ # print(f"plop {mounting_points[elem]} ==> {drive_access.keys()}")
+ if mounting_points[elem] in drive_access:
+ tmp_elem[elem] = {
+ "read_bytes": drive_access[mounting_points[elem]].read_bytes,
+ "write_bytes": drive_access[mounting_points[elem]].write_bytes,
+ "used": drive_usage.used,
+ "total": drive_usage.total,
+ }
+ else:
+ tmp_elem[elem] = {
+ "used": drive_usage.used,
+ "total": drive_usage.total,
+ }
+ return tmp_elem
+
+def create_network_data() -> Dict:
+ # eth0 => snetio(bytes_sent=0, bytes_recv=0, packets_sent=0, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0)
+ data = psutil.net_io_counters(pernic=True)
+ tmp_elem = {}
+ for elem in data:
+ tmp_elem[elem] = {
+ "bytes_sent": data[elem].bytes_sent,
+ "bytes_recv": data[elem].bytes_recv,
+ }
+ return tmp_elem
+
+def agglutinate(configuration, name, data):
+ if configuration[name] == "auto":
+ return data
+ elif "include" in configuration[name]:
+ return filter(data, configuration[name]["include"])
+ return none
+
+while True:
+ out = {}
+ if need_process(configuration["cpu"]):
+ base_elem = create_cpu_data()
+ out["cpu"] = agglutinate(configuration, "cpu", base_elem)
+
+ if need_process(configuration["memory"]):
+ base_elem = create_memory_data()
+ out["memory"] = agglutinate(configuration, "memory", base_elem)
+
+ if need_process(configuration["swap"]):
+ base_elem = create_swap_data()
+ out["swap"] = agglutinate(configuration, "swap", base_elem)
+
+ if need_process(configuration["drive"]):
+ base_elem = create_drive_data()
+ out["drive"] = agglutinate(configuration, "drive", base_elem)
+
+ if configuration["network"] == "auto" or "include" in configuration["network"]:
+ base_elem = create_network_data()
+ out["network"] = agglutinate(configuration, "network", base_elem)
+
+ #print("Read new value:")
+ print(json.dumps(out, indent=4))
+ send_to_server(out)
+ time.sleep(args.sleep)
+
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..d82f84d
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,46 @@
+version: '3'
+
+services:
+ karusic_db_service:
+ image: mysql:latest
+ restart: always
+ command: --default-authentication-plugin=mysql_native_password
+ env_file:
+ - ./config.env
+ volumes:
+ - /workspace/data/karusic/db:/var/lib/mysql
+ mem_limit: 600m
+ healthcheck:
+ test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
+ timeout: 20s
+ retries: 10
+
+ karauth_adminer_service:
+ image: adminer:latest
+ restart: always
+ depends_on:
+ - karusic_db_service
+ ports:
+ - 19079:8080
+ links:
+ - karusic_db_service:db
+ read_only: false
+ mem_limit: 100m
+
+ karusic_back_service:
+ restart: always
+ image: gitea.atria-soft.org/kangaroo-and-rabbit/karusic:latest
+ depends_on:
+ - karusic_db_service
+ ports:
+ - 19080:18080
+ env_file:
+ - ./config.env
+ links:
+ - karusic_db_service:db
+ read_only: true
+ mem_limit: 1200m
+ healthcheck:
+ test: ["CMD", "wget" ,"http://localhost:18080/karusic/api/health_check", "-O", "/dev/null"]
+ timeout: 20s
+ retries: 3