SourcePawn:AutoUpdater

From Devicenull's Code

Jump to: navigation, search

This automatically installs and keeps plugins up to date

#pragma semicolon 1
#include <downloader>
#include <sourcemod>
#include <textparse>
#include <keyvalues>
#include <console>
 
public Plugin:myinfo = 
{
	name = "AutoUpdater",
	author = "devicenull",
	description = "Automatically updates plugins",
	version = "0.1.0.1",
	url = "http://plugins.devicenull.org/"
};
 
new Handle:cfgParser;
new Handle:dw;
 
#define MAX_PLUGINS 32
 
new String:PluginName[MAX_PLUGINS][256];
new PluginID[MAX_PLUGINS];
new PluginRev[MAX_PLUGINS];
 
new nextPlugin;
new curPlugin;
 
new String:recvBuffer[512];
 
new curState;
#define STATE_CHECKING 0
#define STATE_DOWNLOADING 1
#define STATE_IDLE 3
 
#define CFG_PATH "configs/autoupdate.cfg"
 
 
public OnPluginStart()
{
	RegServerCmd("sm_addplugin",sm_addplugin,"<pluginid> <pluginname> - Adds this plugin to your server");
	dw = CreateDownloader();
	if (dw == 0)
	{
    	PrintToServer("CreateHandle failed");
	}
	SetCallback(dw,DownloadComplete);
	PrintToServer("OnPluginStart");
}
 
public OnPluginEnd()
{
    PrintToServer("OnPluginEnd "); 
    if (!CloseHandle(dw))
    {
        PrintToServer("Couldn't close handle!");
	}
}
 
public OnServerLoad()
{
	LogToGame("Starting update checks...");
	//We only need to reload the config on mapchange
	decl String:path[128];
	BuildPath(Path_SM,path,128,CFG_PATH);
	nextPlugin = curPlugin = 0;
	ParseConfig(path);
	--nextPlugin;
	DoUpdate();
}
 
public DoUpdate()
{
	curState = STATE_CHECKING;
	curPlugin = 0;
	//We need at least one plugin to continue
	if (nextPlugin > 0)
	{
		DoUpdateCheck();
	}	
}
 
public Action:sm_addplugin(args)
{
	decl String:temp[64];
	decl nextPos;
	decl String:arguments[256];
	GetCmdArgString(arguments,256);
	nextPos = StrBreak(arguments,temp,64);
	if (nextPos == -1)
	{
		LogToGame("Usage: sm_addplugin <pluginid> <pluginname>");
		return Plugin_Handled;
	}
	PluginID[nextPlugin] = StringToInt(temp);
	StrBreak(arguments[nextPos],PluginName[nextPlugin],256);
 
	++nextPlugin;
	if (curState == STATE_IDLE)
	{
		DoUpdate();
	}
	return Plugin_Handled;
}
 
DoUpdateCheck()
{
	curState = STATE_CHECKING;
 
	ClearOutput(dw);
	SetOutputString(dw,recvBuffer,512);
 
	decl String:downloadurl[256];
	Format(downloadurl,256,"http://plugins.devicenull.org/checkupdates.php?pluginid=%i&revision=%i",PluginID[curPlugin],PluginRev[curPlugin]);
	SetURL(dw,downloadurl);
	curState = STATE_CHECKING;
	Download(dw);
}
 
EndUpdateCheck()
{
	curState = STATE_IDLE;
	decl String:temp[512];
	BuildPath(Path_SM,temp,512,CFG_PATH);
	WriteConfig(temp);
	CloseHandle(dw);
}
 
DownloadPlugin(pluginID)
{
	curState = STATE_DOWNLOADING;
 
	//Prepare to download the updated plugin
	ClearOutput(dw);
 
	decl String:temp[512];
	BuildPath(Path_SM,temp,512,"plugins/");
	Format(temp,512,"cstrike/%s%s.smx",temp,PluginName[pluginID]);
	SetOutputFile(dw,temp);
 
	Format(temp,512,"http://plugins.devicenull.org/getupdates.php?pluginid=%i",PluginID[pluginID]);
	SetURL(dw,temp);
	Download(dw);
 
}
 
public DownloadComplete(const sucess, const status, Handle:arg)
{
	if (curState == STATE_CHECKING)
	{
		if (strcmp(recvBuffer,"ok",false) == 0)
		{
			PrintToServer("Plugin %s is up to date",PluginName[curPlugin]);
			if (++curPlugin < nextPlugin)
			{
				DoUpdateCheck();
			}
			else
			{
				EndUpdateCheck();
			}
		}
		else if (StrContains(recvBuffer,"upd",false) != -1)
		{
			PrintToServer("Plugin %s needs an update",PluginName[curPlugin]);
			//Get the new revision number
			PluginRev[curPlugin] = StringToInt(recvBuffer[4]);
 
			DownloadPlugin(curPlugin);
 
		}		
	}
	else if (curState == STATE_DOWNLOADING)
	{
		curState = STATE_CHECKING;
		if (++curPlugin < nextPlugin)
		{
			DoUpdateCheck();
		}
		else
		{
			EndUpdateCheck();
		}
	}
 
}
 
WriteConfig(String:file[])
{
	new Handle:fl = OpenFile(file,"w");
	WriteFileLine(fl,"Plugins");
	WriteFileLine(fl,"{");
	for (new i=0;i<nextPlugin;++i)
	{
		PrintToServer("I: %i next: %i",i,nextPlugin);
		WriteFileLine(fl,"\t\"%s\"",PluginName[i]);
		WriteFileLine(fl,"\t{");
		WriteFileLine(fl,"\t\t\"id\"\t%i",PluginID[i]);
		WriteFileLine(fl,"\t\t\"rev\"\t%i",PluginRev[i]);
		WriteFileLine(fl,"\t}");
	}
	WriteFileLine(fl,"}");
	CloseHandle(fl);
}
 
public ParseConfig(String:cfgPath[])
{
	cfgParser = SMC_CreateParser();
	SMC_SetReaders(cfgParser
				,Config_NewSection
				,Config_NewValue
				,Config_EndSection);
 
	SMC_ParseFile(cfgParser,cfgPath);
}
 
public SMCResult:Config_NewSection(Handle:smc, const String:name[], bool:opt_quotes)
{
	strcopy(PluginName[nextPlugin],256,name);
 
	return SMCParse_Continue;
}
 
public SMCResult:Config_NewValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
{
	if (strcmp(key,"id",false)==0)
	{
		PluginID[nextPlugin] = StringToInt(value);	
	}
	else if (strcmp(key,"rev",false)==0)
	{
		PluginRev[nextPlugin] = StringToInt(value);
	}
	return SMCParse_Continue;
}
 
public SMCResult:Config_EndSection(Handle:smc)
{
	PrintToServer("Loaded plugin: %s - %i - %i",PluginName[nextPlugin],PluginID[nextPlugin],PluginRev[nextPlugin]);
	++nextPlugin;
	return SMCParse_Continue;
}