Upload mirror

This commit is contained in:
Marvin Lukaschek committed 2020-08-19 20:37:30 +02:00
1 parent d0038e50d7
commit 3636ecd7cd
10 files changed
+1700

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
#if defined _updater_included
#endinput
#endif
#define _updater_included
/**
* Adds your plugin to the updater. The URL will be updated if
* your plugin was previously added.
*
* @param url URL to your plugin's update file.
* @noreturn
*/
native void Updater_AddPlugin(const char[] url);
/**
* Removes your plugin from the updater. This does not need to
* be called during OnPluginEnd.
*
* @noreturn
*/
native void Updater_RemovePlugin();
/**
* Forces your plugin to be checked for updates. The behaviour
* of the update is dependant on the server's configuration.
*
* @return True if an update was triggered. False otherwise.
* @error Plugin not found in updater.
*/
native bool Updater_ForceUpdate();
/**
* Called when your plugin is about to be checked for updates.
*
* @return Plugin_Handled to prevent checking, Plugin_Continue to allow it.
*/
forward Action Updater_OnPluginChecking();
/**
* Called when your plugin is about to begin downloading an available update.
*
* @return Plugin_Handled to prevent downloading, Plugin_Continue to allow it.
*/
forward Action Updater_OnPluginDownloading();
/**
* Called when your plugin's update files have been fully downloaded
* and are about to write to their proper location. This should be used
* to free read-only resources that require write access for your update.
*
* @note OnPluginUpdated will be called later during the same frame.
*
* @noreturn
*/
forward void Updater_OnPluginUpdating();
/**
* Called when your plugin's update has been completed. It is safe
* to reload your plugin at this time.
*
* @noreturn
*/
forward void Updater_OnPluginUpdated();
/**
* @brief Reloads a plugin.
*
* @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin).
* @noreturn
*/
stock void ReloadPlugin(Handle plugin=null)
{
char filename[64];
GetPluginFilename(plugin, filename, sizeof(filename));
ServerCommand("sm plugins reload %s", filename);
}
public SharedPlugin __pl_updater =
{
name = "updater",
file = "updater.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_updater_SetNTVOptional()
{
MarkNativeAsOptional("Updater_AddPlugin");
MarkNativeAsOptional("Updater_RemovePlugin");
MarkNativeAsOptional("Updater_ForceUpdate");
}
#endif
+316
View File
@@ -0,0 +1,316 @@
#pragma semicolon 1
#pragma newdecls required
/* SM Includes */
#include <sourcemod>
#undef REQUIRE_EXTENSIONS
#include <cURL>
#include <socket>
#include <steamtools>
#include <SteamWorks>
#define REQUIRE_EXTENSIONS
/* Plugin Info */
#define PLUGIN_NAME "Updater"
#define PLUGIN_VERSION "1.2.2"
public Plugin myinfo =
{
name = PLUGIN_NAME,
author = "GoD-Tony",
description = "Automatically updates SourceMod plugins and files",
version = PLUGIN_VERSION,
url = "http://forums.alliedmods.net/showthread.php?t=169095"
};
/* Globals */
//#define DEBUG // This will enable verbose logging. Useful for developers testing their updates.
#define CURL_AVAILABLE() (GetFeatureStatus(FeatureType_Native, "curl_easy_init") == FeatureStatus_Available)
#define SOCKET_AVAILABLE() (GetFeatureStatus(FeatureType_Native, "SocketCreate") == FeatureStatus_Available)
#define STEAMTOOLS_AVAILABLE() (GetFeatureStatus(FeatureType_Native, "Steam_CreateHTTPRequest") == FeatureStatus_Available)
#define STEAMWORKS_AVAILABLE() (GetFeatureStatus(FeatureType_Native, "SteamWorks_WriteHTTPResponseBodyToFile") == FeatureStatus_Available)
#define EXTENSION_ERROR "This plugin requires one of the cURL, Socket, SteamTools, or SteamWorks extensions to function."
#define TEMP_FILE_EXT "temp" // All files are downloaded with this extension first.
#define MAX_URL_LENGTH 256
#define UPDATE_URL "http://godtony.mooo.com/updater/updater.txt"
enum UpdateStatus {
Status_Idle,
Status_Checking, // Checking for updates.
Status_Downloading, // Downloading an update.
Status_Updated, // Update is complete.
Status_Error, // An error occured while downloading.
};
bool g_bGetDownload;
bool g_bGetSource;
Handle g_hPluginPacks = INVALID_HANDLE;
Handle g_hDownloadQueue = INVALID_HANDLE;
Handle g_hRemoveQueue = INVALID_HANDLE;
bool g_bDownloading = false;
static Handle _hUpdateTimer = INVALID_HANDLE;
static float _fLastUpdate = 0.0;
static char _sDataPath[PLATFORM_MAX_PATH];
/* Core Includes */
#include "updater/plugins.sp"
#include "updater/filesys.sp"
#include "updater/download.sp"
#include "updater/api.sp"
/* Plugin Functions */
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// cURL
MarkNativeAsOptional("curl_OpenFile");
MarkNativeAsOptional("curl_slist");
MarkNativeAsOptional("curl_slist_append");
MarkNativeAsOptional("curl_easy_init");
MarkNativeAsOptional("curl_easy_setopt_int_array");
MarkNativeAsOptional("curl_easy_setopt_handle");
MarkNativeAsOptional("curl_easy_setopt_string");
MarkNativeAsOptional("curl_easy_perform_thread");
MarkNativeAsOptional("curl_easy_strerror");
// Socket
MarkNativeAsOptional("SocketCreate");
MarkNativeAsOptional("SocketSetArg");
MarkNativeAsOptional("SocketSetOption");
MarkNativeAsOptional("SocketConnect");
MarkNativeAsOptional("SocketSend");
// SteamTools
MarkNativeAsOptional("Steam_CreateHTTPRequest");
MarkNativeAsOptional("Steam_SetHTTPRequestHeaderValue");
MarkNativeAsOptional("Steam_SendHTTPRequest");
MarkNativeAsOptional("Steam_WriteHTTPResponseBody");
MarkNativeAsOptional("Steam_ReleaseHTTPRequest");
API_Init();
RegPluginLibrary("updater");
return APLRes_Success;
}
public void OnPluginStart()
{
if (!CURL_AVAILABLE() && !SOCKET_AVAILABLE() && !STEAMTOOLS_AVAILABLE() && !STEAMWORKS_AVAILABLE())
{
SetFailState(EXTENSION_ERROR);
}
LoadTranslations("common.phrases");
// Convars.
Handle hCvar = INVALID_HANDLE;
hCvar = CreateConVar("sm_updater_version", PLUGIN_VERSION, PLUGIN_NAME, 0|FCVAR_NOTIFY|FCVAR_DONTRECORD);
OnVersionChanged(hCvar, "", "");
HookConVarChange(hCvar, OnVersionChanged);
hCvar = CreateConVar("sm_updater", "2", "Determines update functionality. (1 = Notify, 2 = Download, 3 = Include source code)", 0, true, 1.0, true, 3.0);
OnSettingsChanged(hCvar, "", "");
HookConVarChange(hCvar, OnSettingsChanged);
// Commands.
RegAdminCmd("sm_updater_check", Command_Check, ADMFLAG_RCON, "Forces Updater to check for updates.");
RegAdminCmd("sm_updater_status", Command_Status, ADMFLAG_RCON, "View the status of Updater.");
// Initialize arrays.
g_hPluginPacks = CreateArray();
g_hDownloadQueue = CreateArray();
g_hRemoveQueue = CreateArray();
// Temp path for checking update files.
BuildPath(Path_SM, _sDataPath, sizeof(_sDataPath), "data/updater.txt");
#if !defined DEBUG
// Add this plugin to the autoupdater.
Updater_AddPlugin(GetMyHandle(), UPDATE_URL);
#endif
// Check for updates every 24 hours.
_hUpdateTimer = CreateTimer(86400.0, Timer_CheckUpdates, _, TIMER_REPEAT);
}
public void OnAllPluginsLoaded()
{
// Check for updates on startup.
TriggerTimer(_hUpdateTimer, true);
}
public Action Timer_CheckUpdates(Handle timer)
{
Updater_FreeMemory();
// Update everything!
int maxPlugins = GetMaxPlugins();
for (int i = 0; i < maxPlugins; i++)
{
if (Updater_GetStatus(i) == Status_Idle)
{
Updater_Check(i);
}
}
_fLastUpdate = GetTickedTime();
return Plugin_Continue;
}
public Action Command_Check(int client, int args)
{
float fNextUpdate = _fLastUpdate + 3600.0;
if (fNextUpdate > GetTickedTime())
{
ReplyToCommand(client, "[Updater] Updates can only be checked once per hour. %.1f minutes remaining.", (fNextUpdate - GetTickedTime()) / 60.0);
}
else
{
ReplyToCommand(client, "[Updater] Checking for updates.");
TriggerTimer(_hUpdateTimer, true);
}
return Plugin_Handled;
}
public Action Command_Status(int client, int args)
{
char sFilename[64];
Handle hPlugin = INVALID_HANDLE;
int maxPlugins = GetMaxPlugins();
ReplyToCommand(client, "[Updater] -- Status Begin --");
ReplyToCommand(client, "Plugins being monitored for updates:");
for (int i = 0; i < maxPlugins; i++)
{
hPlugin = IndexToPlugin(i);
if (IsValidPlugin(hPlugin))
{
GetPluginFilename(hPlugin, sFilename, sizeof(sFilename));
ReplyToCommand(client, " [%i] %s", i, sFilename);
}
}
ReplyToCommand(client, "Last update check was %.1f minutes ago.", (GetTickedTime() - _fLastUpdate) / 60.0);
ReplyToCommand(client, "[Updater] --- Status End ---");
return Plugin_Handled;
}
public void OnVersionChanged(Handle convar, const char[] oldValue, const char[] newValue)
{
if (!StrEqual(newValue, PLUGIN_VERSION))
{
SetConVarString(convar, PLUGIN_VERSION);
}
}
public void OnSettingsChanged(Handle convar, const char[] oldValue, const char[] newValue)
{
switch (GetConVarInt(convar))
{
case 1: // Notify only.
{
g_bGetDownload = false;
g_bGetSource = false;
}
case 2: // Download updates.
{
g_bGetDownload = true;
g_bGetSource = false;
}
case 3: // Download with source code.
{
g_bGetDownload = true;
g_bGetSource = true;
}
}
}
#if !defined DEBUG
public void Updater_OnPluginUpdated()
{
Updater_Log("Reloading Updater plugin... updates will resume automatically.");
// Reload this plugin.
char filename[64];
GetPluginFilename(INVALID_HANDLE, filename, sizeof(filename));
ServerCommand("sm plugins reload %s", filename);
}
#endif
void Updater_Check(int index)
{
if (Fwd_OnPluginChecking(IndexToPlugin(index)) == Plugin_Continue)
{
char url[MAX_URL_LENGTH];
Updater_GetURL(index, url, sizeof(url));
Updater_SetStatus(index, Status_Checking);
AddToDownloadQueue(index, url, _sDataPath);
}
}
void Updater_FreeMemory()
{
// Make sure that no threads are active.
if (g_bDownloading || GetArraySize(g_hDownloadQueue))
{
return;
}
// Remove all queued plugins.
int index;
int maxPlugins = GetArraySize(g_hRemoveQueue);
for (int i = 0; i < maxPlugins; i++)
{
index = PluginToIndex(GetArrayCell(g_hRemoveQueue, i));
if (index != -1)
{
Updater_RemovePlugin(index);
}
}
ClearArray(g_hRemoveQueue);
// Remove plugins that have been unloaded.
for (int i = 0; i < GetMaxPlugins(); i++)
{
if (!IsValidPlugin(IndexToPlugin(i)))
{
Updater_RemovePlugin(i);
i--;
}
}
}
int Updater_Log(const char[] format, any:...)
{
char buffer[256];
char path[PLATFORM_MAX_PATH];
VFormat(buffer, sizeof(buffer), format, 2);
BuildPath(Path_SM, path, sizeof(path), "logs/Updater.log");
LogToFileEx(path, "%s", buffer);
}
#if defined DEBUG
int Updater_DebugLog(const char[] format, any:...)
{
char buffer[256];
char path[PLATFORM_MAX_PATH];
VFormat(buffer, sizeof(buffer), format, 2);
BuildPath(Path_SM, path, sizeof(path), "logs/Updater_Debug.log");
LogToFileEx(path, "%s", buffer);
}
#endif
+115
View File
@@ -0,0 +1,115 @@
/* API - Natives & Forwards */
static Handle fwd_OnPluginChecking = INVALID_HANDLE;
static Handle fwd_OnPluginDownloading = INVALID_HANDLE;
static Handle fwd_OnPluginUpdating = INVALID_HANDLE;
static Handle fwd_OnPluginUpdated = INVALID_HANDLE;
void API_Init()
{
CreateNative("Updater_AddPlugin", Native_AddPlugin);
CreateNative("Updater_RemovePlugin", Native_RemovePlugin);
CreateNative("Updater_ForceUpdate", Native_ForceUpdate);
fwd_OnPluginChecking = CreateForward(ET_Event);
fwd_OnPluginDownloading = CreateForward(ET_Event);
fwd_OnPluginUpdating = CreateForward(ET_Ignore);
fwd_OnPluginUpdated = CreateForward(ET_Ignore);
}
// native Updater_AddPlugin(const char[] url);
public int Native_AddPlugin(Handle plugin, int numParams)
{
char url[MAX_URL_LENGTH];
GetNativeString(1, url, sizeof(url));
Updater_AddPlugin(plugin, url);
}
// native Updater_RemovePlugin();
public int Native_RemovePlugin(Handle plugin, int numParams)
{
int index = PluginToIndex(plugin);
if (index != -1)
{
Updater_QueueRemovePlugin(plugin);
}
}
// native bool Updater_ForceUpdate();
public int Native_ForceUpdate(Handle plugin, int numParams)
{
int index = PluginToIndex(plugin);
if (index == -1)
{
ThrowNativeError(SP_ERROR_NOT_FOUND, "Plugin not found in updater.");
}
else if (Updater_GetStatus(index) == Status_Idle)
{
Updater_Check(index);
return 1;
}
return 0;
}
// forward Action:Updater_OnPluginChecking();
Action Fwd_OnPluginChecking(Handle plugin)
{
Action result = Plugin_Continue;
Function func = GetFunctionByName(plugin, "Updater_OnPluginChecking");
if (func != INVALID_FUNCTION && AddToForward(fwd_OnPluginChecking, plugin, func))
{
Call_StartForward(fwd_OnPluginChecking);
Call_Finish(result);
RemoveAllFromForward(fwd_OnPluginChecking, plugin);
}
return result;
}
// forward Action:Updater_OnPluginDownloading();
Action Fwd_OnPluginDownloading(Handle plugin)
{
Action result = Plugin_Continue;
Function func = GetFunctionByName(plugin, "Updater_OnPluginDownloading");
if (func != INVALID_FUNCTION && AddToForward(fwd_OnPluginDownloading, plugin, func))
{
Call_StartForward(fwd_OnPluginDownloading);
Call_Finish(result);
RemoveAllFromForward(fwd_OnPluginDownloading, plugin);
}
return result;
}
// forward Updater_OnPluginUpdating();
void Fwd_OnPluginUpdating(Handle plugin)
{
Function func = GetFunctionByName(plugin, "Updater_OnPluginUpdating");
if (func != INVALID_FUNCTION && AddToForward(fwd_OnPluginUpdating, plugin, func))
{
Call_StartForward(fwd_OnPluginUpdating);
Call_Finish();
RemoveAllFromForward(fwd_OnPluginUpdating, plugin);
}
}
// forward Updater_OnPluginUpdated();
void Fwd_OnPluginUpdated(Handle plugin)
{
Function func = GetFunctionByName(plugin, "Updater_OnPluginUpdated");
if (func != INVALID_FUNCTION && AddToForward(fwd_OnPluginUpdated, plugin, func))
{
Call_StartForward(fwd_OnPluginUpdated);
Call_Finish();
RemoveAllFromForward(fwd_OnPluginUpdated, plugin);
}
}
+235
View File
@@ -0,0 +1,235 @@
/* Download Manager */
#include "updater/download_curl.sp"
#include "updater/download_socket.sp"
#include "updater/download_steamtools.sp"
#include "updater/download_steamworks.sp"
DataPackPos QueuePack_URL;
void FinalizeDownload(int index)
{
/* Strip the temporary file extension from downloaded files. */
char newpath[PLATFORM_MAX_PATH];
char oldpath[PLATFORM_MAX_PATH];
Handle hFiles = Updater_GetFiles(index);
int maxFiles = GetArraySize(hFiles);
for (int i = 0; i < maxFiles; i++)
{
GetArrayString(hFiles, i, newpath, sizeof(newpath));
Format(oldpath, sizeof(oldpath), "%s.%s", newpath, TEMP_FILE_EXT);
// Rename doesn't overwrite on Windows. Make sure the path is clear.
if (FileExists(newpath))
{
DeleteFile(newpath);
}
RenameFile(newpath, oldpath);
}
ClearArray(hFiles);
}
void AbortDownload(int index)
{
/* Delete all downloaded temporary files. */
char path[PLATFORM_MAX_PATH];
Handle hFiles = Updater_GetFiles(index);
int maxFiles = GetArraySize(hFiles);
for (int i = 0; i < maxFiles; i++)
{
GetArrayString(hFiles, 0, path, sizeof(path));
Format(path, sizeof(path), "%s.%s", path, TEMP_FILE_EXT);
if (FileExists(path))
{
DeleteFile(path);
}
}
ClearArray(hFiles);
}
void ProcessDownloadQueue(bool force=false)
{
if (!force && (g_bDownloading || !GetArraySize(g_hDownloadQueue)))
{
return;
}
Handle hQueuePack = GetArrayCell(g_hDownloadQueue, 0);
SetPackPosition(hQueuePack, QueuePack_URL);
char url[MAX_URL_LENGTH];
char dest[PLATFORM_MAX_PATH];
ReadPackString(hQueuePack, url, sizeof(url));
ReadPackString(hQueuePack, dest, sizeof(dest));
if (!CURL_AVAILABLE() && !SOCKET_AVAILABLE() && !STEAMTOOLS_AVAILABLE() && !STEAMWORKS_AVAILABLE())
{
SetFailState(EXTENSION_ERROR);
}
#if defined DEBUG
Updater_DebugLog("Download started:");
Updater_DebugLog(" [0] URL: %s", url);
Updater_DebugLog(" [1] Destination: %s", dest);
#endif
g_bDownloading = true;
if (STEAMWORKS_AVAILABLE())
{
if (SteamWorks_IsLoaded())
{
Download_SteamWorks(url, dest);
}
else
{
CreateTimer(10.0, Timer_RetryQueue);
}
}
else if (STEAMTOOLS_AVAILABLE())
{
if (g_bSteamLoaded)
{
Download_SteamTools(url, dest);
}
else
{
CreateTimer(10.0, Timer_RetryQueue);
}
}
else if (CURL_AVAILABLE())
{
Download_cURL(url, dest);
}
else if (SOCKET_AVAILABLE())
{
Download_Socket(url, dest);
}
}
public Action Timer_RetryQueue(Handle timer)
{
ProcessDownloadQueue(true);
return Plugin_Stop;
}
void AddToDownloadQueue(int index, const char[] url, const char[] dest)
{
Handle hQueuePack = CreateDataPack();
WritePackCell(hQueuePack, index);
QueuePack_URL = GetPackPosition(hQueuePack);
WritePackString(hQueuePack, url);
WritePackString(hQueuePack, dest);
PushArrayCell(g_hDownloadQueue, hQueuePack);
ProcessDownloadQueue();
}
void DownloadEnded(bool successful, const char[] error="")
{
Handle hQueuePack = GetArrayCell(g_hDownloadQueue, 0);
ResetPack(hQueuePack);
char url[MAX_URL_LENGTH];
char dest[PLATFORM_MAX_PATH];
int index = ReadPackCell(hQueuePack);
ReadPackString(hQueuePack, url, sizeof(url));
ReadPackString(hQueuePack, dest, sizeof(dest));
// Remove from the queue.
CloseHandle(hQueuePack);
RemoveFromArray(g_hDownloadQueue, 0);
#if defined DEBUG
Updater_DebugLog(" [2] Successful: %s", successful ? "Yes" : "No");
#endif
switch (Updater_GetStatus(index))
{
case Status_Checking:
{
if (!successful || !ParseUpdateFile(index, dest))
{
Updater_SetStatus(index, Status_Idle);
#if defined DEBUG
if (error[0] != '\0')
{
Updater_DebugLog(" [2] %s", error);
}
#endif
}
}
case Status_Downloading:
{
if (successful)
{
// Check if this was the last file we needed.
char lastfile[PLATFORM_MAX_PATH];
Handle hFiles = Updater_GetFiles(index);
GetArrayString(hFiles, GetArraySize(hFiles) - 1, lastfile, sizeof(lastfile));
Format(lastfile, sizeof(lastfile), "%s.%s", lastfile, TEMP_FILE_EXT);
if (StrEqual(dest, lastfile))
{
Handle hPlugin = IndexToPlugin(index);
Fwd_OnPluginUpdating(hPlugin);
FinalizeDownload(index);
char sName[64];
if (!GetPluginInfo(hPlugin, PlInfo_Name, sName, sizeof(sName)))
{
strcopy(sName, sizeof(sName), "Null");
}
Updater_Log("Successfully updated and installed \"%s\".", sName);
Updater_SetStatus(index, Status_Updated);
Fwd_OnPluginUpdated(hPlugin);
}
}
else
{
// Failed during an update.
AbortDownload(index);
Updater_SetStatus(index, Status_Error);
char filename[64];
GetPluginFilename(IndexToPlugin(index), filename, sizeof(filename));
Updater_Log("Error downloading update for plugin: %s", filename);
Updater_Log(" [0] URL: %s", url);
Updater_Log(" [1] Destination: %s", dest);
if (error[0] != '\0')
{
Updater_Log(" [2] %s", error);
}
}
}
case Status_Error:
{
// Delete any additional files that this plugin had queued.
if (successful && FileExists(dest))
{
DeleteFile(dest);
}
}
}
g_bDownloading = false;
ProcessDownloadQueue();
}
+62
View File
@@ -0,0 +1,62 @@
/* Extension Helper - cURL */
void Download_cURL(const char[] url, const char[] dest)
{
char sURL[MAX_URL_LENGTH];
PrefixURL(sURL, sizeof(sURL), url);
Handle hFile = curl_OpenFile(dest, "wb");
if (hFile == INVALID_HANDLE)
{
char sError[256];
FormatEx(sError, sizeof(sError), "Error writing to file: %s", dest);
DownloadEnded(false, sError);
return;
}
int CURL_Default_opt[][2] = {
{view_as<int>(CURLOPT_NOSIGNAL), 1},
{view_as<int>(CURLOPT_NOPROGRESS), 1},
{view_as<int>(CURLOPT_TIMEOUT), 30},
{view_as<int>(CURLOPT_CONNECTTIMEOUT), 60},
{view_as<int>(CURLOPT_VERBOSE), 0}
};
Handle headers = curl_slist();
curl_slist_append(headers, "Pragma: no-cache");
curl_slist_append(headers, "Cache-Control: no-cache");
Handle hDLPack = CreateDataPack();
WritePackCell(hDLPack, view_as<int>(hFile));
WritePackCell(hDLPack, view_as<int>(headers));
Handle curl = curl_easy_init();
curl_easy_setopt_int_array(curl, CURL_Default_opt, sizeof(CURL_Default_opt));
curl_easy_setopt_handle(curl, CURLOPT_WRITEDATA, hFile);
curl_easy_setopt_string(curl, CURLOPT_URL, url);
curl_easy_setopt_handle(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_perform_thread(curl, OnCurlComplete, hDLPack);
}
public void OnCurlComplete(Handle curl, CURLcode code, any hDLPack)
{
ResetPack(hDLPack);
CloseHandle(ReadPackCell(hDLPack)); // hFile
CloseHandle(ReadPackCell(hDLPack)); // headers
CloseHandle(hDLPack);
CloseHandle(curl);
if(code == CURLE_OK)
{
DownloadEnded(true);
}
else
{
char sError[256];
curl_easy_strerror(code, sError, sizeof(sError));
Format(sError, sizeof(sError), "cURL error: %s", sError);
DownloadEnded(false, sError);
}
}
+203
View File
@@ -0,0 +1,203 @@
/* Extension Helper - Socket */
#define MAX_REDIRECTS 5
static DataPackPos DLPack_Header;
static DataPackPos DLPack_Redirects;
static DataPackPos DLPack_File;
static DataPackPos DLPack_Request;
void Download_Socket(const char[] url, const char[] dest)
{
char sURL[MAX_URL_LENGTH];
PrefixURL(sURL, sizeof(sURL), url);
if (strncmp(sURL, "https://", 8) == 0)
{
char sError[256];
FormatEx(sError, sizeof(sError), "Socket does not support HTTPs (URL: %s).", sURL);
DownloadEnded(false, sError);
return;
}
Handle hFile = OpenFile(dest, "wb");
if (hFile == INVALID_HANDLE)
{
char sError[256];
FormatEx(sError, sizeof(sError), "Error writing to file: %s", dest);
DownloadEnded(false, sError);
return;
}
// Format HTTP GET method.
char hostname[64];
char location[128];
char filename[64];
char sRequest[MAX_URL_LENGTH+128];
ParseURL(sURL, hostname, sizeof(hostname), location, sizeof(location), filename, sizeof(filename));
FormatEx(sRequest, sizeof(sRequest), "GET %s/%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nPragma: no-cache\r\nCache-Control: no-cache\r\n\r\n", location, filename, hostname);
Handle hDLPack = CreateDataPack();
DLPack_Header = GetPackPosition(hDLPack);
WritePackCell(hDLPack, 0);
DLPack_Redirects = GetPackPosition(hDLPack);
WritePackCell(hDLPack, 0);
DLPack_File = GetPackPosition(hDLPack);
WritePackCell(hDLPack, view_as<int>(hFile));
DLPack_Request = GetPackPosition(hDLPack);
WritePackString(hDLPack, sRequest);
Handle socket = SocketCreate(SOCKET_TCP, OnSocketError);
SocketSetArg(socket, hDLPack);
SocketSetOption(socket, ConcatenateCallbacks, 4096);
SocketConnect(socket, OnSocketConnected, OnSocketReceive, OnSocketDisconnected, hostname, 80);
}
public void OnSocketConnected(Handle socket, any hDLPack)
{
char sRequest[MAX_URL_LENGTH+128];
SetPackPosition(hDLPack, DLPack_Request);
ReadPackString(hDLPack, sRequest, sizeof(sRequest));
SocketSend(socket, sRequest);
}
public void OnSocketReceive(Handle socket, char[] data, const int size, any hDLPack)
{
int idx = 0;
// Check if the HTTP header has already been parsed.
SetPackPosition(hDLPack, DLPack_Header);
bool bParsedHeader = view_as<bool>(ReadPackCell(hDLPack));
int iRedirects = ReadPackCell(hDLPack);
if (!bParsedHeader)
{
// Parse header data.
if ((idx = StrContains(data, "\r\n\r\n")) == -1)
{
idx = 0;
}
else
{
idx += 4;
}
if (strncmp(data, "HTTP/", 5) == 0)
{
// Check for location header.
int idx2 = StrContains(data, "\nLocation: ", false);
if (idx2 > -1 && (idx2 < idx || !idx))
{
if (++iRedirects > MAX_REDIRECTS)
{
CloseSocketHandles(socket, hDLPack);
DownloadEnded(false, "Socket error: too many redirects.");
return;
}
else
{
SetPackPosition(hDLPack, DLPack_Redirects);
WritePackCell(hDLPack, iRedirects);
}
// skip to url
idx2 += 11;
char sURL[MAX_URL_LENGTH];
strcopy(sURL, (FindCharInString(data[idx2], '\r') + 1), data[idx2]);
PrefixURL(sURL, sizeof(sURL), sURL);
#if defined DEBUG
Updater_DebugLog(" [ ] Redirected: %s", sURL);
#endif
if (strncmp(sURL, "https://", 8) == 0)
{
CloseSocketHandles(socket, hDLPack);
char sError[256];
FormatEx(sError, sizeof(sError), "Socket does not support HTTPs (URL: %s).", sURL);
DownloadEnded(false, sError);
return;
}
char hostname[64];
char location[128];
char filename[64];
char sRequest[MAX_URL_LENGTH+128];
ParseURL(sURL, hostname, sizeof(hostname), location, sizeof(location), filename, sizeof(filename));
FormatEx(sRequest, sizeof(sRequest), "GET %s/%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nPragma: no-cache\r\nCache-Control: no-cache\r\n\r\n", location, filename, hostname);
SetPackPosition(hDLPack, DLPack_Request); // sRequest
WritePackString(hDLPack, sRequest);
Handle newSocket = SocketCreate(SOCKET_TCP, OnSocketError);
SocketSetArg(newSocket, hDLPack);
SocketSetOption(newSocket, ConcatenateCallbacks, 4096);
SocketConnect(newSocket, OnSocketConnected, OnSocketReceive, OnSocketDisconnected, hostname, 80);
CloseHandle(socket);
return;
}
// Check HTTP status code
char sStatusCode[64];
strcopy(sStatusCode, (FindCharInString(data, '\r') - 8), data[9]);
if (strncmp(sStatusCode, "200", 3) != 0)
{
CloseSocketHandles(socket, hDLPack);
char sError[256];
FormatEx(sError, sizeof(sError), "Socket error: %s", sStatusCode);
DownloadEnded(false, sError);
return;
}
}
SetPackPosition(hDLPack, DLPack_Header);
WritePackCell(hDLPack, 1); // bParsedHeader
}
// Write data to file.
SetPackPosition(hDLPack, DLPack_File);
Handle hFile = view_as<Handle>(ReadPackCell(hDLPack));
while (idx < size)
{
WriteFileCell(hFile, data[idx++], 1);
}
}
public void OnSocketDisconnected(Handle socket, any hDLPack)
{
CloseSocketHandles(socket, hDLPack);
DownloadEnded(true);
}
public void OnSocketError(Handle socket, const int errorType, const int errorNum, any hDLPack)
{
CloseSocketHandles(socket, hDLPack);
char sError[256];
FormatEx(sError, sizeof(sError), "Socket error: %d (Error code %d)", errorType, errorNum);
DownloadEnded(false, sError);
}
void CloseSocketHandles(Handle socket, Handle hDLPack)
{
SetPackPosition(hDLPack, DLPack_File);
CloseHandle(view_as<Handle>(ReadPackCell(hDLPack))); // hFile
CloseHandle(hDLPack);
CloseHandle(socket);
}
+51
View File
@@ -0,0 +1,51 @@
/* Extension Helper - SteamTools */
void Download_SteamTools(const char[] url, const char[] dest)
{
char sURL[MAX_URL_LENGTH];
PrefixURL(sURL, sizeof(sURL), url);
Handle hDLPack = CreateDataPack();
WritePackString(hDLPack, dest);
HTTPRequestHandle hRequest = Steam_CreateHTTPRequest(HTTPMethod_GET, sURL);
Steam_SetHTTPRequestHeaderValue(hRequest, "Pragma", "no-cache");
Steam_SetHTTPRequestHeaderValue(hRequest, "Cache-Control", "no-cache");
Steam_SendHTTPRequest(hRequest, OnSteamHTTPComplete, hDLPack);
}
public void OnSteamHTTPComplete(HTTPRequestHandle HTTPRequest, bool requestSuccessful, HTTPStatusCode statusCode, any hDLPack)
{
char sDest[PLATFORM_MAX_PATH];
ResetPack(hDLPack);
ReadPackString(hDLPack, sDest, sizeof(sDest));
CloseHandle(hDLPack);
if (requestSuccessful && statusCode == HTTPStatusCode_OK)
{
Steam_WriteHTTPResponseBody(HTTPRequest, sDest);
DownloadEnded(true);
}
else
{
char sError[256];
FormatEx(sError, sizeof(sError), "SteamTools error (status code %i). Request successful: %s", view_as<int>(statusCode), requestSuccessful ? "True" : "False");
DownloadEnded(false, sError);
}
Steam_ReleaseHTTPRequest(HTTPRequest);
}
/* Keep track of SteamTools load state. */
bool g_bSteamLoaded;
public void Steam_FullyLoaded()
{
g_bSteamLoaded = true;
}
public void Steam_Shutdown()
{
g_bSteamLoaded = false;
}
+40
View File
@@ -0,0 +1,40 @@
/* Extension Helper - SteamWorks */
void Download_SteamWorks(const char[] url, const char[] dest)
{
char sURL[MAX_URL_LENGTH];
PrefixURL(sURL, sizeof(sURL), url);
Handle hDLPack = CreateDataPack();
WritePackString(hDLPack, dest);
Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sURL);
SteamWorks_SetHTTPRequestHeaderValue(hRequest, "Pragma", "no-cache");
SteamWorks_SetHTTPRequestHeaderValue(hRequest, "Cache-Control", "no-cache");
SteamWorks_SetHTTPCallbacks(hRequest, OnSteamWorksHTTPComplete);
SteamWorks_SetHTTPRequestContextValue(hRequest, hDLPack);
SteamWorks_SendHTTPRequest(hRequest);
}
public void OnSteamWorksHTTPComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, any hDLPack)
{
char sDest[PLATFORM_MAX_PATH];
ResetPack(hDLPack);
ReadPackString(hDLPack, sDest, sizeof(sDest));
CloseHandle(hDLPack);
if (bRequestSuccessful && eStatusCode == k_EHTTPStatusCode200OK)
{
SteamWorks_WriteHTTPResponseBodyToFile(hRequest, sDest);
DownloadEnded(true);
}
else
{
char sError[256];
FormatEx(sError, sizeof(sError), "SteamWorks error (status code %i). Request successful: %s", view_as<int>(eStatusCode), bRequestSuccessful ? "True" : "False");
DownloadEnded(false, sError);
}
CloseHandle(hRequest);
}
+385
View File
@@ -0,0 +1,385 @@
/* File System Parsers */
// Strip filename from path.
void StripPathFilename(char[] path)
{
strcopy(path, FindCharInString(path, '/', true) + 1, path);
}
// Return the filename and extension from a given path.
void GetPathBasename(char[] path, char[] buffer, int maxlength)
{
int check = -1;
if ((check = FindCharInString(path, '/', true)) != -1 ||
(check = FindCharInString(path, '\\', true)) != -1)
{
strcopy(buffer, maxlength, path[check+1]);
}
else
{
strcopy(buffer, maxlength, path);
}
}
// Add http protocol to url if it's missing.
void PrefixURL(char[] buffer, int maxlength, const char[] url)
{
if (strncmp(url, "http://", 7) != 0 && strncmp(url, "https://", 8) != 0)
{
Format(buffer, maxlength, "http://%s", url);
}
else
{
strcopy(buffer, maxlength, url);
}
}
// Split URL into hostname, location, and filename. No trailing slashes.
void ParseURL(const char[] url, char[] host, int maxHost, char[] location, int maxLoc, char[] filename, int maxName)
{
// Strip url prefix.
int idx = StrContains(url, "://");
idx = (idx != -1) ? idx + 3 : 0;
char dirs[16][64];
int total = ExplodeString(url[idx], "/", dirs, sizeof(dirs), sizeof(dirs[]));
// host
Format(host, maxHost, "%s", dirs[0]);
// location
location[0] = '\0';
for (int i = 1; i < total - 1; i++)
{
Format(location, maxLoc, "%s/%s", location, dirs[i]);
}
// filename
Format(filename, maxName, "%s", dirs[total-1]);
}
// Converts Updater SMC file paths into paths relative to the game folder.
void ParseSMCPathForLocal(const char[] path, char[] buffer, int maxlength)
{
char dirs[16][64];
int total = ExplodeString(path, "/", dirs, sizeof(dirs), sizeof(dirs[]));
if (StrEqual(dirs[0], "Path_SM"))
{
BuildPath(Path_SM, buffer, maxlength, "");
}
else // Path_Mod
{
buffer[0] = '\0';
}
// Construct the path and create directories if needed.
for (int i = 1; i < total - 1; i++)
{
Format(buffer, maxlength, "%s%s/", buffer, dirs[i]);
if(!DirExists(buffer))
{
CreateDirectory(buffer, 511);
}
}
// Add the filename to the end of the path.
Format(buffer, maxlength, "%s%s", buffer, dirs[total-1]);
}
// Converts Updater SMC file paths into paths relative to the plugin's update URL.
void ParseSMCPathForDownload(const char[] path, char[] buffer, int maxlength)
{
char dirs[16][64];
int total = ExplodeString(path, "/", dirs, sizeof(dirs), sizeof(dirs[]));
// Construct the path.
buffer[0] = '\0';
for (int i = 1; i < total; i++)
{
Format(buffer, maxlength, "%s/%s", buffer, dirs[i]);
}
}
// Parses a plugin's update file.
// Logs update notes and begins download if required.
// Returns true if an update was available.
static Handle SMC_Sections;
static Handle SMC_DataTrie;
static Handle SMC_DataPack;
static int SMC_LineNum;
bool ParseUpdateFile(int index, const char[] path)
{
/* Return true if an update was available. */
SMC_Sections = CreateArray(64);
SMC_DataTrie = CreateTrie();
SMC_DataPack = CreateDataPack();
SMC_LineNum = 0;
Handle smc = SMC_CreateParser();
SMC_SetRawLine(smc, Updater_RawLine);
SMC_SetReaders(smc, Updater_NewSection, Updater_KeyValue, Updater_EndSection);
char sBuffer[MAX_URL_LENGTH];
Handle hPack;
bool bUpdate = false;
SMCError err = SMC_ParseFile(smc, path);
if (err == SMCError_Okay)
{
// Initialize data
Handle hPlugin = IndexToPlugin(index);
Handle hFiles = Updater_GetFiles(index);
ClearArray(hFiles);
// current version.
char sCurrentVersion[16];
if (!GetPluginInfo(hPlugin, PlInfo_Version, sCurrentVersion, sizeof(sCurrentVersion)))
{
strcopy(sCurrentVersion, sizeof(sCurrentVersion), "Null");
}
// latest version.
char smcLatestVersion[16];
if (GetTrieValue(SMC_DataTrie, "version->latest", hPack))
{
ResetPack(hPack);
ReadPackString(hPack, smcLatestVersion, sizeof(smcLatestVersion));
}
// Check if we have the latest version.
if (!StrEqual(sCurrentVersion, smcLatestVersion))
{
char sFilename[64];
char sName[64];
GetPluginFilename(hPlugin, sFilename, sizeof(sFilename));
if (GetPluginInfo(hPlugin, PlInfo_Name, sName, sizeof(sName)))
{
Updater_Log("Update available for \"%s\" (%s). Current: %s - Latest: %s", sName, sFilename, sCurrentVersion, smcLatestVersion);
}
else
{
Updater_Log("Update available for \"%s\". Current: %s - Latest: %s", sFilename, sCurrentVersion, smcLatestVersion);
}
if (GetTrieValue(SMC_DataTrie, "information->notes", hPack))
{
ResetPack(hPack);
int iCount = 0;
while (IsPackReadable(hPack, 1))
{
ReadPackString(hPack, sBuffer, sizeof(sBuffer));
Updater_Log(" [%i] %s", iCount++, sBuffer);
}
}
// Log update notes, save file list, and begin downloading.
if (g_bGetDownload && Fwd_OnPluginDownloading(hPlugin) == Plugin_Continue)
{
// Get previous version.
char smcPrevVersion[16];
if (GetTrieValue(SMC_DataTrie, "version->previous", hPack))
{
ResetPack(hPack);
ReadPackString(hPack, smcPrevVersion, sizeof(smcPrevVersion));
}
// Check if we only need the patch files.
if (StrEqual(sCurrentVersion, smcPrevVersion) && GetTrieValue(SMC_DataTrie, "patch->plugin", hPack))
{
ParseSMCFilePack(index, hPack, hFiles);
if (g_bGetSource && GetTrieValue(SMC_DataTrie, "patch->source", hPack))
{
ParseSMCFilePack(index, hPack, hFiles);
}
}
else if (GetTrieValue(SMC_DataTrie, "files->plugin", hPack))
{
ParseSMCFilePack(index, hPack, hFiles);
if (g_bGetSource && GetTrieValue(SMC_DataTrie, "files->source", hPack))
{
ParseSMCFilePack(index, hPack, hFiles);
}
}
Updater_SetStatus(index, Status_Downloading);
}
else
{
// We don't want to spam the logs with the same update notification.
Updater_SetStatus(index, Status_Updated);
}
bUpdate = true;
}
#if defined DEBUG
iCount = 0;
Updater_DebugLog(" ");
Updater_DebugLog("SMC DEBUG");
ResetPack(SMC_DataPack);
while (IsPackReadable(SMC_DataPack, 1))
{
ReadPackString(SMC_DataPack, sBuffer, sizeof(sBuffer));
Updater_DebugLog("%s", sBuffer);
if (GetTrieValue(SMC_DataTrie, sBuffer, hPack))
{
iCount = 0;
ResetPack(hPack);
while (IsPackReadable(hPack, 1))
{
ReadPackString(hPack, sBuffer, sizeof(sBuffer));
Updater_DebugLog(" [%i] %s", iCount++, sBuffer);
}
}
}
Updater_DebugLog("END SMC DEBUG");
Updater_DebugLog(" ");
#endif
}
else
{
Updater_Log("SMC parsing error on line %d", SMC_LineNum);
Updater_GetURL(index, sBuffer, sizeof(sBuffer));
Updater_Log(" [0] URL: %s", sBuffer);
if (SMC_GetErrorString(err, sBuffer, sizeof(sBuffer)))
{
Updater_Log(" [1] ERROR: %s", sBuffer);
}
}
// Clean up SMC data.
ResetPack(SMC_DataPack);
while (IsPackReadable(SMC_DataPack, 1))
{
ReadPackString(SMC_DataPack, sBuffer, sizeof(sBuffer));
if (GetTrieValue(SMC_DataTrie, sBuffer, hPack))
{
CloseHandle(hPack);
}
}
CloseHandle(SMC_Sections);
CloseHandle(SMC_DataTrie);
CloseHandle(SMC_DataPack);
CloseHandle(smc);
return bUpdate;
}
void ParseSMCFilePack(int index, Handle hPack, Handle hFiles)
{
// Prepare URL
char urlprefix[MAX_URL_LENGTH];
char url[MAX_URL_LENGTH];
char dest[PLATFORM_MAX_PATH];
char sBuffer[MAX_URL_LENGTH];
Updater_GetURL(index, urlprefix, sizeof(urlprefix));
StripPathFilename(urlprefix);
ResetPack(hPack);
while (IsPackReadable(hPack, 1))
{
ReadPackString(hPack, sBuffer, sizeof(sBuffer));
// Merge url.
ParseSMCPathForDownload(sBuffer, url, sizeof(url));
Format(url, sizeof(url), "%s%s", urlprefix, url);
// Make sure the current plugin path matches the update.
ParseSMCPathForLocal(sBuffer, dest, sizeof(dest));
char sLocalBase[64];
char sPluginBase[64];
char sFilename[64];
GetPathBasename(dest, sLocalBase, sizeof(sLocalBase));
GetPathBasename(sFilename, sPluginBase, sizeof(sPluginBase));
if (StrEqual(sLocalBase, sPluginBase))
{
StripPathFilename(dest);
Format(dest, sizeof(dest), "%s/%s", dest, sFilename);
}
// Save the file location for later.
PushArrayString(hFiles, dest);
// Add temporary file extension.
Format(dest, sizeof(dest), "%s.%s", dest, TEMP_FILE_EXT);
// Begin downloading file.
AddToDownloadQueue(index, url, dest);
}
}
public SMCResult Updater_RawLine(Handle smc, const char[] line, int lineno)
{
SMC_LineNum = lineno;
return SMCParse_Continue;
}
public SMCResult Updater_NewSection(Handle smc, const char[] name, bool opt_quotes)
{
PushArrayString(SMC_Sections, name);
return SMCParse_Continue;
}
public SMCResult Updater_KeyValue(Handle smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes)
{
char sCurSection[MAX_URL_LENGTH];
char sKey[MAX_URL_LENGTH];
Handle hPack;
GetArrayString(SMC_Sections, GetArraySize(SMC_Sections)-1, sCurSection, sizeof(sCurSection));
FormatEx(sKey, sizeof(sKey), "%s->%s", sCurSection, key);
StringToLower(sKey);
if (!GetTrieValue(SMC_DataTrie, sKey, hPack))
{
hPack = CreateDataPack();
SetTrieValue(SMC_DataTrie, sKey, hPack);
WritePackString(SMC_DataPack, sKey);
}
WritePackString(hPack, value);
return SMCParse_Continue;
}
public SMCResult Updater_EndSection(Handle smc)
{
if (GetArraySize(SMC_Sections))
{
RemoveFromArray(SMC_Sections, GetArraySize(SMC_Sections)-1);
}
return SMCParse_Continue;
}
stock void StringToLower(char[] input)
{
int length = strlen(input);
for (int i = 0; i < length; i++)
{
input[i] = CharToLower(input[i]);
}
}
+196
View File
@@ -0,0 +1,196 @@
/* PluginPack Helpers */
static DataPackPos PluginPack_Plugin;
static DataPackPos PluginPack_Files;
static DataPackPos PluginPack_Status;
static DataPackPos PluginPack_URL;
int GetMaxPlugins()
{
return GetArraySize(g_hPluginPacks);
}
bool IsValidPlugin(Handle plugin)
{
/* Check if the plugin handle is pointing to a valid plugin. */
Handle hIterator = GetPluginIterator();
bool bIsValid = false;
while (MorePlugins(hIterator))
{
if (plugin == ReadPlugin(hIterator))
{
bIsValid = true;
break;
}
}
CloseHandle(hIterator);
return bIsValid;
}
int PluginToIndex(Handle plugin)
{
Handle hPluginPack = INVALID_HANDLE;
int maxPlugins = GetMaxPlugins();
for (int i = 0; i < maxPlugins; i++)
{
hPluginPack = GetArrayCell(g_hPluginPacks, i);
SetPackPosition(hPluginPack, PluginPack_Plugin);
if (plugin == view_as<Handle>(ReadPackCell(hPluginPack)))
{
return i;
}
}
return -1;
}
Handle IndexToPlugin(int index)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_Plugin);
return view_as<Handle>(ReadPackCell(hPluginPack));
}
void Updater_AddPlugin(Handle plugin, const char[] url)
{
int index = PluginToIndex(plugin);
if (index != -1)
{
// Remove plugin from removal queue.
int maxPlugins = GetArraySize(g_hRemoveQueue);
for (int i = 0; i < maxPlugins; i++)
{
if (plugin == GetArrayCell(g_hRemoveQueue, i))
{
RemoveFromArray(g_hRemoveQueue, i);
break;
}
}
// Update the url.
Updater_SetURL(index, url);
}
else
{
Handle hPluginPack = CreateDataPack();
Handle hFiles = CreateArray(PLATFORM_MAX_PATH);
PluginPack_Plugin = GetPackPosition(hPluginPack);
WritePackCell(hPluginPack, view_as<int>(plugin));
PluginPack_Files = GetPackPosition(hPluginPack);
WritePackCell(hPluginPack, view_as<int>(hFiles));
PluginPack_Status = GetPackPosition(hPluginPack);
WritePackCell(hPluginPack, view_as<int>(Status_Idle));
PluginPack_URL = GetPackPosition(hPluginPack);
WritePackString(hPluginPack, url);
PushArrayCell(g_hPluginPacks, hPluginPack);
}
}
void Updater_QueueRemovePlugin(Handle plugin)
{
/* Flag a plugin for removal. */
int maxPlugins = GetArraySize(g_hRemoveQueue);
for (int i = 0; i < maxPlugins; i++)
{
// Make sure it wasn't previously flagged.
if (plugin == GetArrayCell(g_hRemoveQueue, i))
{
return;
}
}
PushArrayCell(g_hRemoveQueue, plugin);
Updater_FreeMemory();
}
void Updater_RemovePlugin(int index)
{
/* Warning: Removing a plugin will shift indexes. */
CloseHandle(Updater_GetFiles(index)); // hFiles
CloseHandle(GetArrayCell(g_hPluginPacks, index)); // hPluginPack
RemoveFromArray(g_hPluginPacks, index);
}
Handle Updater_GetFiles(int index)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_Files);
return view_as<Handle>(ReadPackCell(hPluginPack));
}
UpdateStatus Updater_GetStatus(int index)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_Status);
return view_as<UpdateStatus>(ReadPackCell(hPluginPack));
}
void Updater_SetStatus(int index, UpdateStatus status)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_Status);
WritePackCell(hPluginPack, view_as<int>(status));
}
void Updater_GetURL(int index, char[] buffer, int size)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_URL);
ReadPackString(hPluginPack, buffer, size);
}
void Updater_SetURL(int index, const char[] url)
{
Handle hPluginPack = GetArrayCell(g_hPluginPacks, index);
SetPackPosition(hPluginPack, PluginPack_URL);
WritePackString(hPluginPack, url);
}
/* Stocks */
stock void ReloadPlugin(Handle plugin=INVALID_HANDLE)
{
char filename[64];
GetPluginFilename(plugin, filename, sizeof(filename));
ServerCommand("sm plugins reload %s", filename);
}
stock void UnloadPlugin(Handle plugin=INVALID_HANDLE)
{
char filename[64];
GetPluginFilename(plugin, filename, sizeof(filename));
ServerCommand("sm plugins unload %s", filename);
}
stock void DisablePlugin(Handle plugin=INVALID_HANDLE)
{
char filename[64];
char path_disabled[PLATFORM_MAX_PATH];
char path_plugin[PLATFORM_MAX_PATH];
GetPluginFilename(plugin, filename, sizeof(filename));
BuildPath(Path_SM, path_disabled, sizeof(path_disabled), "plugins/disabled/%s", filename);
BuildPath(Path_SM, path_plugin, sizeof(path_plugin), "plugins/%s", filename);
if (FileExists(path_disabled))
{
DeleteFile(path_disabled);
}
if (!RenameFile(path_disabled, path_plugin))
{
DeleteFile(path_plugin);
}
ServerCommand("sm plugins unload %s", filename);
}