[DEV] upgrade client and back to add basic api for logs

This commit is contained in:
Edouard DUPIN 2023-01-13 00:36:47 +01:00
parent 31af52dc9e
commit 95902e7312
21 changed files with 554 additions and 274 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<artifactId>karanage</artifactId>
<version>0.2.1</version>
<version>0.2.2</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
@ -22,7 +22,7 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.2.1</version>
<version>0.2.4</version>
</dependency>
</dependencies>

View File

@ -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);

View File

@ -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<DataLog> 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();
}
}

View File

@ -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<DataHistory> datas = null;
List<StateHistory> 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 {

View File

@ -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<DataInstant> datas = null;
List<StateInstant> 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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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"])
time.sleep(configuration["config"]["sleep"])

View File

@ -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)}")
data = stateInterface.gets(topic=args.topic, since=args.since)
print(f"Ret = {json.dumps(data, indent=4)}")

View File

@ -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)}")

View File

@ -1 +1 @@
0.2.0-dev
0.3.0-dev

View File

@ -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

View File

@ -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

View File

@ -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}'"

View File

@ -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)

View File

@ -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"))

View File

@ -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"))

View File

@ -56,4 +56,5 @@ setup(name='karanage',
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
# python3 -m build
# python3 -m twine upload dist/*
# python3 -m twine upload dist/*

View File

@ -1 +1 @@
0.2.0-dev
0.3.0-dev

View File

@ -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