summaryrefslogtreecommitdiff
path: root/indra/llcommon/lualistener.h
blob: 85fb093cd635035e01cb5d90eac8f44870c04ff0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * @file   lualistener.h
 * @author Nat Goodspeed
 * @date   2024-02-06
 * @brief  Define LuaListener class
 * 
 * $LicenseInfo:firstyear=2024&license=viewerlgpl$
 * Copyright (c) 2024, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if ! defined(LL_LUALISTENER_H)
#define LL_LUALISTENER_H

#include "llevents.h"
#include "llinstancetracker.h"
#include "llsd.h"
#include "llthreadsafequeue.h"
#include <iosfwd>                   // std::ostream
#include <memory>                   // std::unique_ptr
#include <string>
#include <utility>                  // std::pair

struct lua_State;
class LLLeapListener;

/**
 * LuaListener is based on LLLeap. It serves an analogous function.
 *
 * Each LuaListener instance has an int key, generated randomly to
 * inconvenience malicious Lua scripts wanting to mess with others. The idea
 * is that a given lua_State stores in its Registry:
 * - "event.listener": the int key of the corresponding LuaListener, if any
 * The original thought was that LuaListener would itself store the Lua
 * function -- but surprisingly, there is no C/C++ type in the API that stores
 * a Lua function.
 *
 * (We considered storing in "event.listener" the LuaListener pointer itself
 * as a light userdata, but the problem would be if Lua code overwrote that.
 * We want to prevent any Lua script from crashing the viewer, intentionally
 * or otherwise. Safer to use a key lookup.)
 *
 * Like LLLeap, each LuaListener instance also has an associated
 * LLLeapListener to respond to LLEventPump management commands.
 */
class LuaListener: public LLInstanceTracker<LuaListener, int>
{
    using super = LLInstanceTracker<LuaListener, int>;
public:
    LuaListener(lua_State* L);

    LuaListener(const LuaListener&) = delete;
    LuaListener& operator=(const LuaListener&) = delete;

    ~LuaListener();

    std::string getReplyName() const;
    std::string getCommandName() const;

    /**
     * LuaListener enqueues reply events from its LLLeapListener on mQueue.
     * Call getNext() to retrieve the next such event. Blocks the calling
     * coroutine if the queue is empty.
     */
    using PumpData = std::pair<std::string, LLSD>;
    PumpData getNext();

    friend std::ostream& operator<<(std::ostream& out, const LuaListener& self);

private:
    static int getUniqueKey();
    bool queueEvent(const std::string& pump, const LLSD& data);

    LLThreadSafeQueue<PumpData> mQueue;

    std::string mCoroName;
    std::unique_ptr<LLLeapListener> mListener;
    LLTempBoundListener mShutdownConnection;
};

#endif /* ! defined(LL_LUALISTENER_H) */