Added support for Glances API and completly reworked API
This commit is contained in:
@ -1,352 +1,32 @@
|
||||
package de.svenkubiak.jpushover;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import de.svenkubiak.jpushover.enums.Constants;
|
||||
import de.svenkubiak.jpushover.enums.Priority;
|
||||
import de.svenkubiak.jpushover.enums.Sound;
|
||||
import de.svenkubiak.jpushover.apis.Glance;
|
||||
import de.svenkubiak.jpushover.apis.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
* Zero-dependency convenient class for sending messages to Pushover
|
||||
* Zero-dependency convenient class for working with the Pushover API
|
||||
* See https://pushover.net/api for API details
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class JPushover {
|
||||
private static final int HTTP_OK = 200;
|
||||
private Priority pushoverPriority;
|
||||
private Sound pushoverSound;
|
||||
private String pushoverToken;
|
||||
private String pushoverUser;
|
||||
private String pushoverMessage;
|
||||
private String pushoverDevice;
|
||||
private String pushoverTitle;
|
||||
private String pushoverUrl;
|
||||
private String pushoverUrlTitle;
|
||||
private String pushoverTimestamp;
|
||||
private String pushoverRetry;
|
||||
private String pushoverExpire;
|
||||
private String pushoverCallback;
|
||||
private String proxyHost;
|
||||
private int proxyPort;
|
||||
private boolean pushoverHtml;
|
||||
/**
|
||||
* Creates a new Glance instance for the Glances API
|
||||
*
|
||||
* @return Glance instance
|
||||
*/
|
||||
public static Glance newGlance() {
|
||||
return new Glance();
|
||||
}
|
||||
|
||||
public JPushover() {
|
||||
this.withSound(Sound.PUSHOVER);
|
||||
this.withPriority(Priority.NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JPushover instance
|
||||
* @return JPushover instance
|
||||
* Creates a new Message instance for the Messages API
|
||||
*
|
||||
* @return Message instance
|
||||
*/
|
||||
public static JPushover create() {
|
||||
return new JPushover();
|
||||
}
|
||||
|
||||
/**
|
||||
* Your application's API token
|
||||
* (required)
|
||||
*
|
||||
* @param token The pushover API token
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withToken(final String token) {
|
||||
this.pushoverToken = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user/group key (not e-mail address) of your user (or you),
|
||||
* viewable when logged into the @see <a href="https://pushover.net/login">pushover dashboard</a>
|
||||
* (required)
|
||||
*
|
||||
* @param user The username
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withUser(final String user) {
|
||||
this.pushoverUser = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how often (in seconds) the Pushover servers will send the same notification to the user.
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param retry Number of seconds
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withRetry(final String retry) {
|
||||
this.pushoverRetry = retry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how many seconds your notification will continue to be retried for (every retry seconds).
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param expire Number of seconds
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withExpire(final String expire) {
|
||||
this.pushoverExpire = expire;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your message
|
||||
* (required)
|
||||
*
|
||||
* @param message The message to sent
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withMessage(final String message) {
|
||||
this.pushoverMessage = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your user's device name to send the message directly to that device,
|
||||
* rather than all of the user's devices
|
||||
* (optional)
|
||||
*
|
||||
* @param device The device name
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withDevice(final String device) {
|
||||
this.pushoverDevice = device;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your message's title, otherwise your app's name is used
|
||||
* (optional)
|
||||
*
|
||||
* @param title The title
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withTitle(final String title) {
|
||||
this.pushoverTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A supplementary URL to show with your message
|
||||
* (optional)
|
||||
*
|
||||
* @param url The url
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withUrl(final String url) {
|
||||
this.pushoverUrl = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables HTML in the pushover message
|
||||
* (optional)
|
||||
*
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover enableHtml() {
|
||||
this.pushoverHtml = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A title for your supplementary URL, otherwise just the URL is shown
|
||||
*
|
||||
* @param urlTitle The url title
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withUrlTitle(final String urlTitle) {
|
||||
this.pushoverUrlTitle = urlTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Unix timestamp of your message's date and time to display to the user,
|
||||
* rather than the time your message is received by our API
|
||||
*
|
||||
* @param timestamp The Unix timestamp
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withTimestamp(final String timestamp) {
|
||||
this.pushoverTimestamp = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority of the message based on the @see <a href="https://pushover.net/api#priority">documentation</a>
|
||||
* (optional)
|
||||
*
|
||||
* @param priority The priority enum
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withPriority(final Priority priority) {
|
||||
this.pushoverPriority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of one of the sounds supported by device clients to override
|
||||
* the user's default sound choice
|
||||
* (optional)
|
||||
*
|
||||
* @param sound THe sound enum
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withSound(final Sound sound) {
|
||||
this.pushoverSound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback parameter may be supplied with a publicly-accessible URL that the
|
||||
* pushover servers will send a request to when the user has acknowledged your
|
||||
* notification.
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param callback The callback URL
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withCallback(final String callback) {
|
||||
this.pushoverCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given proxy for HTTP requests
|
||||
*
|
||||
* @param proxyHost The host that should be used for the Proxy
|
||||
* @param proxyPort The port that should be used for the Proxy
|
||||
* @return JPushover instance
|
||||
*/
|
||||
public final JPushover withProxy(final String proxyHost, final int proxyPort) {
|
||||
this.proxyHost = proxyHost;
|
||||
this.proxyPort = proxyPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a validation request to pushover ensuring that the token and user
|
||||
* is correct, that there is at least one active device on the account.
|
||||
*
|
||||
* Requires token parameter
|
||||
* Requires user parameter
|
||||
* Optional device parameter to check specific device
|
||||
*
|
||||
* @return true if token and user are valid and at least on device is on the account, false otherwise
|
||||
*
|
||||
* @throws IOException if validation fails
|
||||
* @throws InterruptedException if validation fails
|
||||
*/
|
||||
public boolean validate() throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(this.pushoverToken, "Token is required for validation");
|
||||
Objects.requireNonNull(this.pushoverUser, "User is required for validation");
|
||||
|
||||
NavigableMap<String, String> body = new TreeMap<>();
|
||||
body.put(Constants.TOKEN.toString(), this.pushoverToken);
|
||||
body.put(Constants.USER.toString(), this.pushoverUser);
|
||||
|
||||
var httpResponse = getResponse(toJson(body), Constants.VALIDATION_URL.toString());
|
||||
|
||||
var valid = false;
|
||||
if (httpResponse.statusCode() == HTTP_OK) {
|
||||
var response = httpResponse.body();
|
||||
if (response != null && response.contains("\"status\":1")) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to pushover
|
||||
*
|
||||
* @return JPushoverResponse instance
|
||||
*
|
||||
* @throws IOException if sending the message fails
|
||||
* @throws InterruptedException if sending the message fails
|
||||
*/
|
||||
public final JPushoverResponse push() throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(this.pushoverToken, "Token is required for a message");
|
||||
Objects.requireNonNull(this.pushoverUser, "User is required for a message");
|
||||
Objects.requireNonNull(this.pushoverMessage, "Message is required for a message");
|
||||
|
||||
if (Priority.EMERGENCY.equals(this.pushoverPriority)) {
|
||||
Objects.requireNonNull(this.pushoverRetry, "Retry is required on priority emergency");
|
||||
Objects.requireNonNull(this.pushoverExpire, "Expire is required on priority emergency");
|
||||
}
|
||||
|
||||
NavigableMap<String, String> body = new TreeMap<>();
|
||||
body.put(Constants.TOKEN.toString(), this.pushoverToken);
|
||||
body.put(Constants.USER.toString(), this.pushoverUser);
|
||||
body.put(Constants.MESSAGE.toString(), this.pushoverMessage);
|
||||
body.put(Constants.DEVICE.toString(), this.pushoverDevice);
|
||||
body.put(Constants.TITLE.toString(), this.pushoverTitle);
|
||||
body.put(Constants.URL.toString(), this.pushoverUrl);
|
||||
body.put(Constants.RETRY.toString(), this.pushoverRetry);
|
||||
body.put(Constants.EXPIRE.toString(), this.pushoverExpire);
|
||||
body.put(Constants.CALLBACK.toString(), this.pushoverCallback);
|
||||
body.put(Constants.URLTITLE.toString(), this.pushoverUrlTitle);
|
||||
body.put(Constants.PRIORITY.toString(), this.pushoverPriority.toString());
|
||||
body.put(Constants.TIMESTAMP.toString(), this.pushoverTimestamp);
|
||||
body.put(Constants.SOUND.toString(), this.pushoverSound.toString());
|
||||
body.put(Constants.HTML.toString(), this.pushoverHtml ? "1" : "0");
|
||||
|
||||
var httpResponse = getResponse(toJson(body), Constants.MESSAGES_URL.toString());
|
||||
|
||||
var jPushoverResponse = new JPushoverResponse().isSuccessful(false);
|
||||
jPushoverResponse
|
||||
.httpStatus(httpResponse.statusCode())
|
||||
.response(httpResponse.body())
|
||||
.isSuccessful((httpResponse.statusCode() == HTTP_OK) ? true : false);
|
||||
|
||||
return jPushoverResponse;
|
||||
}
|
||||
|
||||
private HttpResponse<String> getResponse(String body, String url) throws IOException, InterruptedException {
|
||||
var httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(body))
|
||||
.build();
|
||||
|
||||
var httpClientBuilder = HttpClient.newBuilder();
|
||||
|
||||
if (this.proxyHost != null && this.proxyPort > 0) {
|
||||
httpClientBuilder.proxy(ProxySelector.of(new InetSocketAddress(this.proxyHost, this.proxyPort)));
|
||||
}
|
||||
|
||||
return httpClientBuilder.build().send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
}
|
||||
|
||||
private String toJson(NavigableMap<String, String> body) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("{");
|
||||
for (Map.Entry<String, String> entry : body.entrySet()) {
|
||||
buffer.append("\"").append(entry.getKey()).append("\"");
|
||||
buffer.append(":");
|
||||
buffer.append("\"").append(entry.getValue()).append("\"");
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append("}");
|
||||
|
||||
return buffer.toString().replace(",}", "}");
|
||||
public static Message newMessage() {
|
||||
return new Message();
|
||||
}
|
||||
}
|
142
src/main/java/de/svenkubiak/jpushover/apis/Glance.java
Normal file
142
src/main/java/de/svenkubiak/jpushover/apis/Glance.java
Normal file
@ -0,0 +1,142 @@
|
||||
package de.svenkubiak.jpushover.apis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import de.svenkubiak.jpushover.enums.Param;
|
||||
import de.svenkubiak.jpushover.http.PushoverRequest;
|
||||
import de.svenkubiak.jpushover.http.PushoverResponse;
|
||||
import de.svenkubiak.jpushover.utils.Urls;
|
||||
import de.svenkubiak.jpushover.utils.Validate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class Glance {
|
||||
private static final String GLANCE_URL = Urls.getGlanceUrl();
|
||||
private String token;
|
||||
private String user;
|
||||
private String device;
|
||||
private String title;
|
||||
private String text;
|
||||
private String subtext;
|
||||
private int count;
|
||||
private int percent;
|
||||
private String proxyHost;
|
||||
private int proxyPort;
|
||||
|
||||
public Glance withToken(String token) {
|
||||
Objects.requireNonNull(token, "token can not be null");
|
||||
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Glance withUser(String user) {
|
||||
Objects.requireNonNull(user, "user can not be null");
|
||||
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Glance withDevice(String device) {
|
||||
Objects.requireNonNull(device, "device can not be null");
|
||||
|
||||
this.device = device;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of the data being shown, such as "Widgets Sold"
|
||||
*
|
||||
* @param title the title to use
|
||||
* @return Glance instance
|
||||
*/
|
||||
public Glance withTitle(String title) {
|
||||
Objects.requireNonNull(title, "title can not be null");
|
||||
Validate.checkArgument(title.length() <= 100, "Title must not exceed a length of 100 characters");
|
||||
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main line of data, used on most screens
|
||||
*
|
||||
* @param text the text to use
|
||||
* @return Glance instance
|
||||
*/
|
||||
public Glance withText(String text) {
|
||||
Objects.requireNonNull(text, "text can not be null");
|
||||
Validate.checkArgument(text.length() <= 100, "Text must not exceed a length of 100 characters");
|
||||
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A second line of data
|
||||
*
|
||||
* @param subtext the subtext to use
|
||||
* @return Glance instance
|
||||
*/
|
||||
public Glance withSubtext(String subtext) {
|
||||
Objects.requireNonNull(subtext, "subtext can not be null");
|
||||
Validate.checkArgument(subtext.length() <= 100, "subtext must not exceed a length of 100 characters");
|
||||
|
||||
this.subtext = subtext;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shown on smaller screens; useful for simple counts
|
||||
*
|
||||
* @param count the count to use
|
||||
* @return Glance instance
|
||||
*/
|
||||
public Glance withCount(int count) {
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shown on some screens as a progress bar/circle
|
||||
*
|
||||
* @param percent the percent to use
|
||||
* @return GLance instance
|
||||
*/
|
||||
public Glance withPercent(int percent) {
|
||||
this.percent = percent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a glance to pushover
|
||||
*
|
||||
* @return PushoverResponse instance
|
||||
*
|
||||
* @throws IOException if sending the message fails
|
||||
* @throws InterruptedException if sending the message fails
|
||||
*/
|
||||
public PushoverResponse push() throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(this.token, "Token is required for a glance");
|
||||
Objects.requireNonNull(this.user, "User is required for a glance");
|
||||
|
||||
NavigableMap<String, String> body = new TreeMap<>();
|
||||
body.put(Param.TOKEN.toString(), this.token);
|
||||
body.put(Param.USER.toString(), this.user);
|
||||
body.put(Param.DEVICE.toString(), this.device);
|
||||
body.put(Param.TITLE.toString(), this.title);
|
||||
body.put(Param.TEXT.toString(), this.text);
|
||||
body.put(Param.SUBTEXT.toString(), this.subtext);
|
||||
body.put(Param.COUNT.toString(), String.valueOf(this.count));
|
||||
body.put(Param.PERCENT.toString(), String.valueOf(this.percent));
|
||||
|
||||
|
||||
return new PushoverRequest().push(GLANCE_URL, body, this.proxyHost, this.proxyPort);
|
||||
}
|
||||
}
|
301
src/main/java/de/svenkubiak/jpushover/apis/Message.java
Normal file
301
src/main/java/de/svenkubiak/jpushover/apis/Message.java
Normal file
@ -0,0 +1,301 @@
|
||||
package de.svenkubiak.jpushover.apis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import de.svenkubiak.jpushover.enums.Param;
|
||||
import de.svenkubiak.jpushover.enums.Priority;
|
||||
import de.svenkubiak.jpushover.enums.Sound;
|
||||
import de.svenkubiak.jpushover.http.PushoverRequest;
|
||||
import de.svenkubiak.jpushover.http.PushoverResponse;
|
||||
import de.svenkubiak.jpushover.utils.Urls;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class Message {
|
||||
private static final String MESSAGE_URL = Urls.getMessageUrl();
|
||||
private static final String VALIDATION_URL = Urls.getValidationUrl();
|
||||
private Priority priority;
|
||||
private Sound sound;
|
||||
private String token;
|
||||
private String user;
|
||||
private String message;
|
||||
private String device;
|
||||
private String title;
|
||||
private String url;
|
||||
private String urlTitle;
|
||||
private String timestamp;
|
||||
private String retry;
|
||||
private String expire;
|
||||
private String callback;
|
||||
private String proxyHost;
|
||||
private int proxyPort;
|
||||
private boolean html;
|
||||
|
||||
public Message() {
|
||||
this.withSound(Sound.PUSHOVER);
|
||||
this.withPriority(Priority.NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Your application's API token
|
||||
* (required)
|
||||
*
|
||||
* @param token The pushover API token
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withToken(final String token) {
|
||||
Objects.requireNonNull(token, "Token can not be null");
|
||||
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user/group key (not e-mail address) of your user (or you),
|
||||
* viewable when logged into the @see <a href="https://pushover.net/login">pushover dashboard</a>
|
||||
* (required)
|
||||
*
|
||||
* @param user The username
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withUser(final String user) {
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how often (in seconds) the Pushover servers will send the same notification to the user.
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param retry Number of seconds
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withRetry(final String retry) {
|
||||
this.retry = retry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how many seconds your notification will continue to be retried for (every retry seconds).
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param expire Number of seconds
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withExpire(final String expire) {
|
||||
this.expire = expire;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your message
|
||||
* (required)
|
||||
*
|
||||
* @param message The message to sent
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withMessage(final String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your user's device name to send the message directly to that device,
|
||||
* rather than all of the user's devices
|
||||
* (optional)
|
||||
*
|
||||
* @param device The device name
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withDevice(final String device) {
|
||||
this.device = device;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Your message's title, otherwise your app's name is used
|
||||
* (optional)
|
||||
*
|
||||
* @param title The title
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withTitle(final String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A supplementary URL to show with your message
|
||||
* (optional)
|
||||
*
|
||||
* @param url The url
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withUrl(final String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables HTML in the pushover message
|
||||
* (optional)
|
||||
*
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message enableHtml() {
|
||||
this.html = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A title for your supplementary URL, otherwise just the URL is shown
|
||||
*
|
||||
* @param urlTitle The url title
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withUrlTitle(final String urlTitle) {
|
||||
this.urlTitle = urlTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Unix timestamp of your message's date and time to display to the user,
|
||||
* rather than the time your message is received by our API
|
||||
*
|
||||
* @param timestamp The Unix timestamp
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withTimestamp(final String timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Priority of the message based on the @see <a href="https://pushover.net/api#priority">documentation</a>
|
||||
* (optional)
|
||||
*
|
||||
* @param priority The priority enum
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withPriority(final Priority priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of one of the sounds supported by device clients to override
|
||||
* the user's default sound choice
|
||||
* (optional)
|
||||
*
|
||||
* @param sound THe sound enum
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withSound(final Sound sound) {
|
||||
this.sound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback parameter may be supplied with a publicly-accessible URL that the
|
||||
* pushover servers will send a request to when the user has acknowledged your
|
||||
* notification.
|
||||
* Only required if priority is set to emergency.
|
||||
*
|
||||
* @param callback The callback URL
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withCallback(final String callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given proxy for HTTP requests
|
||||
*
|
||||
* @param proxyHost The host that should be used for the Proxy
|
||||
* @param proxyPort The port that should be used for the Proxy
|
||||
* @return Message instance
|
||||
*/
|
||||
public final Message withProxy(final String proxyHost, final int proxyPort) {
|
||||
this.proxyHost = proxyHost;
|
||||
this.proxyPort = proxyPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a validation request to pushover ensuring that the token and user
|
||||
* is correct, that there is at least one active device on the account.
|
||||
*
|
||||
* Requires token parameter
|
||||
* Requires user parameter
|
||||
* Optional device parameter to check specific device
|
||||
*
|
||||
* @return true if token and user are valid and at least on device is on the account, false otherwise
|
||||
*
|
||||
* @throws IOException if validation fails
|
||||
* @throws InterruptedException if validation fails
|
||||
*/
|
||||
public boolean validate() throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(this.token, "Token is required for validation");
|
||||
Objects.requireNonNull(this.user, "User is required for validation");
|
||||
|
||||
NavigableMap<String, String> body = new TreeMap<>();
|
||||
body.put(Param.TOKEN.toString(), this.token);
|
||||
body.put(Param.USER.toString(), this.user);
|
||||
|
||||
var pushoverResponse = new PushoverRequest().push(VALIDATION_URL, body, this.proxyHost, this.proxyPort);
|
||||
|
||||
var valid = false;
|
||||
if (pushoverResponse.getHttpStatus() == 200) {
|
||||
var response = pushoverResponse.getResponse();
|
||||
if (response != null && response.contains("\"status\":1")) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to pushover
|
||||
*
|
||||
* @return PushoverResponse instance
|
||||
*
|
||||
* @throws IOException if sending the message fails
|
||||
* @throws InterruptedException if sending the message fails
|
||||
*/
|
||||
public final PushoverResponse push() throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(this.token, "Token is required for a message");
|
||||
Objects.requireNonNull(this.user, "User is required for a message");
|
||||
Objects.requireNonNull(this.message, "Message is required for a message");
|
||||
|
||||
if (Priority.EMERGENCY.equals(this.priority)) {
|
||||
Objects.requireNonNull(this.retry, "Retry is required on priority emergency");
|
||||
Objects.requireNonNull(this.expire, "Expire is required on priority emergency");
|
||||
}
|
||||
|
||||
NavigableMap<String, String> body = new TreeMap<>();
|
||||
body.put(Param.TOKEN.toString(), this.token);
|
||||
body.put(Param.USER.toString(), this.user);
|
||||
body.put(Param.MESSAGE.toString(), this.message);
|
||||
body.put(Param.DEVICE.toString(), this.device);
|
||||
body.put(Param.TITLE.toString(), this.title);
|
||||
body.put(Param.URL.toString(), this.url);
|
||||
body.put(Param.RETRY.toString(), this.retry);
|
||||
body.put(Param.EXPIRE.toString(), this.expire);
|
||||
body.put(Param.CALLBACK.toString(), this.callback);
|
||||
body.put(Param.URLTITLE.toString(), this.urlTitle);
|
||||
body.put(Param.PRIORITY.toString(), this.priority.toString());
|
||||
body.put(Param.TIMESTAMP.toString(), this.timestamp);
|
||||
body.put(Param.SOUND.toString(), this.sound.toString());
|
||||
body.put(Param.HTML.toString(), this.html ? "1" : "0");
|
||||
|
||||
return new PushoverRequest().push(MESSAGE_URL, body, this.proxyHost, this.proxyPort);
|
||||
}
|
||||
}
|
@ -5,14 +5,13 @@ package de.svenkubiak.jpushover.enums;
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public enum Constants {
|
||||
public enum Param {
|
||||
ATTACHMENT("attachment"),
|
||||
CALLBACK("callback"),
|
||||
DEVICE("device"),
|
||||
EXPIRE("expire"),
|
||||
HTML("html"),
|
||||
MESSAGE("message"),
|
||||
MESSAGES_URL("https://api.pushover.net/1/messages.json"),
|
||||
PRIORITY("priority"),
|
||||
RETRY("retry"),
|
||||
SOUND("sound"),
|
||||
@ -22,11 +21,14 @@ public enum Constants {
|
||||
URL("url"),
|
||||
URLTITLE("urltitle"),
|
||||
USER("user"),
|
||||
VALIDATION_URL("https://api.pushover.net/1/users/validate.json");
|
||||
TEXT("text"),
|
||||
SUBTEXT("subtext"),
|
||||
COUNT("count"),
|
||||
PERCENT("percent");
|
||||
|
||||
private final String value;
|
||||
|
||||
Constants (String value) {
|
||||
Param (String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package de.svenkubiak.jpushover.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class PushoverRequest {
|
||||
|
||||
public PushoverResponse push(String url, NavigableMap<String, String> body, String proxyHost, int proxyPort) throws IOException, InterruptedException {
|
||||
Objects.requireNonNull(url, "API URL can not be null");
|
||||
Objects.requireNonNull(body, "body can not be null");
|
||||
|
||||
var httpResponse = getResponse(toJson(body), url, proxyHost, proxyPort);
|
||||
|
||||
var jPushoverResponse = new PushoverResponse().isSuccessful(false);
|
||||
|
||||
jPushoverResponse
|
||||
.httpStatus(httpResponse.statusCode())
|
||||
.response(httpResponse.body())
|
||||
.isSuccessful((httpResponse.statusCode() == 200) ? true : false);
|
||||
|
||||
return jPushoverResponse;
|
||||
}
|
||||
|
||||
private HttpResponse<String> getResponse(String body, String url, String proxyHost, int proxyPort) throws IOException, InterruptedException {
|
||||
var httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(body))
|
||||
.build();
|
||||
|
||||
var httpClientBuilder = HttpClient.newBuilder();
|
||||
|
||||
if (proxyHost != null && proxyPort > 0) {
|
||||
httpClientBuilder.proxy(ProxySelector.of(new InetSocketAddress(proxyHost, proxyPort)));
|
||||
}
|
||||
|
||||
return httpClientBuilder.build().send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
}
|
||||
|
||||
private String toJson(NavigableMap<String, String> body) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("{");
|
||||
for (Map.Entry<String, String> entry : body.entrySet()) {
|
||||
buffer.append("\"").append(entry.getKey()).append("\"");
|
||||
buffer.append(":");
|
||||
buffer.append("\"").append(entry.getValue()).append("\"");
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append("}");
|
||||
|
||||
return buffer.toString().replace(",}", "}");
|
||||
}
|
||||
}
|
@ -1,26 +1,26 @@
|
||||
package de.svenkubiak.jpushover;
|
||||
package de.svenkubiak.jpushover.http;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class JPushoverResponse {
|
||||
public class PushoverResponse {
|
||||
private String pushoverResponse;
|
||||
private int pushoverHttpStatus;
|
||||
private boolean pushoverSuccessful;
|
||||
|
||||
public JPushoverResponse response(String response) {
|
||||
public PushoverResponse response(String response) {
|
||||
this.pushoverResponse = response;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JPushoverResponse httpStatus(int httpStatus) {
|
||||
public PushoverResponse httpStatus(int httpStatus) {
|
||||
this.pushoverHttpStatus = httpStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JPushoverResponse isSuccessful(boolean successful) {
|
||||
public PushoverResponse isSuccessful(boolean successful) {
|
||||
this.pushoverSuccessful = successful;
|
||||
return this;
|
||||
}
|
||||
@ -40,7 +40,7 @@ public class JPushoverResponse {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the api returned a HTTP status code 200, false otherwise
|
||||
* @return true if the API returned a HTTP status code 200, false otherwise
|
||||
*/
|
||||
public boolean isSuccessful() {
|
||||
return pushoverSuccessful;
|
35
src/main/java/de/svenkubiak/jpushover/utils/Urls.java
Normal file
35
src/main/java/de/svenkubiak/jpushover/utils/Urls.java
Normal file
@ -0,0 +1,35 @@
|
||||
package de.svenkubiak.jpushover.utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public class Urls {
|
||||
public static String getGlanceUrl() {
|
||||
String mode = System.getProperty("mode");
|
||||
if (("test").equals(mode)) {
|
||||
return "http://127.0.0.1:8080/1/glances.json";
|
||||
}
|
||||
|
||||
return "https://api.pushover.net/1/glances.json";
|
||||
}
|
||||
|
||||
public static String getMessageUrl() {
|
||||
String mode = System.getProperty("mode");
|
||||
if (("test").equals(mode)) {
|
||||
return "http://127.0.0.1:8080/1/messages.json";
|
||||
}
|
||||
|
||||
return "https://api.pushover.net/1/messages.json";
|
||||
}
|
||||
|
||||
public static String getValidationUrl() {
|
||||
String mode = System.getProperty("mode");
|
||||
if (("test").equals(mode)) {
|
||||
return "http://127.0.0.1:8080/1/users/validate.json";
|
||||
}
|
||||
|
||||
return "https://api.pushover.net/1/users/validate.json";
|
||||
}
|
||||
}
|
22
src/main/java/de/svenkubiak/jpushover/utils/Validate.java
Normal file
22
src/main/java/de/svenkubiak/jpushover/utils/Validate.java
Normal file
@ -0,0 +1,22 @@
|
||||
package de.svenkubiak.jpushover.utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author svenkubiak
|
||||
*
|
||||
*/
|
||||
public final class Validate {
|
||||
/**
|
||||
* Ensures the truth of an expression involving one or more parameters to the calling method.
|
||||
*
|
||||
* @param expression a boolean expression
|
||||
* @param errorMessage the exception message to use if the check fails; will be converted to a string using {@link String#valueOf(Object)}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code expression} is false
|
||||
*/
|
||||
public static void checkArgument(boolean expression, Object errorMessage) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user