mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
67a65c45d3
Geyser installations will now get notified when a new Bedrock release is out and Geyser must be updated. The system works similarly to ViaVersion where OPs get a notification of an update when they join. The permission node for players to see update notifications is `geyser.update` and the backing JSON that controls this can be found at https://github.com/GeyserMC/GeyserSite/blob/gh-pages/versions.json. There is also a config option to disable update checking. This update also fixes modern Paper installations not being able to see colored text logged from Geyser in the console.
197 lines
7.9 KiB
Java
197 lines
7.9 KiB
Java
/*
|
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
* @author GeyserMC
|
|
* @link https://github.com/GeyserMC/Geyser
|
|
*/
|
|
|
|
package org.geysermc.geyser.util;
|
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import org.geysermc.geyser.GeyserImpl;
|
|
|
|
import javax.annotation.Nullable;
|
|
import javax.naming.directory.Attribute;
|
|
import javax.naming.directory.InitialDirContext;
|
|
import java.io.*;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.net.URLEncoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.StandardCopyOption;
|
|
import java.util.Map;
|
|
|
|
public class WebUtils {
|
|
|
|
/**
|
|
* Makes a web request to the given URL and returns the body as a string
|
|
*
|
|
* @param reqURL URL to fetch
|
|
* @return Body contents or error message if the request fails
|
|
*/
|
|
public static String getBody(String reqURL) {
|
|
try {
|
|
URL url = new URL(reqURL);
|
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
|
con.setRequestMethod("GET");
|
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates
|
|
con.setConnectTimeout(10000);
|
|
con.setReadTimeout(10000);
|
|
|
|
return connectionToString(con);
|
|
} catch (Exception e) {
|
|
return e.getMessage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a web request to the given URL and returns the body as a {@link JsonNode}.
|
|
*
|
|
* @param reqURL URL to fetch
|
|
* @return the response as JSON
|
|
*/
|
|
public static JsonNode getJson(String reqURL) throws IOException {
|
|
HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection();
|
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION);
|
|
con.setConnectTimeout(10000);
|
|
con.setReadTimeout(10000);
|
|
return GeyserImpl.JSON_MAPPER.readTree(con.getInputStream());
|
|
}
|
|
|
|
/**
|
|
* Downloads a file from the given URL and saves it to disk
|
|
*
|
|
* @param reqURL File to fetch
|
|
* @param fileLocation Location to save on disk
|
|
*/
|
|
public static void downloadFile(String reqURL, String fileLocation) {
|
|
try {
|
|
HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection();
|
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION);
|
|
InputStream in = con.getInputStream();
|
|
Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING);
|
|
} catch (Exception e) {
|
|
throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Post a string to the given URL
|
|
*
|
|
* @param reqURL URL to post to
|
|
* @param postContent String data to post
|
|
* @return String returned by the server
|
|
* @throws IOException
|
|
*/
|
|
public static String post(String reqURL, String postContent) throws IOException {
|
|
URL url = new URL(reqURL);
|
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
|
con.setRequestMethod("POST");
|
|
con.setRequestProperty("Content-Type", "text/plain");
|
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION);
|
|
con.setDoOutput(true);
|
|
|
|
OutputStream out = con.getOutputStream();
|
|
out.write(postContent.getBytes(StandardCharsets.UTF_8));
|
|
out.close();
|
|
|
|
return connectionToString(con);
|
|
}
|
|
|
|
/**
|
|
* Get the string output from the passed {@link HttpURLConnection}
|
|
*
|
|
* @param con The connection to get the string from
|
|
* @return The body of the returned page
|
|
* @throws IOException
|
|
*/
|
|
private static String connectionToString(HttpURLConnection con) throws IOException {
|
|
// Send the request (we dont use this but its required for getErrorStream() to work)
|
|
con.getResponseCode();
|
|
|
|
// Read the error message if there is one if not just read normally
|
|
InputStream inputStream = con.getErrorStream();
|
|
if (inputStream == null) {
|
|
inputStream = con.getInputStream();
|
|
}
|
|
|
|
StringBuilder content = new StringBuilder();
|
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) {
|
|
String inputLine;
|
|
|
|
while ((inputLine = in.readLine()) != null) {
|
|
content.append(inputLine);
|
|
content.append("\n");
|
|
}
|
|
|
|
con.disconnect();
|
|
}
|
|
|
|
return content.toString();
|
|
}
|
|
|
|
/**
|
|
* Post fields to a URL as a form
|
|
*
|
|
* @param reqURL URL to post to
|
|
* @param fields Form data to post
|
|
* @return String returned by the server
|
|
* @throws IOException
|
|
*/
|
|
public static String postForm(String reqURL, Map<String, String> fields) throws IOException {
|
|
URL url = new URL(reqURL);
|
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
|
con.setRequestMethod("POST");
|
|
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION);
|
|
con.setDoOutput(true);
|
|
|
|
try (OutputStream out = con.getOutputStream()) {
|
|
// Write the form data to the output
|
|
for (Map.Entry<String, String> field : fields.entrySet()) {
|
|
out.write((field.getKey() + "=" + URLEncoder.encode(field.getValue(), StandardCharsets.UTF_8.toString()) + "&").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
}
|
|
|
|
return connectionToString(con);
|
|
}
|
|
|
|
@Nullable
|
|
public static String[] findSrvRecord(GeyserImpl geyser, String remoteAddress) {
|
|
try {
|
|
// Searches for a server address and a port from a SRV record of the specified host name
|
|
InitialDirContext ctx = new InitialDirContext();
|
|
Attribute attr = ctx.getAttributes("dns:///_minecraft._tcp." + remoteAddress, new String[]{"SRV"}).get("SRV");
|
|
// size > 0 = SRV entry found
|
|
if (attr != null && attr.size() > 0) {
|
|
return ((String) attr.get(0)).split(" ");
|
|
}
|
|
} catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes
|
|
if (geyser.getConfig().isDebugMode()) {
|
|
geyser.getLogger().debug("Exception while trying to find an SRV record for the remote host.");
|
|
ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|