Skip to content

Commit

Permalink
Merge pull request #5 from Sitrica/beta
Browse files Browse the repository at this point in the history
1.1.0
  • Loading branch information
TheLimeGlass authored Jul 16, 2020
2 parents 4bee089 + 713260c commit d232bc4
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 80 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {

jar.archiveName = project.name + '.jar'
// Add SNAPSHOT to make this publish as a beta.
version '1.0.9'
version '1.1.0'

sourceCompatibility = 1.8

Expand Down
105 changes: 28 additions & 77 deletions src/main/java/com/sitrica/japson/client/JapsonClient.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
package com.sitrica.japson.client;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.google.common.flogger.FluentLogger;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.sitrica.japson.client.packets.HeartbeatPacket;
import com.sitrica.japson.shared.Japson;
import com.sitrica.japson.shared.Packet;
import com.sitrica.japson.shared.ReceiverFuture;
import com.sitrica.japson.shared.ReturnablePacket;

public class JapsonClient extends Japson {

private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private static final FluentLogger logger = FluentLogger.forEnclosingClass();

protected long HEARTBEAT = 1000L, DELAY = 1000L; // in milliseconds.

Expand Down Expand Up @@ -79,10 +68,6 @@ public JapsonClient setHeartbeat(long heartbeat) {
return this;
}

public FluentLogger getLogger() {
return logger;
}

public void shutdown() {
executor.shutdown();
}
Expand All @@ -91,71 +76,37 @@ public void kill() {
executor.shutdownNow();
}

@Override
public JapsonClient setAllowedAddresses(InetAddress... addesses) {
acceptable.clear();
acceptable.addAll(Sets.newHashSet(addesses));
return this;
}

@Override
public JapsonClient setPacketBufferSize(int buffer) {
this.PACKET_SIZE = buffer;
return this;
}

@Override
public JapsonClient setPassword(String password) {
this.password = password;
return this;
}

@Override
public JapsonClient enableDebug() {
this.debug = true;
return this;
}

public <T> T sendPacket(ReturnablePacket<T> japsonPacket) throws TimeoutException, InterruptedException, ExecutionException {
return CompletableFuture.supplyAsync(() -> {
try (DatagramSocket socket = new DatagramSocket()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeInt(japsonPacket.getID());
out.writeUTF(gson.toJson(japsonPacket.toJson()));
byte[] buf = out.toByteArray();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
// Reset the byte buffer
buf = new byte[PACKET_SIZE];
ByteArrayDataInput input = new ReceiverFuture(logger, this, socket)
.create(new DatagramPacket(buf, buf.length))
.get();
if (input == null) {
logger.atSevere().log("Packet with id %s returned null or an incorrect readable object for Japson", japsonPacket.getID());
return null;
}
int id = input.readInt();
if (id != japsonPacket.getID()) {
logger.atSevere().log("Sent returnable packet with id %s, but did not get correct packet id returned", japsonPacket.getID());
return null;
}
String json = input.readUTF();
if (debug)
logger.atInfo().log("Sent returnable packet with id %s and recieved %s", japsonPacket.getID(), json);
return japsonPacket.getObject(JsonParser.parseString(json).getAsJsonObject());
} catch (SocketException socketException) {
logger.atSevere().withCause(socketException)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Socket error: " + socketException.getMessage());
} catch (IOException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("IO error: " + exception.getMessage());
} catch (InterruptedException | ExecutionException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Timeout: " + exception.getMessage());
}
return null;
}).get(HEARTBEAT * 3, TimeUnit.MILLISECONDS);
return sendPacket(address, port, japsonPacket, gson);
}

public void sendPacket(Packet japsonPacket) {
CompletableFuture.runAsync(() -> {
try (DatagramSocket socket = new DatagramSocket()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeInt(japsonPacket.getID());
out.writeUTF(gson.toJson(japsonPacket.toJson()));
byte[] buf = out.toByteArray();
socket.setSoTimeout((int)(HEARTBEAT * 3));
socket.send(new DatagramPacket(buf, buf.length, address, port));
if (debug)
logger.atInfo().log("Sent non-returnable packet with id %s", japsonPacket.getID());
} catch (SocketException socketException) {
logger.atSevere().withCause(socketException)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Socket error: " + socketException.getMessage());
} catch (IOException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("IO error: " + exception.getMessage());
}
});
sendPacket(address, port, japsonPacket, gson);
}

}
25 changes: 25 additions & 0 deletions src/main/java/com/sitrica/japson/server/JapsonServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,31 @@ public void addIgnoreDebugPackets(Integer... packets) {
ignored.addAll(Sets.newHashSet(packets));
}

@Override
public JapsonServer setAllowedAddresses(InetAddress... addesses) {
acceptable.clear();
acceptable.addAll(Sets.newHashSet(addesses));
return this;
}

@Override
public JapsonServer setPacketBufferSize(int buffer) {
this.PACKET_SIZE = buffer;
return this;
}

@Override
public JapsonServer setPassword(String password) {
this.password = password;
return this;
}

@Override
public JapsonServer enableDebug() {
this.debug = true;
return this;
}

/**
* The amount of minutes to wait before forgetting about a connection.
*
Expand Down
109 changes: 107 additions & 2 deletions src/main/java/com/sitrica/japson/shared/Japson.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
package com.sitrica.japson.shared;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;

public abstract class Japson {

protected static final FluentLogger logger = FluentLogger.forEnclosingClass();
protected final Set<InetAddress> acceptable = new HashSet<>();
protected final Set<Handler> handlers = new HashSet<>();

Expand Down Expand Up @@ -46,18 +62,24 @@ public boolean isAllowed(InetAddress address) {
return acceptable.contains(address);
}

public void setPacketBufferSize(int buffer) {
public Japson setPacketBufferSize(int buffer) {
this.PACKET_SIZE = buffer;
return this;
}

public void setPassword(String password) {
public Japson setPassword(String password) {
this.password = password;
return this;
}

public Set<Handler> getHandlers() {
return handlers;
}

public FluentLogger getLogger() {
return logger;
}

public InetAddress getAddress() {
return address;
}
Expand All @@ -79,4 +101,87 @@ public int getPort() {
return port;
}

public <T> T sendPacket(InetAddress address, int port, ReturnablePacket<T> japsonPacket) throws TimeoutException, InterruptedException, ExecutionException {
return sendPacket(address, port, japsonPacket, new GsonBuilder()
.enableComplexMapKeySerialization()
.serializeNulls()
.setLenient()
.create());
}

public <T> T sendPacket(InetAddress address, int port, ReturnablePacket<T> japsonPacket, Gson gson) throws TimeoutException, InterruptedException, ExecutionException {
return CompletableFuture.supplyAsync(() -> {
try (DatagramSocket socket = new DatagramSocket()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeInt(japsonPacket.getID());
out.writeUTF(gson.toJson(japsonPacket.toJson()));
byte[] buf = out.toByteArray();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
// Reset the byte buffer
buf = new byte[PACKET_SIZE];
ByteArrayDataInput input = new ReceiverFuture(logger, this, socket)
.create(new DatagramPacket(buf, buf.length))
.get();
if (input == null) {
logger.atSevere().log("Packet with id %s returned null or an incorrect readable object for Japson", japsonPacket.getID());
return null;
}
int id = input.readInt();
if (id != japsonPacket.getID()) {
logger.atSevere().log("Sent returnable packet with id %s, but did not get correct packet id returned", japsonPacket.getID());
return null;
}
String json = input.readUTF();
if (debug)
logger.atInfo().log("Sent returnable packet with id %s and recieved %s", japsonPacket.getID(), json);
return japsonPacket.getObject(JsonParser.parseString(json).getAsJsonObject());
} catch (SocketException socketException) {
logger.atSevere().withCause(socketException)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Socket error: " + socketException.getMessage());
} catch (IOException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("IO error: " + exception.getMessage());
} catch (InterruptedException | ExecutionException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Timeout: " + exception.getMessage());
}
return null;
}).get(3, TimeUnit.SECONDS);
}

public void sendPacket(InetAddress address, int port, Packet japsonPacket) {
sendPacket(address, port, japsonPacket, new GsonBuilder()
.enableComplexMapKeySerialization()
.serializeNulls()
.setLenient()
.create());
}

public void sendPacket(InetAddress address, int port, Packet japsonPacket, Gson gson) {
CompletableFuture.runAsync(() -> {
try (DatagramSocket socket = new DatagramSocket()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeInt(japsonPacket.getID());
out.writeUTF(gson.toJson(japsonPacket.toJson()));
byte[] buf = out.toByteArray();
socket.setSoTimeout((int)(3000));
socket.send(new DatagramPacket(buf, buf.length, address, port));
if (debug)
logger.atInfo().log("Sent non-returnable packet with id %s", japsonPacket.getID());
} catch (SocketException socketException) {
logger.atSevere().withCause(socketException)
.atMostEvery(15, TimeUnit.SECONDS)
.log("Socket error: " + socketException.getMessage());
} catch (IOException exception) {
logger.atSevere().withCause(exception)
.atMostEvery(15, TimeUnit.SECONDS)
.log("IO error: " + exception.getMessage());
}
});
}

}

0 comments on commit d232bc4

Please sign in to comment.