mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-09 01:07:16 +01:00
996c078105
Prevent releasing IRC sessions while they could still be in use. Few other changes that had to be committed because of the change in the module API.
331 lines
14 KiB
C++
331 lines
14 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Common.hpp"
|
|
#include "Manager.hpp"
|
|
#include "Connection.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Bind specific functions to certain server events.
|
|
*/
|
|
void BindCallbacks();
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Undo changes made with BindCallbacks().
|
|
*/
|
|
void UnbindCallbacks();
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Register the module API under the specified virtual machine.
|
|
*/
|
|
void RegisterAPI(HSQUIRRELVM vm);
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Initialize the plug-in by obtaining the API provided by the host plug-in.
|
|
*/
|
|
void OnSquirrelInitialize()
|
|
{
|
|
// Attempt to import the plug-in API exported by the host plug-in
|
|
_SqMod = sq_api_import(_Func);
|
|
// Did we failed to obtain the plug-in exports?
|
|
if (!_SqMod)
|
|
{
|
|
OutputError("Failed to attach [%s] on host plug-in.", SQMG_NAME);
|
|
}
|
|
else
|
|
{
|
|
// Obtain the Squirrel API
|
|
_SqAPI = _SqMod->GetSquirrelAPI();
|
|
// Expand the Squirrel API into global functions
|
|
sq_api_expand(_SqAPI);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Load the module on the virtual machine provided by the host module.
|
|
*/
|
|
void OnSquirrelLoad()
|
|
{
|
|
// Make sure that we have a valid plug-in API
|
|
if (!_SqMod)
|
|
{
|
|
return; // Unable to proceed.
|
|
}
|
|
// Obtain the Squirrel API and VM
|
|
_SqVM = _SqMod->GetSquirrelVM();
|
|
// Make sure that a valid virtual machine exists
|
|
if (!_SqVM)
|
|
{
|
|
return; // Unable to proceed.
|
|
}
|
|
// Set this as the default database
|
|
DefaultVM::Set(_SqVM);
|
|
// Register the module API
|
|
RegisterAPI(_SqVM);
|
|
// Notify about the current status
|
|
OutputMessage("Registered: %s", SQMG_NAME);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* The virtual machine is about to be terminated and script resources should be released.
|
|
*/
|
|
void OnSquirrelTerminate()
|
|
{
|
|
OutputMessage("Terminating: %s", SQMG_NAME);
|
|
// Release null objects just in case
|
|
NullObject().Release();
|
|
NullTable().Release();
|
|
NullArray().Release();
|
|
NullFunction().ReleaseGently();
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* The virtual machined was closed and all memory associated with it was released.
|
|
*/
|
|
void OnSquirrelReleased()
|
|
{
|
|
// Release the current virtual machine, if any
|
|
DefaultVM::Set(nullptr);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Validate the module API to make sure we don't run into issues.
|
|
*/
|
|
bool CheckAPIVer(CCStr ver)
|
|
{
|
|
// Obtain the numeric representation of the API version
|
|
const LongI vernum = std::strtol(ver, nullptr, 10);
|
|
// Check against version mismatch
|
|
if (vernum == SQMOD_API_VER)
|
|
{
|
|
return true;
|
|
}
|
|
// Log the incident
|
|
OutputError("API version mismatch on %s", SQMG_NAME);
|
|
OutputMessage("=> Requested: %ld Have: %ld", vernum, SQMOD_API_VER);
|
|
// Invoker should not attempt to communicate through the module API
|
|
return false;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* React to command sent by other plug-ins.
|
|
*/
|
|
static uint8_t OnPluginCommand(uint32_t command_identifier, CCStr message)
|
|
{
|
|
switch(command_identifier)
|
|
{
|
|
case SQMOD_INITIALIZE_CMD:
|
|
if (CheckAPIVer(message))
|
|
{
|
|
OnSquirrelInitialize();
|
|
}
|
|
break;
|
|
case SQMOD_LOAD_CMD:
|
|
OnSquirrelLoad();
|
|
break;
|
|
case SQMOD_TERMINATE_CMD:
|
|
OnSquirrelTerminate();
|
|
break;
|
|
case SQMOD_RELEASED_CMD:
|
|
OnSquirrelReleased();
|
|
break;
|
|
default: break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* The server was initialized and this plug-in was loaded successfully.
|
|
*/
|
|
static uint8_t OnServerInitialise()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void OnServerShutdown(void)
|
|
{
|
|
// The server may still send callbacks
|
|
UnbindCallbacks();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void BindCallbacks()
|
|
{
|
|
_Clbk->OnServerInitialise = OnServerInitialise;
|
|
_Clbk->OnServerShutdown = OnServerShutdown;
|
|
_Clbk->OnPluginCommand = OnPluginCommand;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void UnbindCallbacks()
|
|
{
|
|
_Clbk->OnServerInitialise = nullptr;
|
|
_Clbk->OnServerShutdown = nullptr;
|
|
_Clbk->OnPluginCommand = nullptr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void RegisterAPI(HSQUIRRELVM vm)
|
|
{
|
|
Table mgns(vm);
|
|
|
|
mgns.Bind(_SC("Manager"), Class< Manager >(vm, _SC("SqMgManager"))
|
|
// Constructors
|
|
.Ctor()
|
|
.Ctor< const Manager & >()
|
|
// Core Meta-methods
|
|
.Func(_SC("_cmp"), &Manager::Cmp)
|
|
.SquirrelFunc(_SC("_typename"), &Manager::Typename)
|
|
.Func(_SC("_tostring"), &Manager::ToString)
|
|
// Properties
|
|
//.Prop(_SC("Valid"), &Manager::IsValid)
|
|
// Member Methods
|
|
//.Func(_SC("Check"), &Manager::Check)
|
|
// Overloaded Methods
|
|
.Overload< Connection (Manager::*)(CSStr) const >(_SC("Bind"), &Manager::Bind)
|
|
.Overload< Connection (Manager::*)(CSStr, Uint32) const >(_SC("Bind"), &Manager::Bind)
|
|
.Overload< Connection (Manager::*)(CSStr) const >(_SC("Connect"), &Manager::Connect)
|
|
.Overload< Connection (Manager::*)(CSStr, Uint32) const >(_SC("Connect"), &Manager::Connect)
|
|
);
|
|
|
|
mgns.Bind(_SC("Connection"), Class< Connection >(vm, _SC("SqMgConnection"))
|
|
// Constructors
|
|
.Ctor()
|
|
.Ctor< const Connection & >()
|
|
// Core Meta-methods
|
|
.Func(_SC("_cmp"), &Connection::Cmp)
|
|
.SquirrelFunc(_SC("_typename"), &Connection::Typename)
|
|
.Func(_SC("_tostring"), &Connection::ToString)
|
|
// Properties
|
|
//.Prop(_SC("Valid"), &Connection::IsValid)
|
|
// Member Methods
|
|
//.Func(_SC("Check"), &Connection::Check)
|
|
);
|
|
|
|
RootTable(vm).Bind(_SC("SqMg"), mgns);
|
|
|
|
ConstTable(vm).Enum(_SC("EMgF"), Enumeration(vm)
|
|
.Const(_SC("LISTENING"), MG_F_LISTENING)
|
|
.Const(_SC("UDP"), MG_F_UDP)
|
|
.Const(_SC("RESOLVING"), MG_F_RESOLVING)
|
|
.Const(_SC("CONNECTING"), MG_F_CONNECTING)
|
|
.Const(_SC("SSL_HANDSHAKE_DONE"), MG_F_SSL_HANDSHAKE_DONE)
|
|
.Const(_SC("WANT_READ"), MG_F_WANT_READ)
|
|
.Const(_SC("WANT_WRITE"), MG_F_WANT_WRITE)
|
|
.Const(_SC("IS_WEBSOCKET"), MG_F_IS_WEBSOCKET)
|
|
.Const(_SC("SEND_AND_CLOSE"), MG_F_SEND_AND_CLOSE)
|
|
.Const(_SC("CLOSE_IMMEDIATELY"), MG_F_CLOSE_IMMEDIATELY)
|
|
.Const(_SC("WEBSOCKET_NO_DEFRAG"), MG_F_WEBSOCKET_NO_DEFRAG)
|
|
.Const(_SC("DELETE_CHUNK"), MG_F_DELETE_CHUNK)
|
|
.Const(_SC("USER_1"), MG_F_USER_1)
|
|
.Const(_SC("USER_2"), MG_F_USER_2)
|
|
.Const(_SC("USER_3"), MG_F_USER_3)
|
|
.Const(_SC("USER_4"), MG_F_USER_4)
|
|
.Const(_SC("USER_5"), MG_F_USER_5)
|
|
.Const(_SC("USER_6"), MG_F_USER_6)
|
|
);
|
|
|
|
ConstTable(vm).Enum(_SC("MgEv"), Enumeration(vm)
|
|
.Const(_SC("UNKNOWN"), static_cast< Int32 >(MGEV_UNKNOWN))
|
|
.Const(_SC("POLL"), static_cast< Int32 >(MGCE_POLL))
|
|
.Const(_SC("ACCEPT"), static_cast< Int32 >(MGCE_ACCEPT))
|
|
.Const(_SC("CONNECT"), static_cast< Int32 >(MGCE_CONNECT))
|
|
.Const(_SC("RECV"), static_cast< Int32 >(MGCE_RECV))
|
|
.Const(_SC("SEND"), static_cast< Int32 >(MGCE_SEND))
|
|
.Const(_SC("CLOSE"), static_cast< Int32 >(MGCE_CLOSE))
|
|
.Const(_SC("TIMER"), static_cast< Int32 >(MGCE_TIMER))
|
|
.Const(_SC("HTTP_REQUEST"), static_cast< Int32 >(MGCE_HTTP_REQUEST))
|
|
.Const(_SC("HTTP_REPLY"), static_cast< Int32 >(MGCE_HTTP_REPLY))
|
|
.Const(_SC("HTTP_CHUNK"), static_cast< Int32 >(MGCE_HTTP_CHUNK))
|
|
.Const(_SC("SSI_CALL"), static_cast< Int32 >(MGCE_SSI_CALL))
|
|
.Const(_SC("WEBSOCKET_HANDSHAKE_REQUEST"), static_cast< Int32 >(MGCE_WEBSOCKET_HANDSHAKE_REQUEST))
|
|
.Const(_SC("WEBSOCKET_HANDSHAKE_DONE"), static_cast< Int32 >(MGCE_WEBSOCKET_HANDSHAKE_DONE))
|
|
.Const(_SC("WEBSOCKET_FRAME"), static_cast< Int32 >(MGCE_WEBSOCKET_FRAME))
|
|
.Const(_SC("WEBSOCKET_CONTROL_FRAME"), static_cast< Int32 >(MGCE_WEBSOCKET_CONTROL_FRAME))
|
|
.Const(_SC("HTTP_MULTIPART_REQUEST"), static_cast< Int32 >(MGCE_HTTP_MULTIPART_REQUEST))
|
|
.Const(_SC("HTTP_PART_BEGIN"), static_cast< Int32 >(MGCE_HTTP_PART_BEGIN))
|
|
.Const(_SC("HTTP_PART_DATA"), static_cast< Int32 >(MGCE_HTTP_PART_DATA))
|
|
.Const(_SC("HTTP_PART_END"), static_cast< Int32 >(MGCE_HTTP_PART_END))
|
|
.Const(_SC("MQTT_CONNECT"), static_cast< Int32 >(MGCE_MQTT_CONNECT))
|
|
.Const(_SC("MQTT_CONNACK"), static_cast< Int32 >(MGCE_MQTT_CONNACK))
|
|
.Const(_SC("MQTT_PUBLISH"), static_cast< Int32 >(MGCE_MQTT_PUBLISH))
|
|
.Const(_SC("MQTT_PUBACK"), static_cast< Int32 >(MGCE_MQTT_PUBACK))
|
|
.Const(_SC("MQTT_PUBREC"), static_cast< Int32 >(MGCE_MQTT_PUBREC))
|
|
.Const(_SC("MQTT_PUBREL"), static_cast< Int32 >(MGCE_MQTT_PUBREL))
|
|
.Const(_SC("MQTT_PUBCOMP"), static_cast< Int32 >(MGCE_MQTT_PUBCOMP))
|
|
.Const(_SC("MQTT_SUBSCRIBE"), static_cast< Int32 >(MGCE_MQTT_SUBSCRIBE))
|
|
.Const(_SC("MQTT_SUBACK"), static_cast< Int32 >(MGCE_MQTT_SUBACK))
|
|
.Const(_SC("MQTT_UNSUBSCRIBE"), static_cast< Int32 >(MGCE_MQTT_UNSUBSCRIBE))
|
|
.Const(_SC("MQTT_UNSUBACK"), static_cast< Int32 >(MGCE_MQTT_UNSUBACK))
|
|
.Const(_SC("MQTT_PINGREQ"), static_cast< Int32 >(MGCE_MQTT_PINGREQ))
|
|
.Const(_SC("MQTT_PINGRESP"), static_cast< Int32 >(MGCE_MQTT_PINGRESP))
|
|
.Const(_SC("MQTT_DISCONNECT"), static_cast< Int32 >(MGCE_MQTT_DISCONNECT))
|
|
.Const(_SC("MQTT_CONNACK_ACCEPTED"), static_cast< Int32 >(MGCE_MQTT_CONNACK_ACCEPTED))
|
|
.Const(_SC("MQTT_CONNACK_UNACCEPTABLE_VERSION"), static_cast< Int32 >(MGCE_MQTT_CONNACK_UNACCEPTABLE_VERSION))
|
|
.Const(_SC("MQTT_CONNACK_IDENTIFIER_REJECTED"), static_cast< Int32 >(MGCE_MQTT_CONNACK_IDENTIFIER_REJECTED))
|
|
.Const(_SC("MQTT_CONNACK_SERVER_UNAVAILABLE"), static_cast< Int32 >(MGCE_MQTT_CONNACK_SERVER_UNAVAILABLE))
|
|
.Const(_SC("MQTT_CONNACK_BAD_AUTH"), static_cast< Int32 >(MGCE_MQTT_CONNACK_BAD_AUTH))
|
|
.Const(_SC("MQTT_CONNACK_NOT_AUTHORIZED"), static_cast< Int32 >(MGCE_MQTT_CONNACK_NOT_AUTHORIZED))
|
|
.Const(_SC("COAP_CON"), static_cast< Int32 >(MGCE_COAP_CON))
|
|
.Const(_SC("COAP_NOC"), static_cast< Int32 >(MGCE_COAP_NOC))
|
|
.Const(_SC("COAP_ACK"), static_cast< Int32 >(MGCE_COAP_ACK))
|
|
.Const(_SC("COAP_RST"), static_cast< Int32 >(MGCE_COAP_RST))
|
|
.Const(_SC("MAX"), static_cast< Int32 >(MGCE_MAX))
|
|
);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * functions, PluginCallbacks * callbacks, PluginInfo * info)
|
|
{
|
|
using namespace SqMod;
|
|
// Output plug-in header
|
|
std::puts("");
|
|
OutputMessage("--------------------------------------------------------------------");
|
|
OutputMessage("Plug-in: %s", SQMG_NAME);
|
|
OutputMessage("Author: %s", SQMG_AUTHOR);
|
|
OutputMessage("Legal: %s", SQMG_COPYRIGHT);
|
|
OutputMessage("--------------------------------------------------------------------");
|
|
std::puts("");
|
|
// Attempt to find the host plug-in ID
|
|
const int host_plugin_id = functions->FindPlugin(SQMOD_HOST_NAME);
|
|
// See if our plug-in was loaded after the host plug-in
|
|
if (host_plugin_id < 0)
|
|
{
|
|
OutputError("%s could find the host plug-in", SQMG_NAME);
|
|
// Don't load!
|
|
return SQMOD_FAILURE;
|
|
}
|
|
// Should never reach this point but just in case
|
|
else if (static_cast< Uint32 >(host_plugin_id) > info->pluginId)
|
|
{
|
|
OutputError("%s loaded after the host plug-in", SQMG_NAME);
|
|
// Don't load!
|
|
return SQMOD_FAILURE;
|
|
}
|
|
// Store server proxies
|
|
_Func = functions;
|
|
_Clbk = callbacks;
|
|
_Info = info;
|
|
// Assign plug-in version
|
|
_Info->pluginVersion = SQMG_VERSION;
|
|
_Info->apiMajorVersion = PLUGIN_API_MAJOR;
|
|
_Info->apiMinorVersion = PLUGIN_API_MINOR;
|
|
// Assign the plug-in name
|
|
std::snprintf(_Info->name, sizeof(_Info->name), "%s", SQMG_HOST_NAME);
|
|
// Bind callbacks
|
|
BindCallbacks();
|
|
// Notify that the plug-in was successfully loaded
|
|
OutputMessage("Successfully loaded %s", SQMG_NAME);
|
|
// Dummy spacing
|
|
std::puts("");
|
|
// Done!
|
|
return SQMOD_SUCCESS;
|
|
}
|