Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion buildbot/PackageScript
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ builder.SetBuildFolder('package')
folder_list = [
'addons/sourcemod/extensions',
'addons/sourcemod/gamedata',
'addons/sourcemod/configs'
'addons/sourcemod/configs',
'addons/sourcemod/scripting',
'addons/sourcemod/scripting/include',
]

# Are we build a x86_64 extension ?
Expand Down Expand Up @@ -42,6 +44,20 @@ def CopyDirContent(src, dest):
if item.is_file():
builder.AddCopy(item.path, dest_entry)

# Include files
CopyFiles('scripting/include', 'addons/sourcemod/scripting/include',
[
'accelerator.inc',
]
)

# Example files
CopyFiles('scripting', 'addons/sourcemod/scripting',
[
'accelerator_example.sp',
]
)

# Copy binaries.
for task in Accelerator.extension:
if task.target.arch == 'x86_64':
Expand Down
2 changes: 2 additions & 0 deletions extension/AMBuilder
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ project = builder.LibraryProject('accelerator.ext')
project.sources = [
'extension.cpp',
'MemoryDownloader.cpp',
'forwards.cpp',
'natives.cpp',
os.path.join(Accelerator.sm_root, 'public', 'smsdk_ext.cpp')
]

Expand Down
65 changes: 65 additions & 0 deletions extension/extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include <IWebternet.h>
#include "MemoryDownloader.h"
#include "forwards.h"
#include "natives.h"

#if defined _LINUX
#include "client/linux/handler/exception_handler.h"
Expand Down Expand Up @@ -464,6 +466,8 @@ class UploadThread: public IThread
count++;
g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response);
if (log) fprintf(log, "Uploaded crash dump: %s\n", response);
UploadedCrash crash{ response };
g_accelerator.StoreUploadedCrash(crash);
} else {
failed++;
g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response);
Expand Down Expand Up @@ -495,6 +499,7 @@ class UploadThread: public IThread
log = nullptr;
}

g_accelerator.MarkAsDoneUploading();
rootconsole->ConsolePrint("Accelerator upload thread finished. (%d skipped, %d uploaded, %d failed)", skip, count, failed);
}

Expand Down Expand Up @@ -1080,6 +1085,25 @@ class UploadThread: public IThread
}
} uploadThread;

class SourcePawnNotifyThread : public IThread
{
public:

void RunThread(IThreadHandle* pHandle) {
for (;;) {
// Wait until OnMapStart is called once, this should be enough delay to make sure plugins are loaded.
if (g_accelerator.IsMapStarted() && g_accelerator.IsDoneUploading()) {
extforwards::CallOnDoneUploadingForward();
break;
}
}
}

void OnTerminate(IThreadHandle* pHandle, bool cancel) {
}

} spNotifyThread;

class VFuncEmptyClass {};

const char *GetCmdLine()
Expand Down Expand Up @@ -1117,6 +1141,11 @@ const char *GetCmdLine()
return (const char *)(reinterpret_cast<VFuncEmptyClass*>(cmdline)->*u.mfpnew)();
}

Accelerator::Accelerator() :
m_doneuploading(false), m_maphasstarted(false)
{
}

bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
sharesys->AddDependency(myself, "webternet.ext", true, true);
Expand All @@ -1142,6 +1171,7 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
strncpy(crashGameDirectory, g_pSM->GetGameFolderName(), sizeof(crashGameDirectory) - 1);

threader->MakeThread(&uploadThread);
threader->MakeThread(&spNotifyThread); // This thread waits for accelator to be done uploading and for the first OnMapStart call, then fires a SourceMod forward

do {
char gameconfigError[256];
Expand Down Expand Up @@ -1321,6 +1351,7 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)

void Accelerator::SDK_OnUnload()
{
extforwards::Shutdown();
plsys->RemovePluginsListener(this);

#if defined _LINUX
Expand All @@ -1336,9 +1367,21 @@ void Accelerator::SDK_OnUnload()
delete handler;
}

void Accelerator::SDK_OnAllLoaded()
{
extforwards::Init();
sharesys->RegisterLibrary(myself, "accelerator");

natives::Setup(m_natives);
m_natives.push_back({ nullptr, nullptr }); // SM requires this to signal the end of the native info array

sharesys->AddNatives(myself, m_natives.data());
}

void Accelerator::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
{
strncpy(crashMap, gamehelpers->GetCurrentMap(), sizeof(crashMap) - 1);
m_maphasstarted.store(true);
}

/* 010 Editor Template
Expand Down Expand Up @@ -1499,3 +1542,25 @@ void Accelerator::OnPluginUnloaded(IPlugin *plugin)

SerializePluginContexts();
}

void Accelerator::StoreUploadedCrash(UploadedCrash& crash)
{
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
m_uploadedcrashes.push_back(std::move(crash));
}

const UploadedCrash* Accelerator::GetUploadedCrash(int element) const
{
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
if (element < 0 || element >= static_cast<int>(m_uploadedcrashes.size())) {
return nullptr;
}

return &m_uploadedcrashes[element];
}

cell_t Accelerator::GetUploadedCrashCount() const
{
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
return static_cast<cell_t>(m_uploadedcrashes.size());
}
68 changes: 68 additions & 0 deletions extension/extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,36 @@
* @brief Accelerator extension code header.
*/

#include <atomic>
#include <vector>
#include <mutex>
#include "smsdk_ext.h"

/**
* @brief Represents a crash that has been successfully uploaded to Accelerator's backend
*/
class UploadedCrash
{
public:
UploadedCrash(const char* response) :
m_httpresponse(response)
{
}

const std::string& GetHTTPResponse() const { return m_httpresponse; }

private:
std::string m_httpresponse; // HTTP response from the crash upload in free form text.
};

/**
* @brief Sample implementation of the SDK Extension.
*/
class Accelerator : public SDKExtension, IPluginsListener
{
public: // SDKExtension
Accelerator();

/**
* @brief This is called after the initial loading sequence has been processed.
*
Expand All @@ -49,6 +71,11 @@ class Accelerator : public SDKExtension, IPluginsListener
*/
virtual void SDK_OnUnload();

/**
* @brief This is called once all known extensions have been loaded.
*/
virtual void SDK_OnAllLoaded();

/**
* @brief Called on server activation before plugins receive the OnServerLoad forward.
*
Expand All @@ -68,6 +95,47 @@ class Accelerator : public SDKExtension, IPluginsListener
* @brief Called when a plugin is unloaded (only if fully loaded).
*/
virtual void OnPluginUnloaded(IPlugin *plugin);

/**
* @brief Stores an uploaded crash into the vector.
* @param crash Uploaded crash instance to store.
*/
void StoreUploadedCrash(UploadedCrash& crash);
/**
* @brief Retrieves an uploaded crash from the given element.
* @param element Vector element (index) to read.
* @return Upload crash if found or NULL if out of bounds.
*/
const UploadedCrash* GetUploadedCrash(int element) const;
/**
* @brief Returns the number of uploaded crashes (for SourcePawn plugins).
* @return Number of uploaded crashes.
*/
cell_t GetUploadedCrashCount() const;
/**
* @brief Signals the extension that uploading is done.
*/
void MarkAsDoneUploading() { m_doneuploading.store(true); }
/**
* @brief Is Accelerator done uploading crashes.
* @return Returns true if yes, false otherwise.
*/
bool IsDoneUploading() const { return m_doneuploading.load(); }
/**
* @brief Has the 'OnMapStart' function called at least once.
* @return True if yes, false otherwise.
*/
bool IsMapStarted() const { return m_maphasstarted.load(); }

private:
std::vector<UploadedCrash> m_uploadedcrashes; // Vector of uploaded crashes
std::vector<sp_nativeinfo_t> m_natives; // Vector of SourcePawn natives
mutable std::mutex m_uploadedcrashes_mutex; // mutex for accessing the m_uploadedcrashes vector
std::atomic_bool m_doneuploading; // Signals that Accelerator is done uploading crashes.
std::atomic_bool m_maphasstarted; // Signals that OnMapStart has been called at least once.
};

// Expose the extension singleton.
extern Accelerator g_accelerator;

#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
36 changes: 36 additions & 0 deletions extension/forwards.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <array>
#include <string>
#include "extension.h"
#include "forwards.h"


static SourceMod::IForward* s_ondoneuploadingforward = nullptr;

static void OnDoneUploadingCallback(void* data)
{
if (s_ondoneuploadingforward) {
s_ondoneuploadingforward->Execute();
}
}


void extforwards::Init()
{
s_ondoneuploadingforward = forwards->CreateForward("Accelerator_OnDoneUploadingCrashes", SourceMod::ExecType::ET_Ignore, 0, nullptr);
}

void extforwards::Shutdown()
{
if (s_ondoneuploadingforward) {
forwards->ReleaseForward(s_ondoneuploadingforward);
s_ondoneuploadingforward = nullptr;
}
}

void extforwards::CallOnDoneUploadingForward()
{
// It's obligatory to use AddFrameAction here because SourcePawn forwards can only be called from the server's main thread.
// AddFrameAction will do this for us and is also thread safe.
smutils->AddFrameAction(OnDoneUploadingCallback, nullptr);
Comment thread
sapphonie marked this conversation as resolved.
}

16 changes: 16 additions & 0 deletions extension/forwards.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef _INCLUDE_FORWARDS_H_
#define _INCLUDE_FORWARDS_H_

namespace extforwards
{
// Initialize the sourcepawn forwards.
void Init();
// Shutdown the sourcepawn forwards.
void Shutdown();
// Calls the on done uploadind forward. (thread safe)
void CallOnDoneUploadingForward();
}



#endif // !_INCLUDE_FORWARDS_H_
54 changes: 54 additions & 0 deletions extension/natives.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <algorithm>
#include <amtl/am-string.h>
#include "extension.h"
#include "natives.h"

static cell_t Native_GetUploadedCrashCount(IPluginContext* context, const cell_t* params)
{
return g_accelerator.GetUploadedCrashCount();
}

static cell_t Native_IsDoneUploadingCrashes(IPluginContext* context, const cell_t* params)
{
if (g_accelerator.IsDoneUploading()) {
return 1;
}

return 0;
}

static cell_t Native_GetCrashHTTPResponse(IPluginContext* context, const cell_t* params)
{
if (!g_accelerator.IsDoneUploading()) {
context->ReportError("Wait until accelerator is done uploading crashes before accessing crash information!");
return 0;
}

int element = static_cast<int>(params[1]);
const UploadedCrash* crash = g_accelerator.GetUploadedCrash(element);

if (!crash) {
context->ReportError("Crash index %i is invalid!", element);
return 0;
}

char* buffer;
context->LocalToString(params[2], &buffer);

size_t maxsize = static_cast<size_t>(params[3]);

ke::SafeStrcpy(buffer, maxsize, crash->GetHTTPResponse().c_str());

return 0;
}

void natives::Setup(std::vector<sp_nativeinfo_t>& vec)
{
sp_nativeinfo_t list[] = {
{"Accelerator_GetUploadedCrashCount", Native_GetUploadedCrashCount},
{"Accelerator_IsDoneUploadingCrashes", Native_IsDoneUploadingCrashes},
{"Accelerator_GetCrashHTTPResponse", Native_GetCrashHTTPResponse},
};

vec.insert(vec.end(), std::begin(list), std::end(list));
}
11 changes: 11 additions & 0 deletions extension/natives.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef _INCLUDE_NATIVES_H_
#define _INCLUDE_NATIVES_H_


namespace natives
{
// Called during the load process to setup the extension natives
void Setup(std::vector<sp_nativeinfo_t>& vec);
}

#endif // !_INCLUDE_NATIVES_H_
2 changes: 1 addition & 1 deletion extension/smsdk_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
//#define SMEXT_CONF_METAMOD

/** Enable interfaces you want to use here by uncommenting lines */
//#define SMEXT_ENABLE_FORWARDSYS
#define SMEXT_ENABLE_FORWARDSYS
//#define SMEXT_ENABLE_HANDLESYS
//#define SMEXT_ENABLE_PLAYERHELPERS
//#define SMEXT_ENABLE_DBMANAGER
Expand Down
Loading