2022-03-03 21:45:19 +00:00
package dev.plex.util ;
2022-04-01 07:54:22 +00:00
import com.google.common.base.Charsets ;
import com.google.gson.Gson ;
import com.google.gson.JsonObject ;
import com.google.gson.JsonSyntaxException ;
2022-03-03 21:45:19 +00:00
import dev.plex.PlexBase ;
2022-04-01 07:54:22 +00:00
import net.kyori.adventure.text.Component ;
import net.kyori.adventure.text.format.NamedTextColor ;
2022-04-07 03:55:54 +00:00
import org.apache.commons.io.FileUtils ;
import org.apache.http.HttpResponse ;
import org.apache.http.client.methods.HttpGet ;
import org.apache.http.impl.client.CloseableHttpClient ;
import org.apache.http.impl.client.HttpClients ;
import org.apache.http.util.EntityUtils ;
2022-04-07 04:08:03 +00:00
import org.bukkit.Bukkit ;
2022-04-01 08:08:17 +00:00
import org.bukkit.command.CommandSender ;
2023-03-09 01:29:30 +00:00
import org.json.JSONException ;
2022-04-07 03:55:54 +00:00
import org.json.JSONObject ;
2022-03-03 21:45:19 +00:00
2023-03-09 06:16:14 +00:00
import javax.annotation.Nonnull ;
import java.io.BufferedReader ;
import java.io.File ;
import java.io.IOException ;
import java.io.InputStreamReader ;
import java.net.HttpURLConnection ;
import java.net.URL ;
import java.nio.charset.StandardCharsets ;
import java.util.concurrent.CompletableFuture ;
import java.util.concurrent.atomic.AtomicReference ;
2022-04-17 05:27:04 +00:00
public class UpdateChecker implements PlexBase
2022-03-03 21:45:19 +00:00
{
2022-04-01 20:00:55 +00:00
/ *
* - 4 = Never checked for updates
* - 3 = Likely rate limited
* - 2 = Unknown commit
* - 1 = Error occurred
* 0 = Up to date
* > 0 = Number of commits behind
* /
2022-04-22 02:26:51 +00:00
private final String DOWNLOAD_PAGE = " https://ci.plex.us.org/job/ " ;
2022-06-05 03:08:13 +00:00
private final String REPO = plugin . config . getString ( " update_repo " ) ;
2022-08-02 12:08:52 +00:00
private String BRANCH = plugin . config . getString ( " update_branch " ) ;
2022-04-01 20:00:55 +00:00
private int distance = - 4 ;
2022-03-03 21:45:19 +00:00
2022-04-01 07:54:22 +00:00
// Adapted from Paper
private int fetchDistanceFromGitHub ( @Nonnull String repo , @Nonnull String branch , @Nonnull String hash )
2022-03-03 21:45:19 +00:00
{
try
{
2023-03-09 06:16:14 +00:00
HttpURLConnection connection = ( HttpURLConnection ) new URL ( " https://api.github.com/repos/ " + repo + " /compare/ " + branch + " ... " + hash ) . openConnection ( ) ;
2022-04-01 07:54:22 +00:00
connection . connect ( ) ;
if ( connection . getResponseCode ( ) = = HttpURLConnection . HTTP_NOT_FOUND )
2022-03-03 21:45:19 +00:00
{
2022-04-01 07:54:22 +00:00
return - 2 ; // Unknown commit
2022-03-03 21:45:19 +00:00
}
2022-04-01 20:00:55 +00:00
if ( connection . getResponseCode ( ) = = HttpURLConnection . HTTP_FORBIDDEN )
{
return - 3 ; // Rate limited likely
}
2022-04-01 07:54:22 +00:00
try ( BufferedReader reader = new BufferedReader ( new InputStreamReader ( connection . getInputStream ( ) , Charsets . UTF_8 ) ) )
2022-03-03 21:45:19 +00:00
{
2022-04-01 07:54:22 +00:00
JsonObject obj = new Gson ( ) . fromJson ( reader , JsonObject . class ) ;
String status = obj . get ( " status " ) . getAsString ( ) ;
return switch ( status )
{
case " identical " - > 0 ;
case " behind " - > obj . get ( " behind_by " ) . getAsInt ( ) ;
default - > - 1 ;
} ;
2022-04-07 04:14:44 +00:00
}
catch ( JsonSyntaxException | NumberFormatException e )
2022-03-03 21:45:19 +00:00
{
2022-04-01 07:54:22 +00:00
e . printStackTrace ( ) ;
return - 1 ;
2022-03-03 21:45:19 +00:00
}
2022-04-07 04:14:44 +00:00
}
catch ( IOException e )
2022-03-03 21:45:19 +00:00
{
2022-04-01 07:54:22 +00:00
e . printStackTrace ( ) ;
return - 1 ;
}
}
2022-04-08 05:01:02 +00:00
// If verbose is 0, it will display nothing
// If verbose is 1, it will only display a message if there is an update available
// If verbose is 2, it will display all messages
public boolean getUpdateStatusMessage ( CommandSender sender , boolean cached , int verbosity )
2022-04-01 07:54:22 +00:00
{
2022-06-05 03:08:13 +00:00
if ( BRANCH = = null )
2022-04-07 20:59:09 +00:00
{
PlexLog . error ( " You did not specify a branch to use for update checking. Defaulting to master. " ) ;
2022-06-05 03:08:13 +00:00
BRANCH = " master " ;
2022-04-07 20:59:09 +00:00
}
2022-04-01 20:00:55 +00:00
// If it's -4, it hasn't checked for updates yet
if ( distance = = - 4 )
{
2022-06-05 03:08:13 +00:00
distance = fetchDistanceFromGitHub ( REPO , BRANCH , BuildInfo . getHead ( ) ) ;
2022-04-01 20:00:55 +00:00
PlexLog . debug ( " Never checked for updates, checking now... " ) ;
2022-04-07 04:14:44 +00:00
}
else
2022-04-01 20:00:55 +00:00
{
// If the request isn't asked to be cached, fetch it
if ( ! cached )
{
2022-06-05 03:08:13 +00:00
distance = fetchDistanceFromGitHub ( REPO , BRANCH , BuildInfo . getHead ( ) ) ;
2022-04-01 20:00:55 +00:00
PlexLog . debug ( " We have checked for updates before, but this request was not asked to be cached. " ) ;
2022-04-07 04:14:44 +00:00
}
else
2022-04-01 20:00:55 +00:00
{
PlexLog . debug ( " We have checked for updates before, using cache. " ) ;
}
}
2022-04-01 07:54:22 +00:00
switch ( distance )
{
2022-04-13 02:22:17 +00:00
case - 1 - >
{
2022-04-08 05:01:02 +00:00
if ( verbosity = = 2 )
2022-04-07 04:49:45 +00:00
{
sender . sendMessage ( Component . text ( " There was an error checking for updates. " ) . color ( NamedTextColor . RED ) ) ;
}
2022-04-01 07:54:22 +00:00
return false ;
}
2022-04-13 02:22:17 +00:00
case 0 - >
{
2022-04-08 05:01:02 +00:00
if ( verbosity = = 2 )
2022-04-07 04:49:45 +00:00
{
2022-04-08 05:01:02 +00:00
sender . sendMessage ( Component . text ( " Plex is up to date! " ) . color ( NamedTextColor . GREEN ) ) ;
2022-04-07 04:49:45 +00:00
}
2022-04-05 20:46:21 +00:00
return false ;
2022-04-01 07:54:22 +00:00
}
2022-04-13 02:22:17 +00:00
case - 2 - >
{
2022-04-08 05:01:02 +00:00
if ( verbosity = = 2 )
2022-04-07 04:49:45 +00:00
{
sender . sendMessage ( Component . text ( " Unknown version, unable to check for updates. " ) . color ( NamedTextColor . RED ) ) ;
}
2022-04-01 07:54:22 +00:00
return false ;
}
2022-04-13 02:22:17 +00:00
default - >
{
2022-04-08 05:01:02 +00:00
if ( verbosity > = 1 )
{
sender . sendMessage ( Component . text ( " Plex is not up to date! " , NamedTextColor . RED ) ) ;
2022-08-02 04:38:18 +00:00
sender . sendMessage ( Component . text ( " Download a new version at: " + DOWNLOAD_PAGE + " Plex " ) . color ( NamedTextColor . RED ) ) ;
2022-04-08 05:01:02 +00:00
sender . sendMessage ( Component . text ( " Or run: /plex update " ) . color ( NamedTextColor . RED ) ) ;
}
2022-04-01 07:54:22 +00:00
return true ;
}
2022-03-03 21:45:19 +00:00
}
}
2022-04-07 03:55:54 +00:00
2022-04-22 02:26:51 +00:00
public void updateJar ( CommandSender sender , String name , boolean module )
2022-04-07 03:55:54 +00:00
{
CloseableHttpClient client = HttpClients . createDefault ( ) ;
2022-04-22 02:26:51 +00:00
AtomicReference < String > url = new AtomicReference < > ( DOWNLOAD_PAGE + name ) ;
if ( ! module )
{
2022-06-05 03:08:13 +00:00
url . set ( url . get ( ) + " /job/ " + BRANCH ) ;
2022-04-22 02:26:51 +00:00
}
PlexLog . debug ( url . toString ( ) ) ;
HttpGet get = new HttpGet ( url + " /lastSuccessfulBuild/api/json " ) ;
2022-04-07 03:55:54 +00:00
try
{
HttpResponse response = client . execute ( get ) ;
2023-03-09 06:16:14 +00:00
int statusCode = response . getStatusLine ( ) . getStatusCode ( ) ;
if ( statusCode = = HttpURLConnection . HTTP_OK )
2022-04-07 04:08:03 +00:00
{
2023-03-09 06:16:14 +00:00
JSONObject object = new JSONObject ( EntityUtils . toString ( response . getEntity ( ) , StandardCharsets . UTF_8 ) ) ;
JSONObject artifact = object . getJSONArray ( " artifacts " ) . getJSONObject ( 0 ) ;
String jarFile = artifact . getString ( " fileName " ) ;
sender . sendMessage ( PlexUtils . mmDeserialize ( " <green>Downloading latest JAR file: " + jarFile ) ) ;
File copyTo ;
if ( ! module )
2022-04-07 03:55:54 +00:00
{
2023-03-09 06:16:14 +00:00
copyTo = new File ( Bukkit . getUpdateFolderFile ( ) , jarFile ) ;
2022-04-07 04:14:44 +00:00
}
2023-03-09 06:16:14 +00:00
else
2022-04-07 03:55:54 +00:00
{
2023-03-09 06:16:14 +00:00
copyTo = new File ( plugin . getModulesFolder ( ) . getPath ( ) , jarFile ) ;
2022-04-07 03:55:54 +00:00
}
2023-03-09 06:16:14 +00:00
CompletableFuture . runAsync ( ( ) - >
{
try
{
FileUtils . copyURLToFile (
new URL ( url + " /lastSuccessfulBuild/artifact/build/libs/ " + jarFile ) ,
copyTo
) ;
sender . sendMessage ( PlexUtils . mmDeserialize ( " <green>New JAR file downloaded successfully. " ) ) ;
}
catch ( IOException e )
{
e . printStackTrace ( ) ;
}
} ) ;
}
else if ( statusCode = = HttpURLConnection . HTTP_NOT_FOUND )
{
sender . sendMessage ( PlexUtils . mmDeserialize ( " <red>Could not update " + name + " as it can't be found on Jenkins. " ) ) ;
}
else
{
sender . sendMessage ( PlexUtils . mmDeserialize ( " <red>Something went wrong while trying to update " + name + " . Please check the log for more information. " ) ) ;
PlexLog . error ( " Unable to update module {0} due to unexpected status code returned from Jenkins - Status Code: {1} " , name , statusCode ) ;
}
2022-04-07 04:14:44 +00:00
}
catch ( IOException e )
2022-04-07 03:55:54 +00:00
{
e . printStackTrace ( ) ;
}
2023-03-09 01:29:30 +00:00
catch ( JSONException e )
{
2023-03-09 06:16:14 +00:00
sender . sendMessage ( PlexUtils . mmDeserialize ( " <red>Something went wrong while trying to gather information from Jenkins for " + name + " . Please check the log for more information " ) ) ;
PlexLog . error ( " Unable to parse JSON information received from Jenkins - see below for more information... " ) ;
e . printStackTrace ( ) ;
2023-03-09 01:29:30 +00:00
}
2022-04-07 03:55:54 +00:00
}
2022-03-03 21:45:19 +00:00
}