diff --git a/back/pom.xml b/back/pom.xml
index cc44aa8..8fd6380 100644
--- a/back/pom.xml
+++ b/back/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.kar
karanage
- 0.2.1
+ 0.2.2
3.1
@@ -22,7 +22,7 @@
kangaroo-and-rabbit
archidata
- 0.2.1
+ 0.2.4
diff --git a/back/src/org/kar/karanage/WebLauncher.java b/back/src/org/kar/karanage/WebLauncher.java
index d037560..19f7c3c 100755
--- a/back/src/org/kar/karanage/WebLauncher.java
+++ b/back/src/org/kar/karanage/WebLauncher.java
@@ -11,6 +11,7 @@ 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.LogResource;
import org.kar.karanage.api.StateHistoryResource;
import org.kar.karanage.api.StateResource;
import org.kar.karanage.api.UserResource;
@@ -25,8 +26,9 @@ 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.StateHistory;
+import org.kar.karanage.model.StateInstant;
+import org.kar.karanage.model.DataLog;
import org.kar.karanage.model.Group;
public class WebLauncher {
@@ -43,9 +45,10 @@ public class WebLauncher {
// generate the BDD:
try {
String out = "";
- out += SqlWrapper.createTable(DataInstant.class);
- out += SqlWrapper.createTable(DataHistory.class);
+ out += SqlWrapper.createTable(StateInstant.class);
+ out += SqlWrapper.createTable(StateHistory.class);
out += SqlWrapper.createTable(Group.class);
+ out += SqlWrapper.createTable(DataLog.class);
System.out.println(out);
} catch (Exception e) {
// TODO Auto-generated catch block
@@ -75,6 +78,7 @@ public class WebLauncher {
rc.registerClasses(UserResource.class);
rc.registerClasses(StateResource.class);
rc.registerClasses(StateHistoryResource.class);
+ rc.registerClasses(LogResource.class);
rc.registerClasses(HealthCheck.class);
rc.registerClasses(Front.class);
diff --git a/back/src/org/kar/karanage/api/LogResource.java b/back/src/org/kar/karanage/api/LogResource.java
new file mode 100644
index 0000000..50e6f13
--- /dev/null
+++ b/back/src/org/kar/karanage/api/LogResource.java
@@ -0,0 +1,167 @@
+package org.kar.karanage.api;
+
+import org.kar.archidata.SqlWrapper;
+import org.kar.archidata.WhereCondition;
+import org.kar.karanage.model.StateInstant;
+import org.kar.karanage.model.DataLog;
+import org.kar.karanage.model.StateHistory;
+import org.kar.karanage.model.Group;
+import javax.ws.rs.core.Response;
+
+
+import org.kar.archidata.annotation.security.PermitAll;
+import org.kar.archidata.exception.FailException;
+import org.kar.archidata.exception.InputException;
+
+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("/log")
+@Produces({MediaType.APPLICATION_JSON})
+public class LogResource {
+
+
+ @GET
+ @Path("{group}/{system}")
+ //@RolesAllowed("USER")
+ @PermitAll
+ public static String get(
+ @PathParam("group") String groupName,
+ @PathParam("system") String system,
+ @QueryParam("since") String since,
+ @QueryParam("sinceId") Integer sinceId,
+ @QueryParam("limit") Integer limit) throws Exception {
+ // Keep Group ID:
+ if (groupName == null || groupName.length() == 0) {
+ throw new InputException("group", "Missing URL parameter /state/{group}/...");
+ }
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
+ if (group == null) {
+ throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
+ }
+ if (system == null || system.length() == 0) {
+ throw new InputException("system", "Missing URL parameter /state/xxx/{system}/...");
+ }
+ if (limit == null || limit == 0) {
+ limit = 100;
+ }
+ if (limit > 100) {
+ limit = 100;
+ }
+ if (limit < 0) {
+ throw new InputException("limit", "Limit must be inside [1..100]");
+ }
+ if (since != null && sinceId != null) {
+ throw new InputException("since,sinceId", "The 2 parameters can not be set at the same time...");
+ }
+
+ List datas = null;
+ if (since != null) {
+ Timestamp time = null;
+ try {
+ time = Timestamp.from(Instant.parse(since));
+ } catch (Exception ex) {
+ throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
+ }
+ datas = SqlWrapper.getsWhere(DataLog.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("system", "=", system),
+ new WhereCondition("create_date", ">", time)
+ ),
+ "create_date",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "system has no new data or does not exist: '" + system + "'");
+ }
+ } else if (sinceId != null) {
+ datas = SqlWrapper.getsWhere(DataLog.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("system", "=", system),
+ new WhereCondition("id", ">", sinceId)
+ ),
+ "id",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "system has no new data or does not exist: '" + system + "'");
+ }
+ } else {
+ datas = SqlWrapper.getsWhere(DataLog.class,
+ List.of(
+ new WhereCondition("group", "=", group.id),
+ new WhereCondition("system", "=", system)
+ ),
+ "id",
+ true,
+ limit);
+ if (datas == null) {
+ throw new FailException(Response.Status.NOT_FOUND, "system does not exist: '" + system + "'");
+ }
+ }
+
+ StringBuilder out = new StringBuilder("[");
+ boolean first = true;
+ for (DataLog data : datas) {
+ if (first) {
+ first = false;
+ } else {
+ out.append(",");
+ }
+ out.append("{ \"id\": " + data.id + ", \"time\": \"" + data.create_date.toInstant().toString() + "\", \"data\":" + data.data + "}");
+ }
+ out.append("]");
+ return out.toString();
+ }
+
+ @POST
+ @Path("{group}/{system}")
+ @PermitAll
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response post(
+ @PathParam("group") String groupName,
+ @PathParam("system") String system,
+ @QueryParam("time") String time,
+ @QueryParam("id") Integer client_id,
+ String dataToInsert) throws Exception {
+ Group group = SqlWrapper.getWhere(Group.class,
+ List.of(
+ new WhereCondition("name", "=", groupName)
+ ),
+ false);
+ if (group == null) {
+ throw new InputException("group", "url: /log/{group}/... ==> Unknown group name");
+ }
+ DataLog data = new DataLog();
+ data.group = group.id;
+ data.system = system;
+ data.data = dataToInsert;
+ if (client_id != null) {
+ data.client_id = client_id;
+ }
+ if (time != null) {
+ try {
+ data.create_date = Timestamp.from(Instant.parse(time));
+ } catch (Exception ex) {
+ throw new InputException("time", "url: ?time=... ==> is not an iso 8601 time format");
+ }
+ }
+ SqlWrapper.insert(data);
+ return Response.status(201).build();
+ }
+
+}
+
diff --git a/back/src/org/kar/karanage/api/StateHistoryResource.java b/back/src/org/kar/karanage/api/StateHistoryResource.java
index 106662c..753cfeb 100644
--- a/back/src/org/kar/karanage/api/StateHistoryResource.java
+++ b/back/src/org/kar/karanage/api/StateHistoryResource.java
@@ -2,8 +2,8 @@ package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
-import org.kar.karanage.model.DataInstant;
-import org.kar.karanage.model.DataHistory;
+import org.kar.karanage.model.StateInstant;
+import org.kar.karanage.model.StateHistory;
import org.kar.karanage.model.Group;
import javax.ws.rs.core.Response;
@@ -64,7 +64,7 @@ public class StateHistoryResource {
throw new InputException("since,sinceId", "The 2 parameters can not be set at the same time...");
}
- List datas = null;
+ List datas = null;
if (since != null) {
Timestamp time = null;
try {
@@ -72,7 +72,7 @@ public class StateHistoryResource {
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
- datas = SqlWrapper.getsWhere(DataHistory.class,
+ datas = SqlWrapper.getsWhere(StateHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
@@ -85,7 +85,7 @@ public class StateHistoryResource {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else if (sinceId != null) {
- datas = SqlWrapper.getsWhere(DataHistory.class,
+ datas = SqlWrapper.getsWhere(StateHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
@@ -98,7 +98,7 @@ public class StateHistoryResource {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else {
- datas = SqlWrapper.getsWhere(DataHistory.class,
+ datas = SqlWrapper.getsWhere(StateHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
@@ -113,7 +113,7 @@ public class StateHistoryResource {
StringBuilder out = new StringBuilder("[");
boolean first = true;
- for (DataInstant data : datas) {
+ for (StateInstant data : datas) {
if (first) {
first = false;
} else {
diff --git a/back/src/org/kar/karanage/api/StateResource.java b/back/src/org/kar/karanage/api/StateResource.java
index 0b7c23e..b7bf45c 100644
--- a/back/src/org/kar/karanage/api/StateResource.java
+++ b/back/src/org/kar/karanage/api/StateResource.java
@@ -2,8 +2,8 @@ package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
-import org.kar.karanage.model.DataInstant;
-import org.kar.karanage.model.DataHistory;
+import org.kar.karanage.model.StateInstant;
+import org.kar.karanage.model.StateHistory;
import org.kar.karanage.model.Group;
import javax.ws.rs.core.Response;
@@ -45,7 +45,7 @@ public class StateResource {
if (group == null) {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
- DataInstant data = null;
+ StateInstant data = null;
if (since != null) {
Timestamp time = null;
try {
@@ -53,7 +53,7 @@ public class StateResource {
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
- data = SqlWrapper.getWhere(DataInstant.class,
+ data = SqlWrapper.getWhere(StateInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
@@ -64,7 +64,7 @@ public class StateResource {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else {
- data = SqlWrapper.getWhere(DataInstant.class,
+ data = SqlWrapper.getWhere(StateInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
@@ -96,7 +96,7 @@ public class StateResource {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
- List datas = null;
+ List datas = null;
if (since != null) {
Timestamp time = null;
try {
@@ -104,14 +104,14 @@ public class StateResource {
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
- datas = SqlWrapper.getsWhere(DataInstant.class,
+ datas = SqlWrapper.getsWhere(StateInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("modify_date", ">", time)
),
true);
} else {
- datas = SqlWrapper.getsWhere(DataInstant.class,
+ datas = SqlWrapper.getsWhere(StateInstant.class,
List.of(
new WhereCondition("group", "=", group.id)
),
@@ -119,7 +119,7 @@ public class StateResource {
}
StringBuilder out = new StringBuilder("[");
boolean first = true;
- for (DataInstant data : datas) {
+ for (StateInstant data : datas) {
if (first) {
first = false;
} else {
@@ -147,9 +147,10 @@ public class StateResource {
@Consumes(MediaType.APPLICATION_JSON)
public Response post(
@PathParam("group") String groupName,
- @PathParam("topic") String topic,
+ @PathParam("topic") String topic,
+ @QueryParam("state") String state,
String dataToInsert) throws Exception {
- DataInstant previous = null;
+ StateInstant previous = null;
Group group = SqlWrapper.getWhere(Group.class,
List.of(
@@ -160,7 +161,7 @@ public class StateResource {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
if (group != null) {
- previous = SqlWrapper.getWhere(DataInstant.class,
+ previous = SqlWrapper.getWhere(StateInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
@@ -169,12 +170,13 @@ public class StateResource {
}
if (previous == null) {
// insert new data
- DataInstant data = new DataInstant();
+ StateInstant data = new StateInstant();
data.group = group.id;
data.topic = topic;
data.data = dataToInsert;
+ data.state = state;
previous = SqlWrapper.insert(data);
- DataHistory dataHistory = new DataHistory(previous);
+ StateHistory dataHistory = new StateHistory(previous);
dataHistory.year = true;
dataHistory.month = true;
dataHistory.week = true;
@@ -185,9 +187,10 @@ public class StateResource {
// update Data
try {
previous.data = dataToInsert;
- SqlWrapper.update(previous, previous.id, List.of("data"));
+ previous.state = state;
+ SqlWrapper.update(previous, previous.id, List.of("data", "state"));
// add it in history:
- DataHistory dataHistory = new DataHistory(previous);
+ StateHistory dataHistory = new StateHistory(previous);
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC);
diff --git a/back/src/org/kar/karanage/model/DataLog.java b/back/src/org/kar/karanage/model/DataLog.java
new file mode 100644
index 0000000..b5e2241
--- /dev/null
+++ b/back/src/org/kar/karanage/model/DataLog.java
@@ -0,0 +1,43 @@
+package org.kar.karanage.model;
+
+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;
+
+@SQLTableName ("log")
+@SQLIfNotExists
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class DataLog {
+ @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;
+ @SQLUpdateTime
+ @SQLNotNull
+ @SQLDefault("now(3)")
+ @SQLComment("When update the object")
+ public Timestamp create_date = null;
+ @SQLComment("Group of the element")
+ @SQLForeignKey("group")
+ public long group;
+ @SQLLimitSize(256)
+ @SQLComment("System of the message")
+ public String system = null;
+ @SQLComment("Client unique internal ID (for synchronisation system)")
+ public Integer client_id = null;
+ @SQLComment("Message to store")
+ public String data = null;
+}
\ No newline at end of file
diff --git a/back/src/org/kar/karanage/model/DataHistory.java b/back/src/org/kar/karanage/model/StateHistory.java
similarity index 93%
rename from back/src/org/kar/karanage/model/DataHistory.java
rename to back/src/org/kar/karanage/model/StateHistory.java
index 64a364c..f3f5d0f 100644
--- a/back/src/org/kar/karanage/model/DataHistory.java
+++ b/back/src/org/kar/karanage/model/StateHistory.java
@@ -36,15 +36,15 @@ enum TypeData {
NUMBER, BOOLEAN, JSON, STRING
}
-@SQLTableName ("dataHistory")
+@SQLTableName ("stateHistory")
@SQLIfNotExists
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
-public class DataHistory extends DataInstant {
+public class StateHistory extends StateInstant {
// default constructor
- public DataHistory() {
+ public StateHistory() {
}
- public DataHistory(DataInstant other) {
+ public StateHistory(StateInstant other) {
this.group = other.group;
this.topic = other.topic;
this.state = other.state;
diff --git a/back/src/org/kar/karanage/model/DataInstant.java b/back/src/org/kar/karanage/model/StateInstant.java
similarity index 97%
rename from back/src/org/kar/karanage/model/DataInstant.java
rename to back/src/org/kar/karanage/model/StateInstant.java
index 98cbb2b..cd2dc35 100644
--- a/back/src/org/kar/karanage/model/DataInstant.java
+++ b/back/src/org/kar/karanage/model/StateInstant.java
@@ -27,10 +27,10 @@ import org.kar.archidata.annotation.SQLUpdateTime;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-@SQLTableName ("data")
+@SQLTableName ("state")
@SQLIfNotExists
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
-public class DataInstant {
+public class StateInstant {
@SQLAutoIncrement // Add AUTO_INCREMENT modifier
@SQLPrimaryKey // Create a PRIMARY KEY based on this field
@SQLNotNull
diff --git a/client/python/karanage-tools/bin/karanage-system b/client/python/karanage-tools/bin/karanage-system
index 8777de1..fc25251 100755
--- a/client/python/karanage-tools/bin/karanage-system
+++ b/client/python/karanage-tools/bin/karanage-system
@@ -7,7 +7,7 @@ import subprocess
import json
from pathlib import Path
from typing import Dict, List
-import karanage
+from karanage import KaranageState, KaranageConnection, KaranageException, StateSystem
cpu_core_count = psutil.cpu_count(logical=False)
cpu_thread_count = psutil.cpu_count()
@@ -122,12 +122,12 @@ if __name__ == '__main__':
# Load arguments:
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", type=str, default="/etc/karanage/system.json", help="json configuration file")
- parser.add_argument("-C", "--connection", type=str, default="/etc/karanage/connection.json", help="json configuration file")
+ parser.add_argument("-C", "--connection", type=str, default=None, help="json configuration file")
# This element are read from the connection file:
- parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api", 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", "--token", type=str, default="", help="Token to access to the server")
+ parser.add_argument("-u", "--url", type=str, default=None, help="Base URL of the web service")
+ parser.add_argument("-g", "--group", type=str, default=None, help="Group the the message")
+ parser.add_argument("-T", "--token", type=str, default=None, help="Token to access to the server")
# This element are read from the configuration file:
parser.add_argument("-t", "--topic", type=str, default="PC/system", help="Topic of the message")
@@ -158,26 +158,15 @@ if __name__ == '__main__':
if "topic" not in configuration["config"]:
configuration["config"]["topic"] = args.topic
+ connection = KaranageConnection(
+ url = args.url,
+ group = args.group,
+ token = args.token,
+ config_file = args.connection
+ )
- if Path(args.connection).exists():
- f = open(args.connection, "r")
- connection = json.loads(f.read())
- f.close()
- else:
- connection = {}
- # manage the connection model
- if "url" not in connection:
- connection["url"] = args.url
- if "group" not in connection:
- connection["group"] = args.group
- if "token" not in connection:
- connection["token"] = args.token
-
# create the rest interface of karanage
- restInterface = karanage.KaranageREST(
- connection["url"],
- connection["group"],
- connection["token"])
+ stateInterface = KaranageState(connection)
while True:
out = {}
@@ -205,7 +194,7 @@ if __name__ == '__main__':
print(json.dumps(out, indent=4))
# send message to the server:
try:
- restInterface.send_state_to_server(configuration["config"]["topic"], out)
- except karanage.KarangeException as ex:
+ stateInterface.send(configuration["config"]["topic"], out, state = StateSystem.OK)
+ except KaranageException as ex:
print(f"Can not send to the server: {ex}")
- time.sleep(configuration["config"]["sleep"])
\ No newline at end of file
+ time.sleep(configuration["config"]["sleep"])
diff --git a/client/python/karanage-tools/bin/karanage-tools-state-get b/client/python/karanage-tools/bin/karanage-tools-state-get
index 37dc424..850df34 100755
--- a/client/python/karanage-tools/bin/karanage-tools-state-get
+++ b/client/python/karanage-tools/bin/karanage-tools-state-get
@@ -7,45 +7,33 @@ import subprocess
import json
from pathlib import Path
from typing import Dict, List
-import karanage
+from karanage import KaranageException, KaranageConnection, KaranageState
+
if __name__ == '__main__':
# Load arguments:
parser = argparse.ArgumentParser()
- parser.add_argument("-C", "--connection", type=str, default="/etc/karanage/connection.json", help="json configuration file")
- parser.add_argument("-t", "--topic", type=str, default="", help="Topic of the message")
+ parser.add_argument("-C", "--connection", type=str, default=None, help="json configuration file")
+ parser.add_argument("-t", "--topic", type=str, default=None, help="Topic of the message")
parser.add_argument("-s", "--since", type=str, default=None, help="Iso date since the value time must be")
# This element are read from the connection file:
- parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api", 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", "--token", type=str, default="", help="Token to access to the server")
+ parser.add_argument("-u", "--url", type=str, default=None, help="Base URL of the web service")
+ parser.add_argument("-g", "--group", type=str, default=None, help="Group the the message")
+ parser.add_argument("-T", "--token", type=str, default=None, help="Token to access to the server")
args = parser.parse_args()
- if Path(args.connection).exists():
- f = open(args.connection, "r")
- connection = json.loads(f.read())
- f.close()
- else:
- connection = {}
- # manage the connection model
- if "url" not in connection:
- connection["url"] = args.url
- if "group" not in connection:
- connection["group"] = args.group
- if "token" not in connection:
- connection["token"] = args.token
+ connection = KaranageConnection(
+ url = args.url,
+ group = args.group,
+ token = args.token,
+ config_file = args.connection
+ )
# create the rest interface of karanage
- restInterface = karanage.KaranageREST(
- connection["url"],
- connection["group"],
- connection["token"])
+ stateInterface = KaranageState(connection)
- if args.topic == "":
- data = restInterface.get_state_all(since=args.since)
- print(f"Ret = {json.dumps(data, indent=4)}")
- else:
- data = restInterface.get_state_topic(args.topic, since=args.since)
- print(f"Ret = {json.dumps(data, indent=4)}")
\ No newline at end of file
+ data = stateInterface.gets(topic=args.topic, since=args.since)
+ print(f"Ret = {json.dumps(data, indent=4)}")
+
diff --git a/client/python/karanage-tools/bin/karanage-tools-state-history-get b/client/python/karanage-tools/bin/karanage-tools-state-history-get
index c7411ab..adebff9 100755
--- a/client/python/karanage-tools/bin/karanage-tools-state-history-get
+++ b/client/python/karanage-tools/bin/karanage-tools-state-history-get
@@ -7,46 +7,36 @@ import subprocess
import json
from pathlib import Path
from typing import Dict, List
-import karanage
+from karanage import KaranageConnection, KaranageState, KaranageState
if __name__ == '__main__':
# Load arguments:
parser = argparse.ArgumentParser()
- parser.add_argument("-C", "--connection", type=str, default="/etc/karanage/connection.json", help="json configuration file")
- parser.add_argument("-t", "--topic", type=str, default="", help="Topic of the message")
+ parser.add_argument("-C", "--connection", type=str, default=None, help="json configuration file")
+ parser.add_argument("-t", "--topic", type=str, default=None, help="Topic of the message")
parser.add_argument("-s", "--since", type=str, default=None, help="Iso date since the value time must be")
parser.add_argument("-S", "--since-id", type=str, default=None, help="Remote BDD id to start request")
parser.add_argument("-l", "--limit", type=int, default=100, help="Limit the number of request")
# This element are read from the connection file:
- parser.add_argument("-u", "--url", type=str, default="http://localhost:20080/karanage/api", 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", "--token", type=str, default="", help="Token to access to the server")
+ parser.add_argument("-u", "--url", type=str, default=None, help="Base URL of the web service")
+ parser.add_argument("-g", "--group", type=str, default=None, help="Group the the message")
+ parser.add_argument("-T", "--token", type=str, default=None, help="Token to access to the server")
args = parser.parse_args()
- if Path(args.connection).exists():
- f = open(args.connection, "r")
- connection = json.loads(f.read())
- f.close()
- else:
- connection = {}
- # manage the connection model
- if "url" not in connection:
- connection["url"] = args.url
- if "group" not in connection:
- connection["group"] = args.group
- if "token" not in connection:
- connection["token"] = args.token
-
+ connection = KaranageConnection(
+ url = args.url,
+ group = args.group,
+ token = args.token,
+ config_file = args.connection
+ )
+
# create the rest interface of karanage
- restInterface = karanage.KaranageREST(
- connection["url"],
- connection["group"],
- connection["token"])
+ stateInterface = KaranageState(connection)
- if args.topic == "":
+ if args.topic is None:
print("Missing TOPIC ...")
else:
- data = restInterface.get_state_history_topic(args.topic, since=args.since, since_id=args.since_id, limit=args.limit)
+ data = stateInterface.get_history(topic=args.topic, since=args.since, since_id=args.since_id, limit=args.limit)
print(f"Ret = {json.dumps(data, indent=4)}")
\ No newline at end of file
diff --git a/client/python/karanage-tools/version.txt b/client/python/karanage-tools/version.txt
index b4f09dd..0ba2319 100644
--- a/client/python/karanage-tools/version.txt
+++ b/client/python/karanage-tools/version.txt
@@ -1 +1 @@
-0.2.0-dev
\ No newline at end of file
+0.3.0-dev
\ No newline at end of file
diff --git a/client/python/karanage/karanage/__init__.py b/client/python/karanage/karanage/__init__.py
index 35cc386..4bac672 100755
--- a/client/python/karanage/karanage/__init__.py
+++ b/client/python/karanage/karanage/__init__.py
@@ -7,4 +7,7 @@
##
## @license MPL v2.0 (see license file)
##
-from .interface import StateSystem, KaranageREST, KarangeSendError, KarangeException
+from .exception import KaranageException
+from .connection import KaranageConnection
+from .state import StateSystem, KaranageState
+from .log import KaranageLog
diff --git a/client/python/karanage/karanage/connection.py b/client/python/karanage/karanage/connection.py
new file mode 100644
index 0000000..49131fb
--- /dev/null
+++ b/client/python/karanage/karanage/connection.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+##
+## @author Edouard DUPIN
+##
+## @copyright 2023, Edouard DUPIN, all right reserved
+##
+## @license MPL v2.0 (see license file)
+##
+import enum
+import requests
+import json
+from typing import Dict, Optional
+from pathlib import Path
+
+
+class KaranageConnection:
+ def __init__(self,
+ url: Optional[str] = None,
+ group: Optional[str] = None,
+ token: Optional[str] = None,
+ config_file: Optional[str] = None,
+ default_values: Optional[str] = None) -> None:
+ """
+ @brief Initialize the communication class.
+ @param[in] url URL of the karanage API server.
+ @param[in] group Group of the message (token need to have the autorisation to pubhied on it).
+ @param[in] token Token to validate the access on the application.
+ @param[in] config_file path to the configuration file if overload.
+ @param[in] default_values Default configurations.
+ """
+ self.url = "http://localhost:20080/karanage/api"
+ self.group = "test"
+ self.token = None
+ # load user default value:
+ if default_values is not None:
+ if "url" in default_values:
+ self.url = default_values["url"]
+ if "group" in default_values:
+ self.group = default_values["group"]
+ if "token" in default_values:
+ self.token = default_values["token"]
+ # keep correct config file:
+ if config_file is None:
+ config_file = "/etc/karanage/connection.json"
+ # check if the config exist:
+ if Path(config_file).exists():
+ f = open(config_file, "r")
+ configuaration = json.loads(f.read())
+ f.close()
+ else:
+ configuaration = {}
+ # Update data with config file:
+ if "url" in configuaration:
+ self.url = configuaration["url"]
+ if "group" in configuaration:
+ self.group = configuaration["group"]
+ if "token" in configuaration:
+ self.token = configuaration["token"]
+ # set user command - line configuration:
+ if url is not None:
+ self.url = url
+ if group is not None:
+ self.group = group
+ if token is not None:
+ self.token = token
+
+ def get_url(self, service: str):
+ return f"{self.url}/{service}/{self.group}"
+
+ def get_header(self):
+ header = {}
+ if self.token is not None and len(self.token) >15:
+ header['Authorization'] = f"zota {self.token}"
+ return header
\ No newline at end of file
diff --git a/client/python/karanage/karanage/exception.py b/client/python/karanage/karanage/exception.py
new file mode 100644
index 0000000..e0693f2
--- /dev/null
+++ b/client/python/karanage/karanage/exception.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+##
+## @author Edouard DUPIN
+##
+## @copyright 2023, Edouard DUPIN, all right reserved
+##
+## @license MPL v2.0 (see license file)
+##
+
+class KaranageException(Exception):
+ def __init__(self, message, error_id, error_message):
+ # Call the base class constructor with the parameters it needs
+ super().__init__(message)
+
+ # Now for your custom code...
+ self.error_id = error_id
+ self.error_message = error_message
+
+ def __str__(self):
+ return f"{Exception.__str__(self)} Status={self.error_id} message='{self.error_message}'"
diff --git a/client/python/karanage/karanage/interface.py b/client/python/karanage/karanage/interface.py
deleted file mode 100644
index 928a42b..0000000
--- a/client/python/karanage/karanage/interface.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/python3
-# -*- coding: utf-8 -*-
-##
-## @author Edouard DUPIN
-##
-## @copyright 2023, Edouard DUPIN, all right reserved
-##
-## @license MPL v2.0 (see license file)
-##
-import enum
-import requests
-import json
-from typing import Dict, Optional
-
-class KarangeSendError(Exception):
- def __init__(self, message, error_id, error_message):
- # Call the base class constructor with the parameters it needs
- super().__init__(message)
-
- # Now for your custom code...
- self.error_id = error_id
- self.error_message = error_message
-
- def __str__(self):
- return f"{Exception.__str__(self)} Status={self.error_id} message='{self.error_message}'"
-
-class KarangeException(KarangeSendError):
- def __init__(self, message, error_id, error_message):
- # Call the base class constructor with the parameters it needs
- super().__init__(message, error_id, error_message )
-
-
-
-class StateSystem(enum.Enum):
- OK = "OK"
- FAIL = "FAIL"
- DOWN = "DOWN"
-
-
-
-## Generic karanage sending system.
-class KaranageREST:
- def __init__(self, url: str, group: str, token: str) -> None:
- """
- @brief Initialize the communication class.
- @param[in] url URL of the karanage API server.
- @param[in] group Group of the message (token need to have the autorisation to pubhied on it).
- @param[in] token Token to validate the access on the application.
- """
- self.url = url
- self.group = group
- self.token = token
-
- def get_url(self, service: str, topic: Optional[str] = None):
- if topic is None:
- return f"{self.url}/{service}/{self.group}"
- return f"{self.url}/{service}/{self.group}/{topic}"
-
- def send_state_to_server(self, topic: str, data: Optional[Dict], state: StateSystem = StateSystem.OK) -> None:
- """
- @brief Send a message to the server.
- @param[in] topic Topic where to publish the data.
- @param[in] data: Data to send to the server
- @param[in] state: State of the current system
- """
- if data is None:
- data = {}
- param = {
- "state": state,
- }
- header = {}
- if self.token is not None and len(self.token) >15:
- header['Authorization'] = f"zota {self.token}"
- try:
- ret = requests.post(self.get_url("state", topic), json=data, headers=header, params=param)
- except requests.exceptions.ConnectionError as ex:
- raise KarangeException(f"Fail connect server: {self.get_url('state', topic)}", 0, str(ex))
- if 200 <= ret.status_code <= 299:
- pass
- else:
- raise KarangeException(f"Fail send message: {self.get_url('state', topic)}", ret.status_code, ret.content.decode("utf-8"))
-
- def get_state_all(self, since: Optional[str] = None) -> Dict:
- """
- @brief Get all the topic fom the server.
- @param since ISO1866 time value.
- @return A dictionnary with the requested data.
- """
- param = { }
- header = { }
- if self.token is not None and len(self.token) >15:
- header['Authorization'] = f"zota {self.token}"
- if since is not None:
- param["since"] = since
- ret = requests.get(self.get_url("state"), headers=header, params=param)
- if 200 == ret.status_code:
- return json.loads(ret.content.decode('utf-8'))
- raise KarangeException(f"Fail get data: {self.get_url('state')}", ret.status_code, ret.content.decode("utf-8"))
-
- def get_state_topic(self, topic: str, since: Optional[str] = None) -> Dict:
- """
- @brief Get all the topic fom the server.
- @param since ISO1866 time value.
- @return A dictionnary with the requested data.
- """
- param = { }
- header = { }
- if self.token is not None and len(self.token) >15:
- header['Authorization'] = f"zota {self.token}"
- if since is not None:
- param["since"] = since
- ret = requests.get(self.get_url("state", topic), headers=header, params=param)
- #print(ret.content.decode('utf-8'))
- if 200 == ret.status_code:
- return json.loads(ret.content.decode('utf-8'))
- raise KarangeException(f"Fail get data: {self.get_url('state', topic)}", ret.status_code, ret.content.decode("utf-8"))
-
- def get_state_history_topic(self, topic: str, since: Optional[str] = None, since_id: Optional[int] = None, limit: Optional[int] = None) -> Dict:
- """
- @brief Get all the topic fom the server.
- @param since ISO1866 time value.
- @param since_id remote BDD index of tje fielf.
- @param limit Number of value we want to get
- @return A dictionnary with the requested data.
- """
- param = { }
- header = { }
- if self.token is not None and len(self.token) >15:
- header['Authorization'] = f"zota {self.token}"
- if since is not None:
- param["since"] = since
- if since_id is not None:
- param["sinceId"] = since_id
- if limit is not None:
- param["limit"] = limit
- ret = requests.get(self.get_url("state_history", topic), headers=header, params=param)
- #print(ret.content.decode('utf-8'))
- if 200 == ret.status_code:
- return json.loads(ret.content.decode('utf-8'))
- raise KarangeException(f"Fail get data: {self.get_url('state_history', topic)}", ret.status_code, ret.content.decode("utf-8"))
-
-
- def get_all(self) -> Dict:
- """Deprecated"""
- return self.get_state_all()
- def get_topic(self, topic: str) -> Dict:
- """Deprecated"""
- return self.get_state_topic(topic)
- def send_to_server(self, topic: str, data: Optional[Dict], state: StateSystem = StateSystem.OK) -> None:
- """Deprecated"""
- return self.send_state_to_server(topic, data, state)
\ No newline at end of file
diff --git a/client/python/karanage/karanage/log.py b/client/python/karanage/karanage/log.py
new file mode 100644
index 0000000..0bdac83
--- /dev/null
+++ b/client/python/karanage/karanage/log.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+##
+## @author Edouard DUPIN
+##
+## @copyright 2023, Edouard DUPIN, all right reserved
+##
+## @license MPL v2.0 (see license file)
+##
+import enum
+import requests
+import json
+from typing import Dict, Optional
+from .connection import KaranageConnection
+from .exception import KaranageException
+
+## Generic karanage sending system.
+class KaranageLog:
+ def __init__(self, connection: KaranageConnection, system: Optional[str] = None) -> None:
+ """
+ @brief Initialize the communication class.
+ @param[in] connection Connection interface.
+ """
+ self.connection = connection
+ self.system = system
+ self.service = "log"
+
+ def get_url(self):
+ if self.system is None:
+ return self.connection.get_url(self.service)
+ return f"{self.connection.get_url(self.service)}/{self.system}"
+
+ def send(self, system: str, data: Dict, id: int = None) -> None:
+ """
+ @brief Send a message to the server.
+ @param[in] system system where to publish the data.
+ @param[in] data: Data to send to the server
+ @param[in] id: Local internal ID
+ """
+ param = {}
+ if id is not None:
+ param["id"] = id
+ header = self.connection.get_header()
+ try:
+ ret = requests.post(self.get_url(), json=data, headers=header, params=param)
+ except requests.exceptions.ConnectionError as ex:
+ raise KaranageException(f"Fail connect server: {self.get_url('state', system)}", 0, str(ex))
+ if 200 <= ret.status_code <= 299:
+ pass
+ else:
+ raise KaranageException(f"Fail send message: {self.get_url('state', system)}", ret.status_code, ret.content.decode("utf-8"))
+
\ No newline at end of file
diff --git a/client/python/karanage/karanage/state.py b/client/python/karanage/karanage/state.py
new file mode 100644
index 0000000..aa5b767
--- /dev/null
+++ b/client/python/karanage/karanage/state.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+##
+## @author Edouard DUPIN
+##
+## @copyright 2023, Edouard DUPIN, all right reserved
+##
+## @license MPL v2.0 (see license file)
+##
+import enum
+import requests
+import json
+from typing import Dict, Optional
+from .connection import KaranageConnection
+from .exception import KaranageException
+
+class StateSystem(enum.Enum):
+ OK = "OK"
+ FAIL = "FAIL"
+ DOWN = "DOWN"
+
+## Generic karanage sending system.
+class KaranageState:
+ def __init__(self, connection: KaranageConnection) -> None:
+ """
+ @brief Initialize the communication class.
+ @param[in] connection Connection interface.
+ """
+ self.connection = connection
+
+ def get_url(self, service: str, topic: Optional[str] = None):
+ if topic is None:
+ return self.connection.get_url(service)
+ return f"{self.connection.get_url(service)}/{topic}"
+
+ def send(self, topic: str, data: Optional[Dict], state: StateSystem = StateSystem.OK) -> None:
+ """
+ @brief Send a message to the server.
+ @param[in] topic Topic where to publish the data.
+ @param[in] data: Data to send to the server
+ @param[in] state: State of the current system
+ """
+ if data is None:
+ data = {}
+ param = {}
+ if state is not None:
+ param["state"] = state
+ header = self.connection.get_header()
+ try:
+ ret = requests.post(self.get_url("state", topic), json=data, headers=header, params=param)
+ except requests.exceptions.ConnectionError as ex:
+ raise KaranageException(f"Fail connect server: {self.get_url('state', topic)}", 0, str(ex))
+ if 200 <= ret.status_code <= 299:
+ pass
+ else:
+ raise KaranageException(f"Fail send message: {self.get_url('state', topic)}", ret.status_code, ret.content.decode("utf-8"))
+
+
+ def gets(self, topic: Optional[str] = None, since: Optional[str] = None) -> Dict:
+ """
+ @brief Get all the topic fom the server.
+ @param since ISO1866 time value.
+ @return A dictionnary with the requested data.
+ """
+ param = { }
+ header = self.connection.get_header()
+ if since is not None:
+ param["since"] = since
+ ret = requests.get(self.get_url("state", topic), headers=header, params=param)
+ #print(ret.content.decode('utf-8'))
+ if 200 == ret.status_code:
+ return json.loads(ret.content.decode('utf-8'))
+ raise KaranageException(f"Fail get data: {self.get_url('state', topic)}", ret.status_code, ret.content.decode("utf-8"))
+
+ def get_history(self, topic: Optional[str] = None, since: Optional[str] = None, since_id: Optional[int] = None, limit: Optional[int] = None) -> Dict:
+ """
+ @brief Get all the topic fom the server.
+ @param since ISO1866 time value.
+ @param since_id remote BDD index of tje fielf.
+ @param limit Number of value we want to get
+ @return A dictionnary with the requested data.
+ """
+ param = { }
+ header = self.connection.get_header()
+ if since is not None:
+ param["since"] = since
+ if since_id is not None:
+ param["sinceId"] = since_id
+ if limit is not None:
+ param["limit"] = limit
+ ret = requests.get(self.get_url("state_history", topic), headers=header, params=param)
+ #print(ret.content.decode('utf-8'))
+ if 200 == ret.status_code:
+ return json.loads(ret.content.decode('utf-8'))
+ raise KaranageException(f"Fail get data: {self.get_url('state_history', topic)}", ret.status_code, ret.content.decode("utf-8"))
+
diff --git a/client/python/karanage/setup.py b/client/python/karanage/setup.py
index 9b31ae6..be27b29 100755
--- a/client/python/karanage/setup.py
+++ b/client/python/karanage/setup.py
@@ -56,4 +56,5 @@ setup(name='karanage',
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
# python3 -m build
-# python3 -m twine upload dist/*
\ No newline at end of file
+# python3 -m twine upload dist/*
+
diff --git a/client/python/karanage/version.txt b/client/python/karanage/version.txt
index b4f09dd..0ba2319 100644
--- a/client/python/karanage/version.txt
+++ b/client/python/karanage/version.txt
@@ -1 +1 @@
-0.2.0-dev
\ No newline at end of file
+0.3.0-dev
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 405599c..921f2f0 100644
--- a/readme.md
+++ b/readme.md
@@ -48,11 +48,10 @@ docker-compose up -d
build the local image:
+docker login gitea.atria-soft.org
+
docker pull archlinux:base-devel
docker pull bellsoft/liberica-openjdk-alpine:latest
docker build -t gitea.atria-soft.org/kangaroo-and-rabbit/karanage:latest .
-
-docker login gitea.atria-soft.org
-
docker push gitea.atria-soft.org/kangaroo-and-rabbit/karanage:latest