[DEV] upgrade client and back to add basic api for logs
This commit is contained in:
parent
31af52dc9e
commit
95902e7312
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
|
167
back/src/org/kar/karanage/api/LogResource.java
Normal file
167
back/src/org/kar/karanage/api/LogResource.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
@ -148,8 +148,9 @@ public class StateResource {
|
||||
public Response post(
|
||||
@PathParam("group") String groupName,
|
||||
@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);
|
||||
|
||||
|
43
back/src/org/kar/karanage/model/DataLog.java
Normal file
43
back/src/org/kar/karanage/model/DataLog.java
Normal 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;
|
||||
}
|
@ -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;
|
@ -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
|
@ -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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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"])
|
@ -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)
|
||||
data = stateInterface.gets(topic=args.topic, since=args.since)
|
||||
print(f"Ret = {json.dumps(data, indent=4)}")
|
||||
|
||||
|
@ -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)}")
|
@ -1 +1 @@
|
||||
0.2.0-dev
|
||||
0.3.0-dev
|
@ -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
|
||||
|
75
client/python/karanage/karanage/connection.py
Normal file
75
client/python/karanage/karanage/connection.py
Normal 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
|
21
client/python/karanage/karanage/exception.py
Normal file
21
client/python/karanage/karanage/exception.py
Normal 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}'"
|
@ -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)
|
52
client/python/karanage/karanage/log.py
Normal file
52
client/python/karanage/karanage/log.py
Normal 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"))
|
||||
|
96
client/python/karanage/karanage/state.py
Normal file
96
client/python/karanage/karanage/state.py
Normal 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"))
|
||||
|
@ -57,3 +57,4 @@ setup(name='karanage',
|
||||
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
|
||||
# python3 -m build
|
||||
# python3 -m twine upload dist/*
|
||||
|
||||
|
@ -1 +1 @@
|
||||
0.2.0-dev
|
||||
0.3.0-dev
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user