Skip to content

Commit

Permalink
Make elasticlib C++ and Python libraries more idiomatic (#140)
Browse files Browse the repository at this point in the history
All:
* Rename the Notification class to Alert to match the user-facing
function
* Remove the Elastic prefix from class names since the namespace (C++),
outer class (Java), or package name (Python) already provides that
namespacing

C++:
* Flatten the type structure
* Put all classes and functions in an elastic namespace
* Since the Alert class provides setters and getters, just make the
members public to allow [aggregate
initialization](https://en.cppreference.com/w/cpp/language/aggregate_initialization)
* Remove redundant Javadoc tags from comments
* Rewrite the Javadoc-like comments to follow Doxygen conventions
* Make pixel counts use ints, since them being fractional makes no sense
* Move the JSON serialization and NT publishing to a .cpp file
* Use WPILib's bundled fmtlib instead of iostream for performance

Python:
* Flatten type structure
* Remove decorator functions since optional keyword arguments provides
the same functionality with the same reduction in verbosity as C++
* Rename the Notification class to Alert to match the user-facing
function
* Move JSON serialization into send_alert()

I confirmed the C++ version built within
https://github.com/wpilibsuite/allwpilib/tree/main/developerRobot.

Co-authored-by: Gold87 <[email protected]>
  • Loading branch information
calcmogul and Gold872 authored Dec 14, 2024
1 parent 5ec65e2 commit ee1faac
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 662 deletions.
54 changes: 27 additions & 27 deletions elasticlib/Elastic.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ public final class Elastic {
private static final ObjectMapper objectMapper = new ObjectMapper();

/**
* Sends an alert notification to the Elastic dashboard. The alert is serialized as a JSON string
* Sends an notification to the Elastic dashboard. The notification is serialized as a JSON string
* before being published.
*
* @param alert the {@link ElasticNotification} object containing alert details
* @param notification the {@link Notification} object containing notification details
*/
public static void sendAlert(ElasticNotification alert) {
public static void sendNotification(Notification notification) {
try {
publisher.set(objectMapper.writeValueAsString(alert));
publisher.set(objectMapper.writeValueAsString(notification));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}

/**
* Represents a notification object to be sent to the Elastic dashboard. This object holds
* Represents an notification object to be sent to the Elastic dashboard. This object holds
* properties such as level, title, description, display time, and dimensions to control how the
* alert is displayed on the dashboard.
* notification is displayed on the dashboard.
*/
public static class ElasticNotification {
public static class Notification {
@JsonProperty("level")
private NotificationLevel level;

Expand All @@ -59,17 +59,17 @@ public static class ElasticNotification {
private double height;

/**
* Creates a new ElasticNotification with all default parameters. This constructor is intended
* Creates a new Notification with all default parameters. This constructor is intended
* to be used with the chainable decorator methods
*
* <p>Title and description fields are empty.
*/
public ElasticNotification() {
public Notification() {
this(NotificationLevel.INFO, "", "");
}

/**
* Creates a new ElasticNotification with all properties specified.
* Creates a new Notification with all properties specified.
*
* @param level the level of the notification (e.g., INFO, WARNING, ERROR)
* @param title the title text of the notification
Expand All @@ -78,7 +78,7 @@ public ElasticNotification() {
* @param width the width of the notification display area
* @param height the height of the notification display area, inferred if below zero
*/
public ElasticNotification(
public Notification(
NotificationLevel level,
String title,
String description,
Expand All @@ -94,40 +94,40 @@ public ElasticNotification(
}

/**
* Creates a new ElasticNotification with default display time and dimensions.
* Creates a new Notification with default display time and dimensions.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
*/
public ElasticNotification(NotificationLevel level, String title, String description) {
public Notification(NotificationLevel level, String title, String description) {
this(level, title, description, 3000, 350, -1);
}

/**
* Creates a new ElasticNotification with a specified display time and default dimensions.
* Creates a new Notification with a specified display time and default dimensions.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
* @param displayTimeMillis the display time in milliseconds
*/
public ElasticNotification(
public Notification(
NotificationLevel level, String title, String description, int displayTimeMillis) {
this(level, title, description, displayTimeMillis, 350, -1);
}

/**
* Creates a new ElasticNotification with specified dimensions and default display time. If the
* height is below zero, it is automatically inferred based on screen size.
* Creates a new Notification with specified dimensions and default display time. If the height
* is below zero, it is automatically inferred based on screen size.
*
* @param level the level of the notification
* @param title the title text of the notification
* @param description the descriptive text of the notification
* @param width the width of the notification display area
* @param height the height of the notification display area, inferred if below zero
*/
public ElasticNotification(
public Notification(
NotificationLevel level, String title, String description, double width, double height) {
this(level, title, description, 3000, width, height);
}
Expand Down Expand Up @@ -250,7 +250,7 @@ public double getHeight() {
* @param level the level to set the notification to
* @return the current notification
*/
public ElasticNotification withLevel(NotificationLevel level) {
public Notification withLevel(NotificationLevel level) {
this.level = level;
return this;
}
Expand All @@ -261,7 +261,7 @@ public ElasticNotification withLevel(NotificationLevel level) {
* @param title the title to set the notification to
* @return the current notification
*/
public ElasticNotification withTitle(String title) {
public Notification withTitle(String title) {
setTitle(title);
return this;
}
Expand All @@ -272,7 +272,7 @@ public ElasticNotification withTitle(String title) {
* @param description the description to set the notification to
* @return the current notification
*/
public ElasticNotification withDescription(String description) {
public Notification withDescription(String description) {
setDescription(description);
return this;
}
Expand All @@ -283,7 +283,7 @@ public ElasticNotification withDescription(String description) {
* @param seconds the number of seconds to display the notification for
* @return the current notification
*/
public ElasticNotification withDisplaySeconds(double seconds) {
public Notification withDisplaySeconds(double seconds) {
return withDisplayMilliseconds((int) Math.round(seconds * 1000));
}

Expand All @@ -293,7 +293,7 @@ public ElasticNotification withDisplaySeconds(double seconds) {
* @param displayTimeMillis the number of milliseconds to display the notification for
* @return the current notification
*/
public ElasticNotification withDisplayMilliseconds(int displayTimeMillis) {
public Notification withDisplayMilliseconds(int displayTimeMillis) {
setDisplayTimeMillis(displayTimeMillis);
return this;
}
Expand All @@ -304,7 +304,7 @@ public ElasticNotification withDisplayMilliseconds(int displayTimeMillis) {
* @param width the width to set the notification to
* @return the current notification
*/
public ElasticNotification withWidth(double width) {
public Notification withWidth(double width) {
setWidth(width);
return this;
}
Expand All @@ -315,7 +315,7 @@ public ElasticNotification withWidth(double width) {
* @param height the height to set the notification to
* @return the current notification
*/
public ElasticNotification withHeight(double height) {
public Notification withHeight(double height) {
setHeight(height);
return this;
}
Expand All @@ -327,7 +327,7 @@ public ElasticNotification withHeight(double height) {
*
* @return the current notification
*/
public ElasticNotification withAutomaticHeight() {
public Notification withAutomaticHeight() {
setHeight(-1);
return this;
}
Expand All @@ -342,7 +342,7 @@ public ElasticNotification withAutomaticHeight() {
*
* @return the current notification
*/
public ElasticNotification withNoAutoDismiss() {
public Notification withNoAutoDismiss() {
setDisplayTimeMillis(0);
return this;
}
Expand Down
53 changes: 53 additions & 0 deletions elasticlib/elasticlib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2023-2024 Gold87 and other Elastic contributors
// This software can be modified and/or shared under the terms
// defined by the Elastic license:
// https://github.com/Gold872/elastic-dashboard/blob/main/LICENSE

#include "elasticlib.h"

#include <exception>

#include <fmt/core.h>
#include <networktables/NetworkTableInstance.h>
#include <networktables/StringTopic.h>
#include <wpi/json.h>

namespace elastic {

void SendNotification(const Notification& notification) {
static nt::StringTopic topic =
nt::NetworkTableInstance::GetDefault().GetStringTopic(
"/Elastic/RobotNotifications");
static nt::StringPublisher publisher =
topic.Publish({.sendAll = true, .keepDuplicates = true});

try {
// Convert Notification to JSON string
wpi::json jsonData;

if (notification.level == NotificationLevel::INFO) {
jsonData["level"] = "INFO";
} else if (notification.level == NotificationLevel::WARNING) {
jsonData["level"] = "WARNING";
} else if (notification.level == NotificationLevel::ERROR) {
jsonData["level"] = "ERROR";
} else {
jsonData["level"] = "UNKNOWN";
}

jsonData["title"] = notification.title;
jsonData["description"] = notification.description;
jsonData["displayTime"] = notification.displayTime.value();
jsonData["width"] = notification.width;
jsonData["height"] = notification.height;

// Publish the JSON string
publisher.Set(jsonData.dump());
} catch (const std::exception& e) {
fmt::println(stderr, "Error processing JSON: {}", e.what());
} catch (...) {
fmt::println(stderr, "Unknown error occurred while processing JSON.");
}
}

} // namespace elastic
Loading

0 comments on commit ee1faac

Please sign in to comment.