Compare commits
33
Commits
standalone
...
v2.3.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4277dfd74d | ||
|
|
28b4d8dcd0 | ||
|
|
733204b6b9 | ||
|
|
52956ce210 | ||
|
|
2de64da511 | ||
|
|
0ea6867d91 | ||
|
|
190bfaa4a9 | ||
|
|
b43dda37b2 | ||
|
|
4dfb157166 | ||
|
|
d8c2e072b1 | ||
|
|
359b616a41 | ||
|
|
9342f75317 | ||
|
|
f17bb4e414 | ||
|
|
5f347e538b | ||
|
|
b4fb8c69a9 | ||
|
|
95ebcf22a8 | ||
|
|
302da3c907 | ||
|
|
f8019debd0 | ||
|
|
ab317e76b3 | ||
|
|
15556be265 | ||
|
|
26958e35fe | ||
|
|
e905881238 | ||
|
|
fde7a941b6 | ||
|
|
9d24deabe9 | ||
|
|
c2f331e7ec | ||
|
|
705bddd062 | ||
|
|
826609db30 | ||
|
|
0eca96bd67 | ||
|
|
f767387840 | ||
|
|
8ae3c21a23 | ||
|
|
be1c056502 | ||
|
|
500142eb5b | ||
|
|
1e5876bc08 |
No files matched your search
+2
-1
@@ -11,7 +11,8 @@
|
||||
/build.xml
|
||||
|
||||
# maven
|
||||
/target
|
||||
/*/target/
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
# vim
|
||||
.*.sw[a-p]
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: j8y4qeDOXAYjmf6WU6EbpUA6AKTz26yJ4zNb6oAuB4h9Y3PpBRjFjCIBL6jJQnMxZMLjdgk72/3uqS7+//jJ8/iiY/OJhO2L+2us8TJDcQhH5EI1USe/lcZKf60iJjmd9Q9pjh1eHNYhxr6kyNLnpa6fw5b/hIBT6CvNZAJV1qbhRpHwtzbgdlMFaHGnpX192vJNw7E3uuJuSwue5XNK2ybDp81oTrM0Q16JCq/UsQhGq4Ba3JffOhdBhpfg4EI2jJfe3vN8CFqojCYKNSp7eL6DPFPaV4x8Ly8cRIOZ5Zb60m5SyWAcagPKJuUq3ZOTHfeVTjkI9ymZMHe1pla2Mq6eitIBwZIGnonjyMxcTdkR9EJgq9jo+1PzdStR/NlGLakBiwPzk8Ov0DZ+iOwpYUkISUkMU0UgKWwoFoRu18CHtp+ALEsoYZhBQGlcShq+4EGv9VMNBYk9vN3KXNRMVGKqXd6O3T6shvSQgoUn/3mvksOTAuhS5J4U3woHecDrXwl/RfP2aqiHhX/S7p7yY4hVcHu8kiSYpNQMbay+rNd6HxFcRe/U9HOUt6kW8/yo1ROyCxs3ze+N6LtGDHspgzkFaay6I6wMHYNDnzzRP4MC3Zc73zxViXol6dGBk4Tawsm16VaI6b1uyWLBGKvuU23azkmMTHUmGFXl2/BTaYw=
|
||||
file: universal/target/nuvotifier-universal-2.3.2.2.jar
|
||||
file: universal/target/nuvotifier-universal-2.3.6.jar
|
||||
on:
|
||||
tags: true
|
||||
+1
-1
@@ -74,7 +74,7 @@ The message is JSON-encoded containing the following data:
|
||||
|
||||
A response is given after the vote has been received and parsed, but not yet processed.
|
||||
|
||||
For your convenience, the NuVotifier team has provided client libraries in [JavaScript](https://github.com/NuVotifier/votifier2-js) and [PHP](https://github.com/NuVotifier/votifier2-php). If you are stuck, these libraries may help you.
|
||||
For your convenience, the NuVotifier team has provided client libraries in [JavaScript](https://github.com/NuVotifier/votifier2-js), [PHP](https://github.com/NuVotifier/votifier2-php) and [Go](https://github.com/minecrafter/go-votifier). If you are stuck, these libraries may help you.
|
||||
|
||||
### Protocol v1 (deprecated)
|
||||
|
||||
|
||||
+4
-5
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -56,10 +56,9 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.7.2-R0.1</version>
|
||||
<type>jar</type>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -190,88 +190,82 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
|
||||
debug = cfg.getBoolean("debug", false);
|
||||
|
||||
boolean setUpPort = cfg.getBoolean("enableExternal", true); //Always default to running the external port
|
||||
// Load Votifier tokens.
|
||||
ConfigurationSection tokenSection = cfg.getConfigurationSection("tokens");
|
||||
|
||||
if (setUpPort) {
|
||||
// Load Votifier tokens.
|
||||
ConfigurationSection tokenSection = cfg.getConfigurationSection("tokens");
|
||||
|
||||
if (tokenSection != null) {
|
||||
Map<String, Object> websites = tokenSection.getValues(false);
|
||||
for (Map.Entry<String, Object> website : websites.entrySet()) {
|
||||
tokens.put(website.getKey(), KeyCreator.createKeyFrom(website.getValue().toString()));
|
||||
getLogger().info("Loaded token for website: " + website.getKey());
|
||||
}
|
||||
} else {
|
||||
String token = TokenUtil.newToken();
|
||||
tokenSection = cfg.createSection("tokens");
|
||||
tokenSection.set("default", token);
|
||||
tokens.put("default", KeyCreator.createKeyFrom(token));
|
||||
try {
|
||||
cfg.save(config);
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"Error generating Votifier token", e);
|
||||
gracefulExit();
|
||||
return;
|
||||
}
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("No tokens were found in your configuration, so we've generated one for you.");
|
||||
getLogger().info("Your default Votifier token is " + token + ".");
|
||||
getLogger().info("You will need to provide this token when you submit your server to a voting");
|
||||
getLogger().info("list.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
if (tokenSection != null) {
|
||||
Map<String, Object> websites = tokenSection.getValues(false);
|
||||
for (Map.Entry<String, Object> website : websites.entrySet()) {
|
||||
tokens.put(website.getKey(), KeyCreator.createKeyFrom(website.getValue().toString()));
|
||||
getLogger().info("Loaded token for website: " + website.getKey());
|
||||
}
|
||||
|
||||
// Initialize the receiver.
|
||||
final String host = cfg.getString("host", hostAddr);
|
||||
final int port = cfg.getInt("port", 8192);
|
||||
if (debug)
|
||||
getLogger().info("DEBUG mode enabled!");
|
||||
|
||||
final boolean disablev1 = cfg.getBoolean("disable-v1-protocol");
|
||||
if (disablev1) {
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Votifier protocol v1 parsing has been disabled. Most voting websites do not");
|
||||
getLogger().info("currently support the modern Votifier protocol in NuVotifier.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
serverGroup = new NioEventLoopGroup(1);
|
||||
|
||||
new ServerBootstrap()
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.group(serverGroup)
|
||||
.childHandler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel channel) throws Exception {
|
||||
channel.attr(VotifierSession.KEY).set(new VotifierSession());
|
||||
channel.attr(VotifierPlugin.KEY).set(NuVotifierBukkit.this);
|
||||
channel.pipeline().addLast("greetingHandler", new VotifierGreetingHandler());
|
||||
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !disablev1));
|
||||
channel.pipeline().addLast("voteHandler", new VoteInboundHandler(NuVotifierBukkit.this));
|
||||
}
|
||||
})
|
||||
.bind(host, port)
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
getLogger().info("Votifier enabled on socket "+serverChannel.localAddress()+".");
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
socketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
getLogger().log(Level.SEVERE, "Votifier was not able to bind to " + socketAddress, future.cause());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
getLogger().info("You have enableExternal set to false in your config.yml. NuVotifier will NOT listen to votes coming in from an external voting list.");
|
||||
String token = TokenUtil.newToken();
|
||||
tokenSection = cfg.createSection("tokens");
|
||||
tokenSection.set("default", token);
|
||||
tokens.put("default", KeyCreator.createKeyFrom(token));
|
||||
try {
|
||||
cfg.save(config);
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"Error generating Votifier token", e);
|
||||
gracefulExit();
|
||||
return;
|
||||
}
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("No tokens were found in your configuration, so we've generated one for you.");
|
||||
getLogger().info("Your default Votifier token is " + token + ".");
|
||||
getLogger().info("You will need to provide this token when you submit your server to a voting");
|
||||
getLogger().info("list.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Initialize the receiver.
|
||||
final String host = cfg.getString("host", hostAddr);
|
||||
final int port = cfg.getInt("port", 8192);
|
||||
if (debug)
|
||||
getLogger().info("DEBUG mode enabled!");
|
||||
|
||||
final boolean disablev1 = cfg.getBoolean("disable-v1-protocol");
|
||||
if (disablev1) {
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
getLogger().info("Votifier protocol v1 parsing has been disabled. Most voting websites do not");
|
||||
getLogger().info("currently support the modern Votifier protocol in NuVotifier.");
|
||||
getLogger().info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
serverGroup = new NioEventLoopGroup(1);
|
||||
|
||||
new ServerBootstrap()
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.group(serverGroup)
|
||||
.childHandler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel channel) throws Exception {
|
||||
channel.attr(VotifierSession.KEY).set(new VotifierSession());
|
||||
channel.attr(VotifierPlugin.KEY).set(NuVotifierBukkit.this);
|
||||
channel.pipeline().addLast("greetingHandler", new VotifierGreetingHandler());
|
||||
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !disablev1));
|
||||
channel.pipeline().addLast("voteHandler", new VoteInboundHandler(NuVotifierBukkit.this));
|
||||
}
|
||||
})
|
||||
.bind(host, port)
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
getLogger().info("Votifier enabled on socket "+serverChannel.localAddress()+".");
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
socketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
getLogger().log(Level.SEVERE, "Votifier was not able to bind to " + socketAddress, future.cause());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ConfigurationSection forwardingConfig = cfg.getConfigurationSection("forwarding");
|
||||
if (forwardingConfig != null) {
|
||||
String method = forwardingConfig.getString("method", "none").toLowerCase(); //Default to lower case for case-insensitive searches
|
||||
@@ -342,12 +336,12 @@ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, Votifie
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Channel channel, final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
getLogger().info("Got a protocol v1 vote record -> " + vote);
|
||||
getLogger().info("Got a protocol v1 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
} else {
|
||||
getLogger().info("Got a protocol v2 vote record -> " + vote);
|
||||
getLogger().info("Got a protocol v2 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
}
|
||||
}
|
||||
Bukkit.getScheduler().runTask(this, new Runnable() {
|
||||
|
||||
@@ -9,10 +9,6 @@ port: 8192
|
||||
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
|
||||
debug: false
|
||||
|
||||
# Setting this value to false will turn off the votifier port listening for external votes. This is beneficial if the server
|
||||
# is only listening for votes coming from NuVotifier running on your BungeeCord.
|
||||
enableExternal: true
|
||||
|
||||
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
|
||||
# option is currently not recommended as most voting sites only support the old protocol at present. However, if you are
|
||||
# using NuVotifier's proxy forwarding mechanism, enabling this option will increase your server's security.
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ public class NuVotifier extends Plugin implements VoteHandler, VotifierPlugin {
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
getLogger().info("Votifier enabled on socket "+serverChannel.localAddress()+".");
|
||||
getLogger().info("Votifier enabled on socket " + serverChannel.localAddress() + ".");
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
@@ -255,8 +255,10 @@ public class NuVotifier extends Plugin implements VoteHandler, VotifierPlugin {
|
||||
getLogger().info("Using in-memory cache for votes that are not able to be delivered.");
|
||||
} else if ("file".equals(cacheMethod)) {
|
||||
try {
|
||||
voteCache = new FileVoteCache(ProxyServer.getInstance().getServers().size(), this, new File(getDataFolder(),
|
||||
fwdCfg.getString("pluginMessaging.file.name")));
|
||||
voteCache = new FileVoteCache(
|
||||
ProxyServer.getInstance().getServers().size(), this,
|
||||
new File(getDataFolder(), fwdCfg.getString("pluginMessaging.file.name")),
|
||||
fwdCfg.getInt("pluginMessaging.file.cacheTime", -1));
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.SEVERE, "Unload to load file cache. Votes will be lost!", e);
|
||||
}
|
||||
@@ -292,10 +294,22 @@ public class NuVotifier extends Plugin implements VoteHandler, VotifierPlugin {
|
||||
getLogger().info("Address " + section.getString("address") + " couldn't be looked up. Ignoring!");
|
||||
continue;
|
||||
}
|
||||
ProxyForwardingVoteSource.BackendServer server = new ProxyForwardingVoteSource.BackendServer(s,
|
||||
new InetSocketAddress(address, section.getShort("port")),
|
||||
KeyCreator.createKeyFrom(section.getString("token",section.getString("key"))));
|
||||
serverList.add(server);
|
||||
|
||||
Key token = null;
|
||||
try {
|
||||
token = KeyCreator.createKeyFrom(section.getString("token", section.getString("key")));
|
||||
} catch (IllegalArgumentException e) {
|
||||
getLogger().log(Level.SEVERE,
|
||||
"An exception occurred while attempting to add proxy target '" + s + "' - maybe your token is wrong? " +
|
||||
"Votes will not be forwarded to this server!", e);
|
||||
}
|
||||
|
||||
if (token != null) {
|
||||
ProxyForwardingVoteSource.BackendServer server = new ProxyForwardingVoteSource.BackendServer(s,
|
||||
new InetSocketAddress(address, section.getShort("port")),
|
||||
token);
|
||||
serverList.add(server);
|
||||
}
|
||||
}
|
||||
|
||||
forwardingMethod = new ProxyForwardingVoteSource(this, serverGroup, serverList, null);
|
||||
@@ -321,12 +335,12 @@ public class NuVotifier extends Plugin implements VoteHandler, VotifierPlugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Channel channel, final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
getLogger().info("Got a protocol v1 vote record -> " + vote);
|
||||
getLogger().info("Got a protocol v1 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
} else {
|
||||
getLogger().info("Got a protocol v2 vote record -> " + vote);
|
||||
getLogger().info("Got a protocol v2 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package com.vexsoftware.votifier.bungee.forwarding;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import com.vexsoftware.votifier.bungee.forwarding.cache.FileVoteCache;
|
||||
import com.vexsoftware.votifier.bungee.forwarding.cache.VoteCache;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class AbstractPluginMessagingForwardingSource implements ForwardingVoteSource {
|
||||
|
||||
public AbstractPluginMessagingForwardingSource(String channel, List<String> ignoredServers, NuVotifier nuVotifier, VoteCache cache) {
|
||||
ProxyServer.getInstance().registerChannel(channel);
|
||||
this.channel = channel;
|
||||
this.nuVotifier = nuVotifier;
|
||||
this.cache = cache;
|
||||
this.ignoredServers = ignoredServers;
|
||||
}
|
||||
|
||||
protected AbstractPluginMessagingForwardingSource(String channel, NuVotifier nuVotifier, VoteCache voteCache) {
|
||||
this(channel, null, nuVotifier, voteCache);
|
||||
}
|
||||
|
||||
protected final NuVotifier nuVotifier;
|
||||
protected final String channel;
|
||||
protected final VoteCache cache;
|
||||
protected final List<String> ignoredServers;
|
||||
|
||||
@Override
|
||||
public void forward(Vote v) {
|
||||
byte[] rawData = v.serialize().toString().getBytes(StandardCharsets.UTF_8);
|
||||
for (ServerInfo s : ProxyServer.getInstance().getServers().values()) {
|
||||
if (ignoredServers != null && ignoredServers.contains(s.getName())) continue;
|
||||
if (!forwardSpecific(s, rawData)) attemptToAddToCache(v, s.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean forwardSpecific(ServerInfo connection, Vote vote) {
|
||||
byte[] rawData = vote.serialize().toString().getBytes(StandardCharsets.UTF_8);
|
||||
return connection.sendData(channel, rawData, false);
|
||||
}
|
||||
|
||||
private boolean forwardSpecific(ServerInfo connection, byte[] data) {
|
||||
return connection.sendData(channel, data, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void halt() {
|
||||
ProxyServer.getInstance().unregisterChannel(channel);
|
||||
|
||||
if (cache != null && cache instanceof FileVoteCache) {
|
||||
try {
|
||||
((FileVoteCache) cache).halt();
|
||||
} catch (IOException e) {
|
||||
nuVotifier.getLogger().log(Level.SEVERE, "Unable to save cached votes, votes will be lost.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleServerConnected(final ServerConnectedEvent e) {
|
||||
if (cache == null) return;
|
||||
final String serverName = e.getServer().getInfo().getName();
|
||||
final Collection<Vote> cachedVotes = cache.evict(serverName);
|
||||
final Collection<Vote> failedVotes = dumpVotesToServer(cachedVotes, e.getServer().getInfo(), "server '" + serverName + "'");
|
||||
for (Vote v : failedVotes)
|
||||
cache.addToCache(v, serverName);
|
||||
}
|
||||
|
||||
protected void attemptToAddToCache(Vote v, String server) {
|
||||
if (cache != null) {
|
||||
cache.addToCache(v, server);
|
||||
if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().info("Added to forwarding cache: " + v + " -> " + server);
|
||||
} else if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().severe("Could not immediately send vote to backend, vote lost! " + v + " -> " + server);
|
||||
}
|
||||
|
||||
protected void attempToAddToPlayerCache(Vote v, String player) {
|
||||
if (cache != null) {
|
||||
cache.addToCachePlayer(v, player);
|
||||
if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().info("Added to forwarding cache: " + v + " -> (player) " + player);
|
||||
} else if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().severe("Could not immediately send vote to backend, vote lost! " + v + " -> (player) " + player);
|
||||
|
||||
}
|
||||
|
||||
// returns a collection of failed votes
|
||||
private Collection<Vote> dumpVotesToServer(Collection<Vote> cachedVotes, ServerInfo target, String identifier) {
|
||||
List<Vote> failures = new ArrayList<>();
|
||||
|
||||
if (!cachedVotes.isEmpty()) {
|
||||
nuVotifier.getProxy().getScheduler().schedule(nuVotifier, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int evicted = 0;
|
||||
int unsuccessfulEvictions = 0;
|
||||
for (Vote v : cachedVotes) {
|
||||
if (forwardSpecific(target, v)) {
|
||||
evicted++;
|
||||
} else {
|
||||
// Re-add to cache to send later.
|
||||
failures.add(v);
|
||||
unsuccessfulEvictions++;
|
||||
}
|
||||
}
|
||||
if (nuVotifier.isDebug()) {
|
||||
nuVotifier.getLogger().info("Successfully evicted " + evicted + " votes to " + identifier + ".");
|
||||
if (unsuccessfulEvictions > 0) {
|
||||
nuVotifier.getLogger().info("Held " + unsuccessfulEvictions + " votes for " + identifier + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
protected void handlePlayerSwitch(ServerConnectedEvent e) {
|
||||
if (cache == null) return;
|
||||
if (ignoredServers != null && ignoredServers.contains(e.getServer().getInfo().getName())) return;
|
||||
|
||||
String playerName = e.getPlayer().getName();
|
||||
|
||||
final Collection<Vote> cachedVotes = cache.evictPlayer(playerName);
|
||||
final Collection<Vote> failedVotes = dumpVotesToServer(cachedVotes, e.getServer().getInfo(), "player '" + playerName);
|
||||
for (Vote v : failedVotes)
|
||||
cache.addToCachePlayer(v, playerName);
|
||||
}
|
||||
}
|
||||
+14
-3
@@ -8,16 +8,18 @@ import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
/**
|
||||
* @author Joseph Hirschfeld
|
||||
* @date 12/31/2015
|
||||
*/
|
||||
public final class OnlineForwardPluginMessagingForwardingSource extends PluginMessagingForwardingSource {
|
||||
public final class OnlineForwardPluginMessagingForwardingSource extends AbstractPluginMessagingForwardingSource implements Listener {
|
||||
public OnlineForwardPluginMessagingForwardingSource(String channel, NuVotifier nuVotifier, VoteCache cache, String fallbackServer) {
|
||||
super(channel, nuVotifier, cache);
|
||||
this.fallbackServer = fallbackServer;
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
}
|
||||
|
||||
private final String fallbackServer;
|
||||
@@ -27,9 +29,13 @@ public final class OnlineForwardPluginMessagingForwardingSource extends PluginMe
|
||||
ProxiedPlayer p = ProxyServer.getInstance().getPlayer(v.getUsername());
|
||||
if (p == null || !forwardSpecific(p.getServer().getInfo(), v)) {
|
||||
ServerInfo serverInfo = ProxyServer.getInstance().getServers().get(fallbackServer);
|
||||
if (serverInfo == null || !forwardSpecific(serverInfo, v)) {
|
||||
|
||||
// nowhere to fall back to, yet still not online. lets save this vote yet!
|
||||
if (serverInfo == null)
|
||||
attempToAddToPlayerCache(v, v.getUsername());
|
||||
|
||||
else if (!forwardSpecific(serverInfo, v))
|
||||
attemptToAddToCache(v, fallbackServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,4 +50,9 @@ public final class OnlineForwardPluginMessagingForwardingSource extends PluginMe
|
||||
public void onServerConnected(final ServerConnectedEvent e) { //Attempt to resend any votes that were previously cached.
|
||||
handleServerConnected(e);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerSwitch(ServerConnectedEvent e) {
|
||||
handlePlayerSwitch(e);
|
||||
}
|
||||
}
|
||||
+4
-93
@@ -1,75 +1,25 @@
|
||||
package com.vexsoftware.votifier.bungee.forwarding;
|
||||
|
||||
import com.vexsoftware.votifier.bungee.NuVotifier;
|
||||
import com.vexsoftware.votifier.bungee.forwarding.cache.FileVoteCache;
|
||||
import com.vexsoftware.votifier.bungee.forwarding.cache.VoteCache;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Created by Joe Hirschfeld on 10/20/2015.
|
||||
*/
|
||||
public class PluginMessagingForwardingSource implements ForwardingVoteSource, Listener {
|
||||
public class PluginMessagingForwardingSource extends AbstractPluginMessagingForwardingSource implements Listener {
|
||||
|
||||
public PluginMessagingForwardingSource(String channel, List<String> ignoredServers, NuVotifier nuVotifier, VoteCache cache) {
|
||||
ProxyServer.getInstance().registerChannel(channel);
|
||||
super(channel, ignoredServers, nuVotifier, cache);
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
this.channel = channel;
|
||||
this.nuVotifier = nuVotifier;
|
||||
this.cache = cache;
|
||||
this.ignoredServers = ignoredServers;
|
||||
}
|
||||
|
||||
protected PluginMessagingForwardingSource(String channel, NuVotifier nuVotifier, VoteCache voteCache) {
|
||||
this(channel, null, nuVotifier, voteCache);
|
||||
}
|
||||
|
||||
protected final NuVotifier nuVotifier;
|
||||
protected final String channel;
|
||||
protected final VoteCache cache;
|
||||
protected final List<String> ignoredServers;
|
||||
|
||||
@Override
|
||||
public void forward(Vote v) {
|
||||
byte[] rawData = v.serialize().toString().getBytes(StandardCharsets.UTF_8);
|
||||
for (ServerInfo s : ProxyServer.getInstance().getServers().values()) {
|
||||
if (ignoredServers != null && ignoredServers.contains(s.getName())) continue;
|
||||
if (!forwardSpecific(s, rawData)) attemptToAddToCache(v, s.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean forwardSpecific(ServerInfo connection, Vote vote) {
|
||||
byte[] rawData = vote.serialize().toString().getBytes(StandardCharsets.UTF_8);
|
||||
return connection.sendData(channel, rawData, false);
|
||||
}
|
||||
|
||||
private boolean forwardSpecific(ServerInfo connection, byte[] data) {
|
||||
return connection.sendData(channel, data, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void halt() {
|
||||
ProxyServer.getInstance().unregisterChannel(channel);
|
||||
|
||||
if (cache != null && cache instanceof FileVoteCache) {
|
||||
try {
|
||||
((FileVoteCache) cache).halt();
|
||||
} catch (IOException e) {
|
||||
nuVotifier.getLogger().log(Level.SEVERE, "Unable to save cached votes, votes will be lost.", e);
|
||||
}
|
||||
}
|
||||
super(channel, nuVotifier, voteCache);
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(nuVotifier, this);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -81,43 +31,4 @@ public class PluginMessagingForwardingSource implements ForwardingVoteSource, Li
|
||||
public void onServerConnected(final ServerConnectedEvent e) { //Attempt to resend any votes that were previously cached.
|
||||
handleServerConnected(e);
|
||||
}
|
||||
|
||||
protected void handleServerConnected(final ServerConnectedEvent e) {
|
||||
if (cache == null) return;
|
||||
final String serverName = e.getServer().getInfo().getName();
|
||||
final Collection<Vote> cachedVotes = cache.evict(serverName);
|
||||
if (!cachedVotes.isEmpty()) {
|
||||
nuVotifier.getProxy().getScheduler().schedule(nuVotifier, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int evicted = 0;
|
||||
int unsuccessfulEvictions = 0;
|
||||
for (Vote v : cachedVotes) {
|
||||
if (forwardSpecific(e.getServer().getInfo(), v)) {
|
||||
evicted++;
|
||||
} else {
|
||||
// Re-add to cache to send later.
|
||||
cache.addToCache(v, serverName);
|
||||
unsuccessfulEvictions++;
|
||||
}
|
||||
}
|
||||
if (nuVotifier.isDebug()) {
|
||||
nuVotifier.getLogger().info("Successfully evicted " + evicted + " votes to server '" + serverName + "'.");
|
||||
if (unsuccessfulEvictions > 0) {
|
||||
nuVotifier.getLogger().info("Held " + unsuccessfulEvictions + " votes for server '" + serverName + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
protected void attemptToAddToCache(Vote v, String server) {
|
||||
if (cache != null) {
|
||||
cache.addToCache(v, server);
|
||||
if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().info("Added to forwarding cache: " + v + " -> " + server);
|
||||
} else if (nuVotifier.isDebug())
|
||||
nuVotifier.getLogger().severe("Could not immediately send vote to backend, vote lost! " + v + " -> " + server);
|
||||
}
|
||||
}
|
||||
Vendored
+114
-34
@@ -7,26 +7,28 @@ import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class FileVoteCache extends MemoryVoteCache {
|
||||
|
||||
private final Logger l;
|
||||
private final File cacheFile;
|
||||
private final int voteTTL;
|
||||
private final ScheduledTask saveTask;
|
||||
|
||||
public FileVoteCache(int initialMemorySize, final Plugin plugin, File cacheFile) throws IOException {
|
||||
public FileVoteCache(int initialMemorySize, final Plugin plugin, File cacheFile, int voteTTL) throws IOException {
|
||||
super(initialMemorySize);
|
||||
this.cacheFile = cacheFile;
|
||||
this.voteTTL = voteTTL;
|
||||
this.l = plugin.getLogger();
|
||||
|
||||
load();
|
||||
|
||||
saveTask = ProxyServer.getInstance().getScheduler().schedule(plugin, new Runnable() {
|
||||
@@ -35,53 +37,131 @@ public class FileVoteCache extends MemoryVoteCache {
|
||||
try {
|
||||
save();
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Unable to save cached votes, votes will be lost if you restart.", e);
|
||||
l.log(Level.SEVERE, "Unable to save cached votes, votes will be lost if you restart.", e);
|
||||
}
|
||||
}
|
||||
}, 3, 3, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private void load() throws IOException {
|
||||
if (cacheFile.exists()) {
|
||||
// Load the cache from disk
|
||||
JSONObject object = new JSONObject(Files.toString(cacheFile, StandardCharsets.UTF_8));
|
||||
|
||||
// Deserialize all votes contained
|
||||
for (Object server : object.keySet()) {
|
||||
JSONArray voteArray = object.optJSONArray(((String) server));
|
||||
if (voteArray == null) continue;
|
||||
Set<Vote> votes = new LinkedHashSet<>(voteArray.length());
|
||||
for (int i = 0; i < voteArray.length(); i++) {
|
||||
votes.add(new Vote(voteArray.getJSONObject(i)));
|
||||
}
|
||||
voteCache.put(((String) server), votes);
|
||||
}
|
||||
} else {
|
||||
cacheFile.createNewFile();
|
||||
// Load the cache from disk
|
||||
JSONObject object;
|
||||
try (BufferedReader reader = Files.newReader(cacheFile, StandardCharsets.UTF_8)) {
|
||||
object = new JSONObject(new JSONTokener(reader));
|
||||
} catch (FileNotFoundException e) {
|
||||
object = new JSONObject();
|
||||
}
|
||||
|
||||
boolean resave = false;
|
||||
|
||||
// First, lets figure out if we are converting from a pre2.3.6 cache
|
||||
if (!object.has("players") || !object.has("servers") || !object.has("version") || object.length() != 3) {
|
||||
JSONObject oldObject = object;
|
||||
object = new JSONObject();
|
||||
object.put("servers", oldObject);
|
||||
object.put("players", new JSONObject());
|
||||
object.put("version", 2);
|
||||
resave = true;
|
||||
}
|
||||
|
||||
if (object.getInt("version") != 2)
|
||||
throw new IllegalStateException("Could not read cache file! Unknown version '" + object.getInt("version") + "' read.");
|
||||
|
||||
JSONObject players = object.getJSONObject("players");
|
||||
JSONObject servers = object.getJSONObject("servers");
|
||||
|
||||
for (Object player : players.keySet()) {
|
||||
playerVoteCache.put(((String) player), readVotes(players.getJSONArray((String) player)));
|
||||
}
|
||||
|
||||
for (Object server : servers.keySet()) {
|
||||
voteCache.put(((String) server), readVotes(players.getJSONArray((String) server)));
|
||||
}
|
||||
|
||||
if (resave) {
|
||||
File replacementFile;
|
||||
for (int i = 0; ; i++) {
|
||||
replacementFile = new File(cacheFile.getParentFile(), cacheFile.getName() + ".bak." + i);
|
||||
if (!replacementFile.exists())
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cacheFile.renameTo(replacementFile)) {
|
||||
l.log(Level.SEVERE, "Backup movement failed! Will not save.");
|
||||
return;
|
||||
}
|
||||
|
||||
l.log(Level.WARNING, "Saving new vote cache format to file - backup moved to " + replacementFile.getAbsolutePath());
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Vote> readVotes(JSONArray voteArray) {
|
||||
List<Vote> votes = new ArrayList<>(voteArray.length());
|
||||
for (int i = 0; i < voteArray.length(); i++) {
|
||||
JSONObject voteObject = voteArray.getJSONObject(i);
|
||||
Vote v = new Vote(voteObject);
|
||||
if (hasTimedOut(v))
|
||||
l.log(Level.WARNING, "Purging out of date vote.", v);
|
||||
else
|
||||
votes.add(v);
|
||||
}
|
||||
return votes;
|
||||
}
|
||||
|
||||
public void save() throws IOException {
|
||||
cacheLock.lock();
|
||||
// Create a copy of the votes.
|
||||
JSONObject votesObject = new JSONObject();
|
||||
for (Map.Entry<String, Collection<Vote>> entry : voteCache.entrySet()) {
|
||||
JSONArray array = new JSONArray();
|
||||
for (Vote vote : entry.getValue()) {
|
||||
array.put(vote.serialize());
|
||||
}
|
||||
votesObject.put(entry.getKey(), array);
|
||||
votesObject.put("version", 2);
|
||||
try {
|
||||
votesObject.put("players", serializeMap(playerVoteCache));
|
||||
votesObject.put("servers", serializeMap(voteCache));
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
cacheLock.unlock();
|
||||
|
||||
try (BufferedWriter writer = Files.newWriter(cacheFile, StandardCharsets.UTF_8)) {
|
||||
votesObject.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject serializeMap(Map<String, Collection<Vote>> map) {
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
Iterator<Map.Entry<String, Collection<Vote>>> entryItr = map.entrySet().iterator();
|
||||
while (entryItr.hasNext()) {
|
||||
Map.Entry<String, Collection<Vote>> entry = entryItr.next();
|
||||
JSONArray array = new JSONArray();
|
||||
Iterator<Vote> voteItr = entry.getValue().iterator();
|
||||
while (voteItr.hasNext()) {
|
||||
Vote vote = voteItr.next();
|
||||
|
||||
// if the vote is no longer valid, notify and remove
|
||||
if (hasTimedOut(vote)) {
|
||||
l.log(Level.WARNING, "Purging out of date vote.", vote);
|
||||
voteItr.remove();
|
||||
} else {
|
||||
array.put(vote.serialize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if, during our iteration, we TTL invalidated all of the votes
|
||||
if (entry.getValue().isEmpty())
|
||||
entryItr.remove();
|
||||
o.put(entry.getKey(), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
private boolean hasTimedOut(Vote v) {
|
||||
if (voteTTL == -1) return false;
|
||||
// scale voteTTL to milliseconds
|
||||
return v.getLocalTimestamp() + voteTTL * 24 * 60 * 60 * 1000 < System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void halt() throws IOException {
|
||||
saveTask.cancel();
|
||||
save();
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+54
-13
@@ -1,6 +1,6 @@
|
||||
package com.vexsoftware.votifier.bungee.forwarding.cache;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.util.*;
|
||||
@@ -13,37 +13,78 @@ public class MemoryVoteCache implements VoteCache {
|
||||
|
||||
public MemoryVoteCache(int initialSize) {
|
||||
voteCache = new HashMap<>(initialSize);
|
||||
this.playerVoteCache = new HashMap<>();
|
||||
}
|
||||
|
||||
protected final Map<String, Collection<Vote>> voteCache;
|
||||
|
||||
protected final Map<String, Collection<Vote>> playerVoteCache;
|
||||
|
||||
protected final ReentrantLock cacheLock = new ReentrantLock();
|
||||
|
||||
@Override
|
||||
public Collection<String> getCachedServers() {
|
||||
cacheLock.lock();
|
||||
Set<String> servers = ImmutableSet.copyOf(voteCache.keySet());
|
||||
cacheLock.unlock();
|
||||
return servers;
|
||||
try {
|
||||
return ImmutableList.copyOf(voteCache.keySet());
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToCache(Vote v, String server) {
|
||||
if (server == null) throw new NullPointerException();
|
||||
cacheLock.lock();
|
||||
Collection<Vote> voteCollection = voteCache.get(server);
|
||||
if (voteCollection == null) {
|
||||
voteCollection = new LinkedHashSet<>();
|
||||
voteCache.put(server, voteCollection);
|
||||
try {
|
||||
Collection<Vote> voteCollection = voteCache.get(server);
|
||||
if (voteCollection == null) {
|
||||
voteCollection = new ArrayList<>();
|
||||
voteCache.put(server, voteCollection);
|
||||
}
|
||||
voteCollection.add(v);
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToCachePlayer(Vote v, String player) {
|
||||
if (player == null) throw new NullPointerException();
|
||||
cacheLock.lock();
|
||||
try {
|
||||
Collection<Vote> voteCollection = playerVoteCache.get(player);
|
||||
if (voteCollection == null) {
|
||||
voteCollection = new ArrayList<>();
|
||||
playerVoteCache.put(player, voteCollection);
|
||||
}
|
||||
voteCollection.add(v);
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Vote> evictPlayer(String player) {
|
||||
if (player == null) throw new NullPointerException();
|
||||
cacheLock.lock();
|
||||
try {
|
||||
Collection<Vote> fromCollection = playerVoteCache.remove(player);
|
||||
return fromCollection != null ? fromCollection : ImmutableList.of();
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
voteCollection.add(v);
|
||||
cacheLock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Vote> evict(String server) {
|
||||
if (server == null) throw new NullPointerException();
|
||||
cacheLock.lock();
|
||||
Collection<Vote> fromCollection = voteCache.remove(server);
|
||||
cacheLock.unlock();
|
||||
return fromCollection != null ? ImmutableSet.copyOf(fromCollection) : ImmutableSet.<Vote>of();
|
||||
try {
|
||||
Collection<Vote> fromCollection = voteCache.remove(server);
|
||||
return fromCollection != null ? fromCollection : ImmutableList.of();
|
||||
} finally {
|
||||
cacheLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -3,6 +3,7 @@ package com.vexsoftware.votifier.bungee.forwarding.cache;
|
||||
import com.vexsoftware.votifier.model.Vote;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Represents a method of caching votes for forwarding to a server that it was not previously capable of sending.
|
||||
@@ -24,6 +25,16 @@ public interface VoteCache {
|
||||
*/
|
||||
void addToCache(Vote v, String server);
|
||||
|
||||
/**
|
||||
* Adds a vote to the vote cache for later sending, specifically keyed to a player. This is for the instance when the
|
||||
* player is rewarded, however is not online any servers able to recieve said vote.
|
||||
*
|
||||
* @param v Vote to add to the cache
|
||||
* @param player Server to add vote under
|
||||
*/
|
||||
default void addToCachePlayer(Vote v, String player) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Evicts all votes from the vote cache and returns a collection of vote objects
|
||||
*
|
||||
@@ -31,4 +42,15 @@ public interface VoteCache {
|
||||
* @return A collection of all votes which were previously in the cache under the server
|
||||
*/
|
||||
Collection<Vote> evict(String server);
|
||||
|
||||
/**
|
||||
* Evicts all votes from the vote cache for a specific player not assigned to a server and returns a collection of
|
||||
* vote objects
|
||||
*
|
||||
* @param player Player name of the votes to evict from the cache
|
||||
* @return A collection of all votes which were previously in the cache under the player
|
||||
*/
|
||||
default Collection<Vote> evictPlayer(String player) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -7,9 +7,9 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
|
||||
public class VotifierProtocol2Encoder extends MessageToByteEncoder<VoteRequest> {
|
||||
private static final short MAGIC = 0x733A;
|
||||
@@ -32,7 +32,7 @@ public class VotifierProtocol2Encoder extends MessageToByteEncoder<VoteRequest>
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(key);
|
||||
mac.update(payload.getBytes(StandardCharsets.UTF_8));
|
||||
String computed = DatatypeConverter.printBase64Binary(mac.doFinal());
|
||||
String computed = Base64.getEncoder().encodeToString(mac.doFinal());
|
||||
object.put("signature", computed);
|
||||
|
||||
// JSON message is ready for encoding.
|
||||
|
||||
@@ -53,6 +53,8 @@ forwarding:
|
||||
# Options for file caching.
|
||||
file:
|
||||
name: cached-votes.json
|
||||
# days before a vote is considered 'dead' - removed from cache with a console warning
|
||||
voteTTL: 10
|
||||
# Specify servers to proxy votes for.
|
||||
proxy:
|
||||
Hub:
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>4.0.31.Final</version>
|
||||
<version>4.1.16.Final</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.vexsoftware.votifier.net.VotifierSession;
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
public interface VoteHandler {
|
||||
void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception;
|
||||
void onVoteReceived(Channel channel, Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception;
|
||||
|
||||
void onError(Channel channel, Throwable throwable);
|
||||
}
|
||||
@@ -47,15 +47,26 @@ public class Vote {
|
||||
*/
|
||||
private String timeStamp;
|
||||
|
||||
/**
|
||||
* Timestamp (unix-millis) normalized and taken from a known source
|
||||
*/
|
||||
private final long localTimestamp;
|
||||
|
||||
@Deprecated
|
||||
public Vote() {
|
||||
localTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp) {
|
||||
this(serviceName, username, address, timeStamp, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public Vote(String serviceName, String username, String address, String timeStamp, long localTimestamp) {
|
||||
this.serviceName = serviceName;
|
||||
this.username = username;
|
||||
this.address = address;
|
||||
this.timeStamp = timeStamp;
|
||||
this.localTimestamp = localTimestamp;
|
||||
}
|
||||
|
||||
private static String getTimestamp(JSONObject object) {
|
||||
@@ -67,13 +78,19 @@ public class Vote {
|
||||
}
|
||||
|
||||
public Vote(JSONObject jsonObject) {
|
||||
this(jsonObject.getString("serviceName"), jsonObject.getString("username"), jsonObject.getString("address"), getTimestamp(jsonObject));
|
||||
this(jsonObject.getString("serviceName"),
|
||||
jsonObject.getString("username"),
|
||||
jsonObject.getString("address"),
|
||||
getTimestamp(jsonObject),
|
||||
// maintained for backwards compatibility with <2.3.6 peers
|
||||
(jsonObject.has("localTimestamp") ? jsonObject.getLong("localTimestamp") : System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Vote (from:" + serviceName + " username:" + username
|
||||
+ " address:" + address + " timeStamp:" + timeStamp + ")";
|
||||
+ " address:" + address + " timeStamp:" + timeStamp
|
||||
+ " localTimestamp:" + localTimestamp + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,12 +169,22 @@ public class Vote {
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local timestamp, in unix-millis. Calculated locally by a NuVotifier instance
|
||||
*
|
||||
* @return The local timestamp
|
||||
*/
|
||||
public long getLocalTimestamp() {
|
||||
return localTimestamp;
|
||||
}
|
||||
|
||||
public JSONObject serialize() {
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("serviceName", serviceName);
|
||||
ret.put("username", username);
|
||||
ret.put("address", address);
|
||||
ret.put("timestamp", timeStamp);
|
||||
ret.put("localTimestamp", localTimestamp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -172,7 +199,6 @@ public class Vote {
|
||||
if (!username.equals(vote.username)) return false;
|
||||
if (!address.equals(vote.address)) return false;
|
||||
return timeStamp.equals(vote.timeStamp);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ public class VoteInboundHandler extends SimpleChannelInboundHandler<Vote> {
|
||||
protected void channelRead0(ChannelHandlerContext ctx, final Vote vote) throws Exception {
|
||||
VotifierSession session = ctx.channel().attr(VotifierSession.KEY).get();
|
||||
|
||||
handler.onVoteReceived(vote, session.getVersion());
|
||||
handler.onVoteReceived(ctx.channel(), vote, session.getVersion());
|
||||
|
||||
if (session.getVersion() == VotifierSession.ProtocolVersion.ONE) {
|
||||
ctx.close();
|
||||
|
||||
+4
-7
@@ -10,13 +10,10 @@ import org.json.JSONObject;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -52,7 +49,7 @@ public class VotifierProtocol2Decoder extends MessageToMessageDecoder<String> {
|
||||
|
||||
// Verify signature.
|
||||
String sigHash = voteMessage.getString("signature");
|
||||
byte[] sigBytes = DatatypeConverter.parseBase64Binary(sigHash);
|
||||
byte[] sigBytes = Base64.getDecoder().decode(sigHash);
|
||||
|
||||
if (!hmacEqual(sigBytes, voteMessage.getString("payload").getBytes(StandardCharsets.UTF_8), key)) {
|
||||
throw new CorruptedFrameException("Signature is not valid (invalid token?)");
|
||||
@@ -92,6 +89,6 @@ public class VotifierProtocol2Decoder extends MessageToMessageDecoder<String> {
|
||||
mac2.reset();
|
||||
byte[] realSig = mac2.doFinal(calculatedSig);
|
||||
|
||||
return Arrays.equals(clientSig, realSig);
|
||||
return MessageDigest.isEqual(clientSig, realSig);
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
package com.vexsoftware.votifier.net.protocol.v1crypto;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.util.Base64;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
@@ -45,21 +46,17 @@ public class RSAIO {
|
||||
PrivateKey privateKey = keyPair.getPrivate();
|
||||
PublicKey publicKey = keyPair.getPublic();
|
||||
|
||||
// Store the public key.
|
||||
// Store the public and private keys.
|
||||
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(
|
||||
publicKey.getEncoded());
|
||||
FileOutputStream out = new FileOutputStream(directory + "/public.key");
|
||||
out.write(DatatypeConverter.printBase64Binary(publicSpec.getEncoded())
|
||||
.getBytes());
|
||||
out.close();
|
||||
|
||||
// Store the private key.
|
||||
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(
|
||||
privateKey.getEncoded());
|
||||
out = new FileOutputStream(directory + "/private.key");
|
||||
out.write(DatatypeConverter.printBase64Binary(privateSpec.getEncoded())
|
||||
.getBytes());
|
||||
out.close();
|
||||
try (FileOutputStream publicOut = new FileOutputStream(directory + "/public.key");
|
||||
FileOutputStream privateOut = new FileOutputStream(directory + "/private.key")) {
|
||||
|
||||
publicOut.write(Base64.getEncoder().encode(publicSpec.getEncoded()));
|
||||
privateOut.write(Base64.getEncoder().encode(privateSpec.getEncoded()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,14 +71,12 @@ public class RSAIO {
|
||||
// Read the public key file.
|
||||
File publicKeyFile = new File(directory + "/public.key");
|
||||
byte[] encodedPublicKey = Files.readAllBytes(publicKeyFile.toPath());
|
||||
encodedPublicKey = DatatypeConverter.parseBase64Binary(new String(
|
||||
encodedPublicKey));
|
||||
encodedPublicKey = Base64.getDecoder().decode(new String(encodedPublicKey, StandardCharsets.UTF_8));
|
||||
|
||||
// Read the private key file.
|
||||
File privateKeyFile = new File(directory + "/private.key");
|
||||
byte[] encodedPrivateKey = Files.readAllBytes(privateKeyFile.toPath());
|
||||
encodedPrivateKey = DatatypeConverter.parseBase64Binary(new String(
|
||||
encodedPrivateKey));
|
||||
encodedPrivateKey = Base64.getDecoder().decode(new String(encodedPrivateKey, StandardCharsets.UTF_8));
|
||||
|
||||
// Instantiate and return the key pair.
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
|
||||
+2
-2
@@ -74,11 +74,11 @@ public class StandaloneVotifierPlugin implements VotifierPlugin, VoteHandler {
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "2.3.2.2";
|
||||
return "2.3.5";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Channel channel, Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
receiver.onVote(vote);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -7,6 +7,7 @@ import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.RSAKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -27,6 +28,9 @@ public class VotifierServerBuilder {
|
||||
|
||||
public VotifierServerBuilder v1Key(KeyPair v1Key) {
|
||||
this.v1Key = Objects.requireNonNull(v1Key, "v1Key");
|
||||
if (!(v1Key.getPrivate() instanceof RSAKey)) {
|
||||
throw new IllegalArgumentException("Provided key is not an RSA key.");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.vexsoftware.votifier.net.protocol;
|
||||
import com.vexsoftware.votifier.VotifierPlugin;
|
||||
import com.vexsoftware.votifier.util.KeyCreator;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -12,6 +11,7 @@ import java.nio.file.Paths;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -23,7 +23,7 @@ public class TestVotifierPlugin implements VotifierPlugin {
|
||||
URL resourceUrl = TestVotifierPlugin.class.getResource(u);
|
||||
Path resourcePath = Paths.get(resourceUrl.toURI());
|
||||
|
||||
return DatatypeConverter.parseBase64Binary(new String(Files.readAllBytes(resourcePath), StandardCharsets.UTF_8));
|
||||
return Base64.getDecoder().decode(new String(Files.readAllBytes(resourcePath), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
+4
-4
@@ -11,9 +11,9 @@ import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class VotifierProtocol2DecoderTest {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(key);
|
||||
object.put("signature",
|
||||
DatatypeConverter.printBase64Binary(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
Base64.getEncoder().encodeToString(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
if (expectSuccess) {
|
||||
assertTrue(channel.writeInbound(object.toString()));
|
||||
@@ -90,7 +90,7 @@ public class VotifierProtocol2DecoderTest {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(TestVotifierPlugin.getI().getTokens().get("default"));
|
||||
object.put("signature",
|
||||
DatatypeConverter.printBase64Binary(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
Base64.getEncoder().encodeToString(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
@@ -113,7 +113,7 @@ public class VotifierProtocol2DecoderTest {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(TestVotifierPlugin.getI().getTokens().get("default"));
|
||||
object.put("signature",
|
||||
DatatypeConverter.printBase64Binary(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
Base64.getEncoder().encode(mac.doFinal(payload.toString().getBytes(StandardCharsets.UTF_8))));
|
||||
|
||||
try {
|
||||
channel.writeInbound(object.toString());
|
||||
|
||||
-5
@@ -25,7 +25,6 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
test.release();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@@ -41,7 +40,6 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.TWO, session.getVersion());
|
||||
test.release();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@@ -59,7 +57,6 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
channel.writeInbound(test);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
test.release();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@@ -75,7 +72,6 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
try {
|
||||
channel.writeInbound(buf);
|
||||
} finally {
|
||||
buf.release();
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
@@ -94,7 +90,6 @@ public class VotifierProtocolDifferentiatorTest {
|
||||
channel.writeInbound(encryptedByteBuf);
|
||||
|
||||
assertEquals(VotifierSession.ProtocolVersion.ONE, session.getVersion());
|
||||
encryptedByteBuf.release();
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
<modules>
|
||||
<module>common</module>
|
||||
<module>bukkit</module>
|
||||
@@ -23,20 +23,17 @@
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>bukkit</id>
|
||||
<url>http://repo.bukkit.org/content/groups/public/</url>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>minimumio-repo</id>
|
||||
<url>http://repo.minimum.io/content/repositories/releases/</url>
|
||||
<id>bintray-nuvotifier-maven</id>
|
||||
<name>nuvotifier-maven</name>
|
||||
<url>https://api.bintray.com/maven/nuvotifier/maven/NuVotifier/;publish=1</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>minimumio-repo-snapshots</id>
|
||||
<url>http://repo.minimum.io/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<build>
|
||||
@@ -48,8 +45,8 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
+15
-2
@@ -5,12 +5,17 @@
|
||||
<parent>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>nuvotifier-sponge</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge-maven-repo</id>
|
||||
@@ -37,6 +42,14 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -50,7 +63,7 @@
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>4.0.1</version>
|
||||
<version>7.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -33,8 +33,6 @@ import org.slf4j.Logger;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.cause.Cause;
|
||||
import org.spongepowered.api.event.cause.NamedCause;
|
||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
@@ -53,7 +51,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "2.3.2.2")
|
||||
@Plugin(id = "nuvotifier", name = "NuVotifier", version = "2.3.5")
|
||||
public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.VotifierPlugin, ForwardedVoteListener {
|
||||
private Logger logger;
|
||||
@Inject
|
||||
@@ -163,87 +161,81 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.Vot
|
||||
|
||||
debug = node.getNode("debug").getBoolean(false);
|
||||
|
||||
boolean setUpPort = node.getNode("enableExternal").getBoolean(true); //Always default to running the external port
|
||||
// Load Votifier tokens.
|
||||
ConfigurationNode tokenSection = node.getNode("tokens");
|
||||
|
||||
if (setUpPort) {
|
||||
// Load Votifier tokens.
|
||||
ConfigurationNode tokenSection = node.getNode("tokens");
|
||||
|
||||
if (tokenSection.hasMapChildren()) {
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> entry : tokenSection.getChildrenMap().entrySet()) {
|
||||
if (entry.getKey() instanceof String) {
|
||||
tokens.put((String) entry.getKey(), KeyCreator.createKeyFrom(entry.getValue().getString()));
|
||||
logger.info("Loaded token for website: " + entry.getKey());
|
||||
}
|
||||
if (tokenSection.hasMapChildren()) {
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> entry : tokenSection.getChildrenMap().entrySet()) {
|
||||
if (entry.getKey() instanceof String) {
|
||||
tokens.put((String) entry.getKey(), KeyCreator.createKeyFrom(entry.getValue().getString()));
|
||||
logger.info("Loaded token for website: " + entry.getKey());
|
||||
}
|
||||
} else {
|
||||
String token = TokenUtil.newToken();
|
||||
tokenSection.setValue(ImmutableMap.of("default", token));
|
||||
tokens.put("default", KeyCreator.createKeyFrom(token));
|
||||
try {
|
||||
loader.save(node);
|
||||
} catch (IOException e) {
|
||||
logger.error("Error generating Votifier token", e);
|
||||
gracefulExit();
|
||||
return;
|
||||
}
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
logger.info("No tokens were found in your configuration, so we've generated one for you.");
|
||||
logger.info("Your default Votifier token is " + token + ".");
|
||||
logger.info("You will need to provide this token when you submit your server to a voting");
|
||||
logger.info("list.");
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Initialize the receiver.
|
||||
final String host = node.getNode("host").getString(hostAddr);
|
||||
final int port = node.getNode("port").getInt(8192);
|
||||
if (debug)
|
||||
logger.info("DEBUG mode enabled!");
|
||||
|
||||
final boolean disablev1 = node.getNode("disable-v1-protocol").getBoolean(false);
|
||||
if (disablev1) {
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
logger.info("Votifier protocol v1 parsing has been disabled. Most voting websites do not");
|
||||
logger.info("currently support the modern Votifier protocol in NuVotifier.");
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
serverGroup = new NioEventLoopGroup(1);
|
||||
|
||||
new ServerBootstrap()
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.group(serverGroup)
|
||||
.childHandler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel channel) throws Exception {
|
||||
channel.attr(VotifierSession.KEY).set(new VotifierSession());
|
||||
channel.attr(com.vexsoftware.votifier.VotifierPlugin.KEY).set(VotifierPlugin.this);
|
||||
channel.pipeline().addLast("greetingHandler", new VotifierGreetingHandler());
|
||||
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !disablev1));
|
||||
channel.pipeline().addLast("voteHandler", new VoteInboundHandler(VotifierPlugin.this));
|
||||
}
|
||||
})
|
||||
.bind(host, port)
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
logger.info("Votifier enabled on socket "+serverChannel.localAddress()+".");
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
socketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
logger.error("Votifier was not able to bind to " + socketAddress, future.cause());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.info("You have enableExternal set to false in your config.yml. NuVotifier will NOT listen to votes coming in from an external voting list.");
|
||||
String token = TokenUtil.newToken();
|
||||
tokenSection.setValue(ImmutableMap.of("default", token));
|
||||
tokens.put("default", KeyCreator.createKeyFrom(token));
|
||||
try {
|
||||
loader.save(node);
|
||||
} catch (IOException e) {
|
||||
logger.error("Error generating Votifier token", e);
|
||||
gracefulExit();
|
||||
return;
|
||||
}
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
logger.info("No tokens were found in your configuration, so we've generated one for you.");
|
||||
logger.info("Your default Votifier token is " + token + ".");
|
||||
logger.info("You will need to provide this token when you submit your server to a voting");
|
||||
logger.info("list.");
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
// Initialize the receiver.
|
||||
final String host = node.getNode("host").getString(hostAddr);
|
||||
final int port = node.getNode("port").getInt(8192);
|
||||
if (debug)
|
||||
logger.info("DEBUG mode enabled!");
|
||||
|
||||
final boolean disablev1 = node.getNode("disable-v1-protocol").getBoolean(false);
|
||||
if (disablev1) {
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
logger.info("Votifier protocol v1 parsing has been disabled. Most voting websites do not");
|
||||
logger.info("currently support the modern Votifier protocol in NuVotifier.");
|
||||
logger.info("------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
serverGroup = new NioEventLoopGroup(1);
|
||||
|
||||
new ServerBootstrap()
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.group(serverGroup)
|
||||
.childHandler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel channel) throws Exception {
|
||||
channel.attr(VotifierSession.KEY).set(new VotifierSession());
|
||||
channel.attr(com.vexsoftware.votifier.VotifierPlugin.KEY).set(VotifierPlugin.this);
|
||||
channel.pipeline().addLast("greetingHandler", new VotifierGreetingHandler());
|
||||
channel.pipeline().addLast("protocolDifferentiator", new VotifierProtocolDifferentiator(false, !disablev1));
|
||||
channel.pipeline().addLast("voteHandler", new VoteInboundHandler(VotifierPlugin.this));
|
||||
}
|
||||
})
|
||||
.bind(host, port)
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
logger.info("Votifier enabled on socket " + serverChannel.localAddress() + ".");
|
||||
} else {
|
||||
SocketAddress socketAddress = future.channel().localAddress();
|
||||
if (socketAddress == null) {
|
||||
socketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
logger.error("Votifier was not able to bind to " + socketAddress, future.cause());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ConfigurationNode forwardingConfig = node.getNode("forwarding");
|
||||
if (forwardingConfig != null) {
|
||||
String method = forwardingConfig.getNode("method").getString("none").toLowerCase(); //Default to lower case for case-insensitive searches
|
||||
@@ -340,23 +332,22 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.Vot
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVoteReceived(final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
public void onVoteReceived(Channel channel, final Vote vote, VotifierSession.ProtocolVersion protocolVersion) throws Exception {
|
||||
if (debug) {
|
||||
if (protocolVersion == VotifierSession.ProtocolVersion.ONE) {
|
||||
logger.info("Got a protocol v1 vote record -> " + vote);
|
||||
logger.info("Got a protocol v1 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
} else {
|
||||
logger.info("Got a protocol v2 vote record -> " + vote);
|
||||
logger.info("Got a protocol v2 vote record from " + channel.remoteAddress() + " -> " + vote);
|
||||
}
|
||||
}
|
||||
Sponge.getScheduler().createTaskBuilder()
|
||||
.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VotifierEvent event = new VotifierEvent(vote, Cause.of(NamedCause.of("Vote", vote)));
|
||||
VotifierEvent event = new VotifierEvent(vote, Sponge.getCauseStackManager().getCurrentCause());
|
||||
Sponge.getEventManager().post(event);
|
||||
}
|
||||
})
|
||||
.async()
|
||||
.submit(this);
|
||||
}
|
||||
|
||||
@@ -378,11 +369,10 @@ public class VotifierPlugin implements VoteHandler, com.vexsoftware.votifier.Vot
|
||||
.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VotifierEvent event = new VotifierEvent(v, Cause.of(NamedCause.of("ForwardedVote", v)));
|
||||
VotifierEvent event = new VotifierEvent(v, Sponge.getCauseStackManager().getCurrentCause());
|
||||
Sponge.getEventManager().post(event);
|
||||
}
|
||||
})
|
||||
.async()
|
||||
.submit(this);
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,6 @@ port: 8192
|
||||
# This is useful when initially setting up NuVotifier to ensure votes are being delivered.
|
||||
debug: false
|
||||
|
||||
# Setting this value to false will turn off the votifier port listening for external votes. This is beneficial if the server
|
||||
# is only listening for votes coming from NuVotifier running on your BungeeCord.
|
||||
enableExternal: true
|
||||
|
||||
# Setting this option to true will disable handling of Protocol v1 packets. While the old protocol is not secure, this
|
||||
# option is currently not recommended as most voting sites only support the old protocol at present. However, if you are
|
||||
# using NuVotifier's proxy forwarding mechanism, enabling this option will increase your server's security.
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>nuvotifier</artifactId>
|
||||
<groupId>com.vexsoftware</groupId>
|
||||
<version>2.3.2.2</version>
|
||||
<version>2.3.6</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ networks.
|
||||
# Installation
|
||||
|
||||
The NuVotifier Universal jar (the default jar that is distributed on spigotmc.org) can be installed on Bukkit, BungeeCord,
|
||||
and Sponge servers as-is without modification.
|
||||
and Sponge servers as-is.
|
||||
|
||||
The Universal JAR can be downloaded off our [SpigotMC resource page](https://www.spigotmc.org/resources/nuvotifier.13449/).
|
||||
|
||||
@@ -18,7 +18,7 @@ the legacy protocol will be referred to v1. As of writing, most if not all vote
|
||||
|
||||
## Enabling the NuVotifier Server port
|
||||
|
||||
NuVotifier allows for the server port to be turned off when NuVotifier is only being used to forward votes. This is only
|
||||
NuVotifier allows for the server port to be turned off when NuVotifier is only receiving forwarded votes. This is only
|
||||
an option on Bukkit based servers, since it would not make logical sense for the port to be turned off on Bungee servers.
|
||||
|
||||
If you are receiving votes from a server list directly on the server in question (votes are not being forwarded through plugin
|
||||
@@ -28,10 +28,10 @@ be set to false.
|
||||
|
||||
## Port Configuration
|
||||
|
||||
One of NuVotifier's functions is acting as a vote server (receiver). The IP for NuVotifier to bind to is configured
|
||||
NuVotifier's main function is acting as a vote server (receiver). The IP for NuVotifier to bind to is configured
|
||||
by the `host` and `ip` configuration values within the config.yml files within the NuVotifier plugin folder.
|
||||
Most times, you will want this `host` value to be set to `0.0.0.0` or your server's ip. `0.0.0.0` will bind to all
|
||||
ip ports on your machine, while specifying a certain IP will only bind to that ip. If you don't know what to set this
|
||||
network addresses on your machine, while specifying a certain IP will only bind to that ip. If you don't know what to set this
|
||||
to, `0.0.0.0` is a safe bet. By default, NuVotifier listens on port 8192. This is the same as the default Votifier port.
|
||||
If you change this, you will have to remember this when setting up forwarding or server lists.
|
||||
|
||||
@@ -39,7 +39,7 @@ If you change this, you will have to remember this when setting up forwarding or
|
||||
|
||||
When first setting up NuVotifier, you will probably want debug mode to be enabled. This prints extra information to the
|
||||
console, ensuring that votes are being processed as they should. If you are experiencing an error, or having issues with
|
||||
votes being processed, you should first look to enable this. Debug mode can be turned on by setting `debug` in the config.yml
|
||||
votes being processed, you should first enable this. Debug mode can be turned on by setting `debug` in the config.yml
|
||||
to true.
|
||||
|
||||
## Tokens vs Public Key
|
||||
@@ -51,7 +51,7 @@ should be used. When setting up the `proxy` forwarding method, tokens should be
|
||||
Making a new token is as easy as adding another entry into `tokens` with the serviceName as the key and whatever string you want
|
||||
as the value. You can usually find the serviceName of a vote provider on their setup page if they use v2.
|
||||
|
||||
Unless a website specifies it, you should assume that the website is using v1, and you should enter your `rsa/public.key`.
|
||||
Unless a website specifies it, you should assume that the website is using v1, and you should use `rsa/public.key`.
|
||||
|
||||
## Forwarding
|
||||
|
||||
@@ -90,22 +90,22 @@ This is suitable for testing, but not for production system.
|
||||
|
||||
Votes can also be cached in a file located in the NuVotifier plugin folder. To enable this, you can set `cache` to file.
|
||||
If you want to change the file location from the default, you can set this under the `name` config under the `file` section.
|
||||
This caching method is suitable for most people.
|
||||
This caching method is suitable for most people. This is the default option.
|
||||
|
||||
##### No Caching
|
||||
|
||||
Caching can also be turned off. This is the default option. You can do this by setting `cache` to `none`. This is also not
|
||||
recommended, and is only suitable for a certain number of setups.
|
||||
Caching can also be turned off. You can do this by setting `cache` to `none`. This is also not recommended, and is only
|
||||
suitable for a certain number of setups.
|
||||
|
||||
### Proxy Based Forwarding
|
||||
|
||||
You can also forward votes using the proxy method. This will cause the BungeeCord to act as a voting websites, sending votes
|
||||
You can also forward votes using the proxy method. This will cause the BungeeCord to act like a voting website, sending votes
|
||||
to each server's NuVotifier port. To enable this method, you must set the `method` under `forwarding` to `proxy` in your
|
||||
BungeeCord config.yml. Within the server's config.yml, `forwarding` should be set to `none`.
|
||||
|
||||
For each server you wish to forward to, you must add each to your BungeeCord config.yml under the `proxy` section of `forwarding`.
|
||||
For each, you must specify the ip address (`address`), port (`port`) and token (`key`). Each backend Bukkit server should have
|
||||
1 default token under the `tokens` section. This is the token that should be used as the token for the `key` in that server's
|
||||
For each, you must specify the ip address (`address`), port (`port`) and token (`token`). Each backend Bukkit server should have
|
||||
1 default token under the `tokens` section. This is the token that should be used as the token for the `token` in that server's
|
||||
section within the `proxy` section. If the server is on the same server (same ip) as the BungeeCord server, you may
|
||||
use the `127.0.0.1` or `localhost` address, setting both the `proxy` forwarding address and Bukkit config.yml address to it.
|
||||
|
||||
@@ -122,7 +122,7 @@ and for Sponge [here](https://github.com/NuVotifier/NuVotifier/blob/master/spong
|
||||
|
||||
## Testing
|
||||
|
||||
There is a free resource for testing your NuVotifier setups at [ibj.io/v](https://ibj.io/v). If you are setting up your
|
||||
There is a free resource for testing your NuVotifier setups at [CraftServers](https://www.craftservers.net/tools/votifier-tester/). If you are setting up your
|
||||
network or server and want a server to get test votes on, you are more than welcome to use it.
|
||||
|
||||
|
||||
@@ -148,4 +148,4 @@ If you wish to contribute code wise, feel free to submit a pull request!
|
||||
## Client Libraries
|
||||
|
||||
NuVotifier has libraries available for [NodeJS](https://github.com/NuVotifier/votifier2-js) and [PHP](https://github.com/NuVotifier/votifier2-php).
|
||||
Both are free to use by serverlists.
|
||||
Both are free to use by serverlists.
|
||||
Reference in new issue
Block a user