// Call a function on a remote server
int CLuaFunctionDefs::FetchRemote ( lua_State* luaVM )
{
    //  bool fetchRemote ( string URL [, int connectionAttempts = 10, int connectTimeout = 10000 ], callback callbackFunction, [ string postData, bool bPostBinary, arguments... ] )
    CScriptArgReader argStream ( luaVM );
    SString strURL; CLuaFunctionRef iLuaFunction; SString strPostData; bool bPostBinary; CLuaArguments args; uint uiConnectionAttempts; uint uiConnectTimeoutMs;

    argStream.ReadString ( strURL );
    if ( argStream.NextIsNumber () )
        MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECTION_ATTEMPTS, "'connection attempts' is being used" );
    argStream.ReadIfNextIsNumber ( uiConnectionAttempts, 10 );
    if ( argStream.NextIsNumber () )
        MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECT_TIMEOUT, "'connect timeout' is being used" );
    argStream.ReadIfNextIsNumber ( uiConnectTimeoutMs, 10000 );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadString ( strPostData, "" );
    argStream.ReadBool ( bPostBinary, false );
    argStream.ReadLuaArguments ( args );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        CLuaMain * luaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( luaMain )
        {
            g_pGame->GetRemoteCalls ()->Call ( strURL, &args, strPostData, bPostBinary, luaMain, iLuaFunction, uiConnectionAttempts, uiConnectTimeoutMs );
            lua_pushboolean ( luaVM, true );
            return 1;
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::RemoveCommandHandler ( lua_State* luaVM )
{
    //  bool removeCommandHandler ( string commandName [, function handler] )
    SString strKey; CLuaFunctionRef iLuaFunction;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strKey );
    argStream.ReadFunction ( iLuaFunction, LUA_REFNIL );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Grab our VM
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            // Remove it from our list
            if ( m_pRegisteredCommands->RemoveCommand ( pLuaMain, strKey, iLuaFunction ) )
            {
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
Esempio n. 3
0
int CLuaFunctionDefs::RemoveEventHandler ( lua_State* luaVM )
{
//  bool removeEventHandler ( string eventName, element attachedTo, function functionVar )
    SString strName; CClientEntity* pEntity; CLuaFunctionRef iLuaFunction;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strName );
    argStream.ReadUserData ( pEntity );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Grab our virtual machine
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            // Do it
            if ( CStaticFunctionDefinitions::RemoveEventHandler ( *pLuaMain, strName, *pEntity, iLuaFunction ) )
            {
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, SString ( "Bad argument @ '%s' [%s]", "removeEventHandler", *argStream.GetErrorMessage () ) );

    // Failed
    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::AddCommandHandler ( lua_State* luaVM )
{
    //  bool addCommandHandler ( string commandName, function handlerFunction, [bool restricted = false, bool caseSensitive = true] )
    SString strKey; CLuaFunctionRef iLuaFunction; bool bRestricted; bool bCaseSensitive;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strKey );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadBool ( bRestricted, false );
    argStream.ReadBool ( bCaseSensitive, true );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Grab our VM
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            // Add them to our list over command handlers
            if ( m_pRegisteredCommands->AddCommand ( pLuaMain, strKey, iLuaFunction, bRestricted, bCaseSensitive ) )
            {
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::RequestBrowserDomains ( lua_State* luaVM )
{
//  bool requestBrowserDomains ( table domains, bool isURL [, function callback ] )
    std::vector<SString> pages; bool bIsURL; CLuaFunctionRef callbackFunction;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadStringTable ( pages );
    argStream.ReadBool ( bIsURL, false );
    argStream.ReadFunction ( callbackFunction, LUA_REFNIL );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Convert to domains if we got a list of URLs
        if ( bIsURL )
        {
            for ( auto& strURL : pages )
            {
                strURL = g_pCore->GetWebCore ()->GetDomainFromURL ( strURL );
            }
        }

        WebRequestCallback callback = [=]( bool bAllow, const std::vector<SString>& domains ) {
            // Test if luaVM is still available
            if ( m_pLuaManager->IsLuaVMValid ( luaVM ) && VERIFY_FUNCTION ( callbackFunction ) )
            {
                CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
                if ( !pLuaMain )
                    return;

                CLuaArguments arguments;
                arguments.PushBoolean ( bAllow );
                
                CLuaArguments LuaTable;
                int i = 0;
                for ( const auto& domain : domains )
                {
                    LuaTable.PushNumber ( ++i );
                    LuaTable.PushString ( domain );
                }
                arguments.PushTable ( &LuaTable );
                arguments.Call ( pLuaMain, callbackFunction );
            }
        };

        g_pCore->GetWebCore ()->RequestPages ( pages, VERIFY_FUNCTION ( callbackFunction ) ? &callback : nullptr );
        lua_pushboolean ( luaVM, true );
        return 1;
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
Esempio n. 6
0
int CLuaDatabaseDefs::OOP_DbQuery ( lua_State* luaVM )
{
    //  handle dbQuery ( [ function callbackFunction, [ table callbackArguments, ] ] element connection, string query, ... )
    CLuaFunctionRef iLuaFunction; CLuaArguments callbackArgs; CDatabaseConnectionElement* pElement; SString strQuery; CLuaArguments Args;

    CScriptArgReader argStream ( luaVM );

    argStream.ReadUserData ( pElement );
    if ( argStream.NextIsFunction () )
    {
        argStream.ReadFunction ( iLuaFunction );
        if ( argStream.NextIsTable () )
        {
            argStream.ReadLuaArgumentsTable( callbackArgs );
        }
    }
    argStream.ReadString ( strQuery );
    argStream.ReadLuaArguments ( Args );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Start async query
        CDbJobData* pJobData = g_pGame->GetDatabaseManager ()->QueryStart ( pElement->GetConnectionHandle (), strQuery, &Args );
        if ( !pJobData )
        {
            if ( !g_pGame->GetDatabaseManager ()->IsLastErrorSuppressed () )
                m_pScriptDebugging->LogWarning ( luaVM, "%s failed; %s", lua_tostring ( luaVM, lua_upvalueindex ( 1 ) ), *g_pGame->GetDatabaseManager ()->GetLastErrorMessage () );
            lua_pushboolean ( luaVM, false );
            return 1;
        }
        // Make callback function if required
        if ( VERIFY_FUNCTION ( iLuaFunction ) )
        {
            CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
            if ( pLuaMain )
            {
                CLuaArguments Arguments;
                Arguments.PushDbQuery ( pJobData );
                Arguments.PushArguments ( callbackArgs );
                pJobData->SetCallback ( CLuaDatabaseDefs::DbQueryCallback, g_pGame->GetLuaCallbackManager ()->CreateCallback ( pLuaMain, iLuaFunction, Arguments ) );
            }
        }
        // Add debug info incase query result does not get collected
        pJobData->SetLuaDebugInfo ( g_pGame->GetScriptDebugging ()->GetLuaDebugInfo ( luaVM ) );
        lua_pushquery ( luaVM, pJobData );
        return 1;
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::UnbindKey ( lua_State* luaVM )
{
    SString strKey = "", strHitState = "";
    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strKey );

    if ( !argStream.HasErrors ( ) )
    {
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            if ( argStream.NextIsString ( 1 ) ) // Check if has command
            {
                // bool unbindKey ( string key, string keyState, string command )
                SString strResource = pLuaMain->GetResource()->GetName();
                SString strCommand = "";
                argStream.ReadString ( strHitState );
                argStream.ReadString ( strCommand );
                if ( !argStream.HasErrors ( ) )
                {
                    if ( CStaticFunctionDefinitions::UnbindKey ( strKey, strHitState, strCommand, strResource ) )
                    {
                        lua_pushboolean ( luaVM, true );
                        return 1;
                    }
                }
            }
            else
            {
                // bool unbindKey ( string key, [ string keyState, function handler ] )
                CLuaFunctionRef iLuaFunction;
                argStream.ReadString ( strHitState, "" );
                argStream.ReadFunction ( iLuaFunction, LUA_REFNIL );
                argStream.ReadFunctionComplete ();
                if ( !argStream.HasErrors ( ) )
                {
                    const char* szHitState = strHitState == "" ? NULL : strHitState.c_str();
                    if ( CStaticFunctionDefinitions::UnbindKey ( strKey, pLuaMain, szHitState, iLuaFunction ) )
                    {
                        lua_pushboolean ( luaVM, true );
                        return 1;
                    }
                }
            }
        }
    }

    if ( argStream.HasErrors ( ) )
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() );

    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::BindKey ( lua_State* luaVM )
{
    SString strKey = "", strHitState = "", strCommand = "", strArguments = "";
    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strKey );
    argStream.ReadString ( strHitState );

    if ( !argStream.HasErrors ( ) )
    {
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            if ( argStream.NextIsString ( ) )
            {
                // bindKey ( string key, string keyState, string commandName, [ string arguments ] )
                SString strResource = pLuaMain->GetResource()->GetName();
                argStream.ReadString ( strCommand );
                argStream.ReadString ( strArguments, "" );
                if ( !argStream.HasErrors ( ) )
                {
                    if ( CStaticFunctionDefinitions::BindKey ( strKey, strHitState, strCommand, strArguments, strResource ) )
                    {
                        lua_pushboolean ( luaVM, true );
                        return 1;
                    }  
                }
            }
            else
            {
                // bindKey ( string key, string keyState, function handlerFunction,  [ var arguments, ... ] )
                CLuaFunctionRef iLuaFunction;
                CLuaArguments Arguments;
                argStream.ReadFunction ( iLuaFunction );
                argStream.ReadLuaArguments ( Arguments );
                argStream.ReadFunctionComplete ();
                if ( !argStream.HasErrors ( ) )
                {
                    if ( CStaticFunctionDefinitions::BindKey ( strKey, strHitState, pLuaMain, iLuaFunction, Arguments ) )
                    {
                        lua_pushboolean ( luaVM, true );
                        return 1;
                    }
                }
            }
        }
    }

    if ( argStream.HasErrors ( ) )
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() );

    lua_pushboolean ( luaVM, false );
    return 1;
}
Esempio n. 9
0
int CLuaTimerDefs::SetTimer ( lua_State* luaVM )
{
    //  timer setTimer ( function theFunction, int timeInterval, int timesToExecute, [ var arguments... ] )
    CLuaFunctionRef iLuaFunction; double dTimeInterval; uint uiTimesToExecute; CLuaArguments Arguments;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadNumber ( dTimeInterval );
    argStream.ReadNumber ( uiTimesToExecute );
    argStream.ReadLuaArguments ( Arguments );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        CLuaMain * luaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( luaMain )
        {
            // Check for the minimum interval
            if ( dTimeInterval < LUA_TIMER_MIN_INTERVAL )
            {
                argStream.SetCustomError ( "Interval is below 50" );
            }
            else
            {
                CLuaTimer* pLuaTimer = luaMain->GetTimerManager ()->AddTimer ( iLuaFunction, CTickCount ( dTimeInterval ), uiTimesToExecute, Arguments );
                if ( pLuaTimer )
                {
                    // Set our timer debug info (in case we don't have any debug info which is usually when you do setTimer(destroyElement, 50, 1) or such)
                    pLuaTimer->SetLuaDebugInfo ( g_pClientGame->GetScriptDebugging ()->GetLuaDebugInfo ( luaVM ) );

                    lua_pushtimer ( luaVM, pLuaTimer );
                    return 1;
                }
            }
        }
    }
    if ( argStream.HasErrors () )
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
Esempio n. 10
0
int CLuaFunctionDefs::AddEventHandler ( lua_State* luaVM )
{
//  bool addEventHandler ( string eventName, element attachedTo, function handlerFunction, [bool getPropagated = true] )
    SString strName; CClientEntity* pEntity; CLuaFunctionRef iLuaFunction; bool bPropagated;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadString ( strName );
    argStream.ReadUserData ( pEntity );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadBool ( bPropagated, true );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Grab our virtual machine
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            // Check if the handle is in use
            if ( pEntity->GetEventManager()->HandleExists ( pLuaMain, strName, iLuaFunction ) )
            {
                m_pScriptDebugging->LogCustom ( luaVM, 255, 0, 0, "addEventHandler: '%s' with this function is already handled", *strName );
                lua_pushboolean ( luaVM, false );
                return 1;
            }

            // Do it
            if ( CStaticFunctionDefinitions::AddEventHandler ( *pLuaMain, strName, *pEntity, iLuaFunction, bPropagated ) )
            {
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, SString ( "Bad argument @ '%s' [%s]", "addEventHandler", *argStream.GetErrorMessage () ) );

    // Failed
    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::GetBrowserSource ( lua_State* luaVM )
{
//  bool getBrowserSource ( function callback )
    CClientWebBrowser* pWebBrowser; CLuaFunctionRef callbackFunction;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadUserData ( pWebBrowser );
    argStream.ReadFunction ( callbackFunction );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain && VERIFY_FUNCTION ( callbackFunction ) )
        {
            pWebBrowser->GetSourceCode ( [callbackFunction, pLuaMain]( const std::string& code ) {
                /*
                    This function should not be called when the resource is about to stop as
                    stopping the resource destroys the browser element and thus cancels the 
                    CefStringVisitor callback class (see CWebView::GetSourceCode::MyStringVisitor)
                */
                if ( VERIFY_FUNCTION ( callbackFunction ) )
                {
                    CLuaArguments arguments;
                    // TODO: Use SCharStringRef/direct string access instead of copying strings around
                    arguments.PushString ( code );
                    arguments.Call ( pLuaMain, callbackFunction );
                }
            });

            lua_pushboolean ( luaVM, true );
            return 1;
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
// Call a function on a remote server
int CLuaFunctionDefs::CallRemote ( lua_State* luaVM )
{
    CScriptArgReader argStream ( luaVM );
    if ( !argStream.NextIsFunction ( 1 ) && !argStream.NextIsFunction ( 2 ) )
    {
        // Call type 1
        //  bool callRemote ( string host [, int connectionAttempts = 10, int connectTimeout = 10000 ], string resourceName, string functionName, callback callbackFunction, [ arguments... ] )
        SString strHost; uint uiConnectionAttempts; uint uiConnectTimeoutMs; SString strResourceName; SString strFunctionName; CLuaFunctionRef iLuaFunction; CLuaArguments args;

        argStream.ReadString ( strHost );
        if ( argStream.NextIsNumber () )
            MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECTION_ATTEMPTS, "'connection attempts' is being used" );
        argStream.ReadIfNextIsNumber ( uiConnectionAttempts, 10 );
        if ( argStream.NextIsNumber () )
            MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECT_TIMEOUT, "'connect timeout' is being used" );
        argStream.ReadIfNextIsNumber ( uiConnectTimeoutMs, 10000 );
        argStream.ReadString ( strResourceName );
        argStream.ReadString ( strFunctionName );
        argStream.ReadFunction ( iLuaFunction );
        argStream.ReadLuaArguments ( args );
        argStream.ReadFunctionComplete ();

        if ( !argStream.HasErrors () )
        {
            CLuaMain * luaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
            if ( luaMain )
            {
                g_pGame->GetRemoteCalls ()->Call ( strHost, strResourceName, strFunctionName, &args, luaMain, iLuaFunction, uiConnectionAttempts, uiConnectTimeoutMs );
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }
    else
    {
        // Call type 2
        //  bool callRemote ( string URL [, int connectionAttempts = 10, int connectTimeout = 10000 ], callback callbackFunction, [ arguments... ] )
        SString strURL; uint uiConnectionAttempts; uint uiConnectTimeoutMs; CLuaFunctionRef iLuaFunction; CLuaArguments args;

        argStream.ReadString ( strURL );
        if ( argStream.NextIsNumber () )
            MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECTION_ATTEMPTS, "'connection attempts' is being used" );
        argStream.ReadIfNextIsNumber ( uiConnectionAttempts, 10 );
        if ( argStream.NextIsNumber () )
            MinServerReqCheck ( argStream, MIN_SERVER_REQ_CALLREMOTE_CONNECT_TIMEOUT, "'connect timeout' is being used" );
        argStream.ReadIfNextIsNumber ( uiConnectTimeoutMs, 10000 );
        argStream.ReadFunction ( iLuaFunction );
        argStream.ReadLuaArguments ( args );
        argStream.ReadFunctionComplete ();

        if ( !argStream.HasErrors () )
        {
            CLuaMain * luaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
            if ( luaMain )
            {
                g_pGame->GetRemoteCalls ()->Call ( strURL, &args, luaMain, iLuaFunction, uiConnectionAttempts, uiConnectTimeoutMs );
                lua_pushboolean ( luaVM, true );
                return 1;
            }
        }
    }

    if ( argStream.HasErrors () )
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
Esempio n. 13
0
int CLuaResourceDefs::Load ( lua_State* luaVM )
{
    //  func,err load( callback callbackFunction[, string name] )
    CLuaFunctionRef iLuaFunction; SString strName;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadFunction ( iLuaFunction );
    argStream.ReadString ( strName, "=(load)" );
    argStream.ReadFunctionComplete ();

    if ( !argStream.HasErrors () )
    {
        // Call supplied function to get all the bits
        // Should apply some limit here?
        SString strInput;
        CLuaArguments callbackArguments;
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        while ( pLuaMain )
        {
            CLuaArguments returnValues;
            callbackArguments.Call ( pLuaMain, iLuaFunction, &returnValues );
            if ( returnValues.Count () )
            {
                CLuaArgument* returnedValue = *returnValues.IterBegin ();
                if ( returnedValue->GetType () == LUA_TSTRING )
                {
                    strInput += returnedValue->GetString ();
                    continue;
                }
            }
            break;
        }

        const char* szChunkname = *strName;
        const char* cpInBuffer = strInput;
        uint uiInSize = strInput.length ();

        // Deobfuscate if required
        const char* cpBuffer;
        uint uiSize;
        if ( !g_pNet->DeobfuscateScript ( cpInBuffer, uiInSize, &cpBuffer, &uiSize, m_pResourceManager->GetResourceName ( luaVM ) + "/load" ) )
        {
            SString strMessage ( "argument 2 is invalid. Please re-compile at http://luac.mtasa.com/", 0 );
            argStream.SetCustomError ( strMessage );
            cpBuffer = NULL;
            g_pCore->GetConsole ()->Print ( argStream.GetFullErrorMessage () );
            g_pClientGame->TellServerSomethingImportant ( 1005, argStream.GetFullErrorMessage (), 3 );
        }

        if ( !argStream.HasErrors () )
        {
            CLuaShared::CheckUTF8BOMAndUpdate ( &cpBuffer, &uiSize );
            if ( !CLuaMain::LuaLoadBuffer ( luaVM, cpBuffer, uiSize, szChunkname ) )
            {
                // Ok
                return 1;
            }
            else
            {
                lua_pushnil ( luaVM );
                lua_insert ( luaVM, -2 );  /* put before error message */
                return 2;  /* return nil plus error message */
            }
        }
    }
    if ( argStream.HasErrors () )
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
int CLuaFunctionDefs::SetBrowserAjaxHandler ( lua_State* luaVM )
{
    //  bool setBrowserAjaxHandler ( browser browser, string URL[, function callback] )
    CClientWebBrowser* pWebBrowser; SString strURL; CLuaFunctionRef callbackFunction;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadUserData ( pWebBrowser );
    argStream.ReadString ( strURL );

    if ( argStream.NextIsNil () || argStream.NextIsNone () )
    {
        if ( !argStream.HasErrors () )
        {
            lua_pushboolean ( luaVM, pWebBrowser->RemoveAjaxHandler ( strURL ) );
            return 1;
        }
        else
            m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );
    }
    else
    {
        argStream.ReadFunction ( callbackFunction );
        argStream.ReadFunctionComplete ();
        if ( !argStream.HasErrors () )
        {
            CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
            if ( pLuaMain && VERIFY_FUNCTION ( callbackFunction ) )
            {
                CResource* pResource = pLuaMain->GetResource ();
                CResourceManager * pResourceManager = m_pResourceManager;
                auto netId = pResource->GetNetID ();

                bool bResult = pWebBrowser->AddAjaxHandler ( strURL, 
                [=] ( std::vector<SString>& vecGet, std::vector<SString>& vecPost ) -> const SString
                {
                    // Make sure the resource is still running
                    if ( !pResourceManager->Exists ( pResource ) || pResource->GetNetID() != netId )
                    {
                        return "";
                    }

                    // Make sure the function is valid
                    if ( VERIFY_FUNCTION ( callbackFunction ) )
                    {
                        CLuaArguments arguments;
                        CLuaArguments getArguments;
                        CLuaArguments postArguments;

                        for ( auto&& param : vecGet )
                            getArguments.PushString ( param );

                        for ( auto&& param : vecPost )
                            postArguments.PushString ( param );

                        arguments.PushTable ( &getArguments );
                        arguments.PushTable ( &postArguments );

                        CLuaArguments result;
                        
                        arguments.Call ( pLuaMain, callbackFunction, &result );

                        if ( result.Count () == 0 )
                            return "";


                        CLuaArgument* returnedValue = *result.IterBegin ();
                        if ( returnedValue->GetType () == LUA_TSTRING )                       
                            return returnedValue->GetString ();
                        else
                            return "";
                    }
                    else
                        return "";

                } );

                lua_pushboolean ( luaVM, bResult );
                return 1;
            }
        }
        else
            m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );
    }

    lua_pushboolean ( luaVM, false );
    return 1;
}