|
| 1 | +package cn.wode490390.nukkit.geoip; |
| 2 | + |
| 3 | +import cn.nukkit.Player; |
| 4 | +import cn.nukkit.plugin.PluginBase; |
| 5 | +import cn.nukkit.utils.Config; |
| 6 | +import com.google.common.base.Preconditions; |
| 7 | +import com.google.common.collect.Maps; |
| 8 | +import com.ice.tar.TarEntry; |
| 9 | +import com.ice.tar.TarInputStream; |
| 10 | +import com.maxmind.geoip2.DatabaseReader; |
| 11 | +import java.io.File; |
| 12 | +import java.io.FileOutputStream; |
| 13 | +import java.io.IOException; |
| 14 | +import java.io.InputStream; |
| 15 | +import java.io.OutputStream; |
| 16 | +import java.net.MalformedURLException; |
| 17 | +import java.net.URL; |
| 18 | +import java.net.URLConnection; |
| 19 | +import java.util.Arrays; |
| 20 | +import java.util.Date; |
| 21 | +import java.util.Map; |
| 22 | +import java.util.zip.GZIPInputStream; |
| 23 | + |
| 24 | +public class GeoIP extends PluginBase { |
| 25 | + |
| 26 | + private static final Map<Player, String> cache = Maps.newHashMap(); |
| 27 | + |
| 28 | + /** |
| 29 | + * Querys player's geographical location. |
| 30 | + * |
| 31 | + * @param palyer |
| 32 | + * @return geographical location or null |
| 33 | + */ |
| 34 | + public static String query(Player palyer) { |
| 35 | + Preconditions.checkNotNull(palyer, "Player cannot be null"); |
| 36 | + return cache.get(palyer); |
| 37 | + } |
| 38 | + |
| 39 | + static void setGeoLocation(Player palyer, String location) { |
| 40 | + cache.put(palyer, location); |
| 41 | + } |
| 42 | + |
| 43 | + Config config; |
| 44 | + private File databaseFile; |
| 45 | + |
| 46 | + @Override |
| 47 | + public void onEnable() { |
| 48 | + try { |
| 49 | + new MetricsLite(this); |
| 50 | + } catch (Exception ignore) { |
| 51 | + |
| 52 | + } |
| 53 | + this.saveDefaultConfig(); |
| 54 | + this.config = this.getConfig(); |
| 55 | + if (this.config.getBoolean("database.show-cities", false)) { |
| 56 | + this.databaseFile = new File(this.getDataFolder(), "GeoIP2-City.mmdb"); |
| 57 | + } else { |
| 58 | + this.databaseFile = new File(this.getDataFolder(), "GeoIP2-Country.mmdb"); |
| 59 | + } |
| 60 | + if (!this.databaseFile.exists()) { |
| 61 | + if (this.config.getBoolean("database.download-if-missing", true)) { |
| 62 | + this.downloadDatabase(); |
| 63 | + } else { |
| 64 | + this.getLogger().warning("Can't find GeoIP database!"); |
| 65 | + this.setEnabled(false); |
| 66 | + return; |
| 67 | + } |
| 68 | + } else if (this.config.getBoolean("database.update.enable", true)) { |
| 69 | + // try to update expired mmdb files |
| 70 | + long diff = new Date().getTime() - this.databaseFile.lastModified(); |
| 71 | + if (diff / 86400000 > this.config.getLong("database.update.by-every-x-days", 30)) { |
| 72 | + this.downloadDatabase(); |
| 73 | + } |
| 74 | + } |
| 75 | + DatabaseReader mmreader; |
| 76 | + try { |
| 77 | + // locale setting |
| 78 | + if (this.config.getBoolean("enable-locale")) { |
| 79 | + // If the locale is not avaliable, use "en". |
| 80 | + mmreader = new DatabaseReader.Builder(this.databaseFile).locales(Arrays.asList(this.config.getString("locale"), "en")).build(); |
| 81 | + } else { |
| 82 | + mmreader = new DatabaseReader.Builder(this.databaseFile).build(); |
| 83 | + } |
| 84 | + } catch (IOException ex) { |
| 85 | + this.getLogger().warning("Failed to read GeoIP database", ex); |
| 86 | + this.setEnabled(false); |
| 87 | + return; |
| 88 | + } |
| 89 | + this.getServer().getPluginManager().registerEvents(new GeoIPListener(this, mmreader), this); |
| 90 | + this.getServer().getCommandMap().register("geoip", new GeoIPCommand(this)); |
| 91 | + } |
| 92 | + |
| 93 | + private void downloadDatabase() { |
| 94 | + try { |
| 95 | + String url; |
| 96 | + if (this.config.getBoolean("database.show-cities", false)) { |
| 97 | + url = this.config.getString("database.download-url-city"); |
| 98 | + } else { |
| 99 | + url = this.config.getString("database.download-url"); |
| 100 | + } |
| 101 | + if (url == null || url.isEmpty()) { |
| 102 | + this.getLogger().warning("GeoIP download url is empty."); |
| 103 | + return; |
| 104 | + } |
| 105 | + this.getLogger().info("Downloading GeoIP database... this might take a while."); |
| 106 | + URL downloadUrl = new URL(url); |
| 107 | + URLConnection conn = downloadUrl.openConnection(); |
| 108 | + conn.setConnectTimeout(10000); |
| 109 | + conn.connect(); |
| 110 | + InputStream input = conn.getInputStream(); |
| 111 | + OutputStream output = new FileOutputStream(this.databaseFile); |
| 112 | + byte[] buffer = new byte[2048]; |
| 113 | + if (url.endsWith(".gz")) { |
| 114 | + input = new GZIPInputStream(input); |
| 115 | + if (url.endsWith(".tar.gz")) { |
| 116 | + // The new GeoIP2 uses tar.gz to pack the db file along with some other txt. So it makes things a bit complicated here. |
| 117 | + String filename; |
| 118 | + TarInputStream tarInputStream = new TarInputStream(input); |
| 119 | + TarEntry entry; |
| 120 | + while ((entry = tarInputStream.getNextEntry()) != null) { |
| 121 | + if (!entry.isDirectory()) { |
| 122 | + filename = entry.getName(); |
| 123 | + if (filename.substring(filename.length() - 5).equalsIgnoreCase(".mmdb")) { |
| 124 | + input = tarInputStream; |
| 125 | + break; |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | + } |
| 131 | + int length = input.read(buffer); |
| 132 | + while (length >= 0) { |
| 133 | + output.write(buffer, 0, length); |
| 134 | + length = input.read(buffer); |
| 135 | + } |
| 136 | + output.close(); |
| 137 | + input.close(); |
| 138 | + } catch (MalformedURLException ex) { |
| 139 | + this.getLogger().warning("GeoIP download url is invalid", ex); |
| 140 | + } catch (IOException ex) { |
| 141 | + this.getLogger().warning("Failed to open connection", ex); |
| 142 | + } |
| 143 | + } |
| 144 | +} |
0 commit comments