1
0

init commit

This commit is contained in:
2022-11-01 23:31:14 +08:00
commit 57c2c6a22e
26 changed files with 2208 additions and 0 deletions

204
envoy/envoy.cpp Normal file
View File

@@ -0,0 +1,204 @@
#include "envoy.h"
#include <string>
#include <iostream>
namespace lua {
/**
* A wrapper for a buffer.
*/
int BufferWrapper::luaLength(lua_State* state) {
lua_pushnumber(state, 0);
return 1;
}
int BufferWrapper::luaGetBytes(lua_State* state) {
lua_pushlstring(state, "buffer", 6);
return 1;
}
int BufferWrapper::luaSetBytes(lua_State* state) {
lua_pushnumber(state, 0);
return 1;
}
/**
* Lua wrapper for a header map. Methods that will modify the map will call a check function
* to see if modification is allowed.
*/
int HeaderMapWrapper::luaAdd(lua_State* state) {
UNUSED(state);
return 0;
}
int HeaderMapWrapper::luaGet(lua_State* state) {
UNUSED(state);
return 0;
}
int HeaderMapWrapper::luaPairs(lua_State* state) {
if (iterator_.get() != nullptr) {
luaL_error(state, "cannot create a second iterator before completing the first");
}
iterator_.reset(HeaderMapIterator::create(state), true);
lua_pushcclosure(state, HeaderMapIterator::static_luaPairsIterator, 1);
return 1;
}
int HeaderMapIterator::luaPairsIterator(lua_State* state) {
UNUSED(state);
return 0;
}
/**
* Lua wrapper for a metadata map.
*/
int MetadataMapWrapper::luaGet(lua_State* state) {
const char* key = luaL_checkstring(state, 2);
UNUSED(key);
return 0;
}
int MetadataMapWrapper::luaPairs(lua_State* state) {
if (iterator_.get() != nullptr) {
luaL_error(state, "cannot create a second iterator before completing the first");
}
iterator_.reset(MetadataMapIterator::create(state), true);
lua_pushcclosure(state, MetadataMapIterator::static_luaPairsIterator, 1);
return 1;
}
int MetadataMapIterator::luaPairsIterator(lua_State* state) {
UNUSED(state);
return 0;
}
/**
* Lua wrapper for a stream info.
*/
int StreamInfoWrapper::luaProtocol(lua_State* state) {
const std::string protocol = "HTTP/1.1";
lua_pushlstring(state, protocol.data(), protocol.size());
return 1;
}
int StreamInfoWrapper::luaDynamicMetadata(lua_State* state) {
UNUSED(state);
return 0;
}
int StreamInfoWrapper::luaDownstreamSslConnection(lua_State* state) {
lua_pushnil(state);
return 1;
}
int StreamInfoWrapper::luaDownstreamLocalAddress(lua_State* state) {
const std::string local_address = "127.0.0.1:1234";
lua_pushlstring(state, local_address.data(), local_address.size());
return 1;
}
int StreamInfoWrapper::luaDownstreamDirectRemoteAddress(lua_State* state) {
const std::string direct_remote_address = "172.17.0.3:80";
lua_pushlstring(state, direct_remote_address.data(), direct_remote_address.size());
return 1;
}
int StreamInfoWrapper::luaRequestedServerName(lua_State* state) {
const std::string server_name = "envoy";
lua_pushlstring(state, server_name.data(), server_name.size());
return 1;
}
/**
* A wrapper for a currently running request/response. This is the primary handle passed to Lua.
* The script interacts with Envoy entirely through this handle.
*/
int StreamHandleWrapper::luaHeaders(lua_State* state) {
if (headers_wrapper_.get() != nullptr) {
headers_wrapper_.pushStack();
} else {
headers_wrapper_.reset(HeaderMapWrapper::create(state), true);
}
return 1;
}
int StreamHandleWrapper::luaBody(lua_State* state) {
UNUSED(state);
return 0;
}
int StreamHandleWrapper::luaBodyChunks(lua_State* state) {
lua_pushcclosure(state, static_luaBodyIterator, 1);
return 1;
}
int StreamHandleWrapper::luaBodyIterator(lua_State* state) {
LuaDeathRef<BufferWrapper> wrapper;
wrapper.reset(BufferWrapper::create(state), true);
return 1;
}
int StreamHandleWrapper::luaMetadata(lua_State* state) {
if (metadata_wrapper_.get() != nullptr) {
metadata_wrapper_.pushStack();
} else {
metadata_wrapper_.reset(MetadataMapWrapper::create(state), true);
}
return 1;
}
int StreamHandleWrapper::luaStreamInfo(lua_State* state) {
if (stream_info_wrapper_.get() != nullptr) {
stream_info_wrapper_.pushStack();
} else {
stream_info_wrapper_.reset(StreamInfoWrapper::create(state), true);
}
return 1;
}
int luaLog(lua_State* state, const char* prefix) {
size_t input_size = 0;
const char* input = luaL_checklstring(state, 2, &input_size);
std::string message(input, input_size);
std::cout << prefix << ": " << message << std::endl;
return 0;
}
int StreamHandleWrapper::luaLogTrace(lua_State* state) {
return luaLog(state, "trace");
}
int StreamHandleWrapper::luaLogDebug(lua_State* state) {
return luaLog(state, "debug");
}
int StreamHandleWrapper::luaLogInfo(lua_State* state) {
return luaLog(state, "info");
}
int StreamHandleWrapper::luaLogWarn(lua_State* state) {
return luaLog(state, "warn");
}
int StreamHandleWrapper::luaLogErr(lua_State* state) {
return luaLog(state, "error");
}
int StreamHandleWrapper::luaLogCritical(lua_State* state) {
return luaLog(state, "crit");
}
int StreamHandleWrapper::luaHttpCall(lua_State* state) {
UNUSED(state);
return 0;
}
int StreamHandleWrapper::luaRespond(lua_State* state) {
UNUSED(state);
return 0;
}
}

130
envoy/envoy.h Normal file
View File

@@ -0,0 +1,130 @@
#pragma once
#include "lua.h"
namespace lua {
class BufferWrapper : public BaseLuaObject<BufferWrapper> {
public:
static ExportedFunctions exportedFunctions() {
return {{"length", static_luaLength},
{"getBytes", static_luaGetBytes},
{"setBytes", static_luaSetBytes}};
}
private:
DECLARE_LUA_FUNCTION(BufferWrapper, luaLength);
DECLARE_LUA_FUNCTION(BufferWrapper, luaGetBytes);
DECLARE_LUA_FUNCTION(BufferWrapper, luaSetBytes);
};
class HeaderMapIterator : public BaseLuaObject<HeaderMapIterator> {
public:
static ExportedFunctions exportedFunctions() { return {}; }
DECLARE_LUA_CLOSURE(HeaderMapIterator, luaPairsIterator);
};
class HeaderMapWrapper : public BaseLuaObject<HeaderMapWrapper> {
public:
static ExportedFunctions exportedFunctions() {
return {
{ "add", static_luaAdd },
{ "get", static_luaGet },
{ "__pairs", static_luaPairs },
};
}
private:
DECLARE_LUA_FUNCTION(HeaderMapWrapper, luaAdd);
DECLARE_LUA_FUNCTION(HeaderMapWrapper, luaGet);
DECLARE_LUA_FUNCTION(HeaderMapWrapper, luaPairs);
LuaDeathRef<HeaderMapIterator> iterator_;
};
class MetadataMapIterator : public BaseLuaObject<MetadataMapIterator> {
public:
static ExportedFunctions exportedFunctions() { return {}; }
DECLARE_LUA_CLOSURE(MetadataMapIterator, luaPairsIterator);
};
class MetadataMapWrapper : public BaseLuaObject<MetadataMapWrapper> {
public:
static ExportedFunctions exportedFunctions() {
return {{"get", static_luaGet}, {"__pairs", static_luaPairs}};
}
private:
DECLARE_LUA_FUNCTION(MetadataMapWrapper, luaGet);
DECLARE_LUA_FUNCTION(MetadataMapWrapper, luaPairs);
LuaDeathRef<MetadataMapIterator> iterator_;
};
class StreamInfoWrapper : public BaseLuaObject<StreamInfoWrapper> {
public:
static ExportedFunctions exportedFunctions() {
return {
{ "protocol", static_luaProtocol },
{ "dynamicMetadata", static_luaDynamicMetadata },
{ "downstreamLocalAddress", static_luaDownstreamLocalAddress },
{ "downstreamDirectRemoteAddress", static_luaDownstreamDirectRemoteAddress },
{ "downstreamSslConnection", static_luaDownstreamSslConnection },
{ "requestedServerName", static_luaRequestedServerName }
};
}
private:
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaProtocol);
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDynamicMetadata);
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDownstreamSslConnection);
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDownstreamLocalAddress);
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDownstreamDirectRemoteAddress);
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaRequestedServerName);
};
class StreamHandleWrapper : public BaseLuaObject<StreamHandleWrapper> {
public:
static ExportedFunctions exportedFunctions() {
return {
{ "headers", static_luaHeaders },
{ "body", static_luaBody },
{ "bodyChunks", static_luaBodyChunks },
{ "metadata", static_luaMetadata },
{ "streamInfo", static_luaStreamInfo },
{ "logTrace", static_luaLogTrace },
{ "logDebug", static_luaLogDebug },
{ "logInfo", static_luaLogInfo },
{ "logWarn", static_luaLogWarn },
{ "logErr", static_luaLogErr },
{ "logCritical", static_luaLogCritical },
{ "httpCall", static_luaHttpCall },
{ "respond", static_luaRespond },
};
}
private:
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaHeaders);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaBody);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaBodyChunks);
DECLARE_LUA_CLOSURE(StreamHandleWrapper, luaBodyIterator);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaMetadata);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaStreamInfo);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogTrace);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogDebug);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogInfo);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogWarn);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogErr);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaLogCritical);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaHttpCall);
DECLARE_LUA_FUNCTION(StreamHandleWrapper, luaRespond);
LuaDeathRef<HeaderMapWrapper> headers_wrapper_;
LuaDeathRef<MetadataMapWrapper> metadata_wrapper_;
LuaDeathRef<StreamInfoWrapper> stream_info_wrapper_;
};
}

105
envoy/envoy.vcxproj Normal file
View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E152FBD5-2A29-400E-8E18-9C515986217C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>envoy</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros">
<NuGetPackageImportStamp>3c953278</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Configuration)\$(PlatformTarget)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Configuration)\$(PlatformTarget)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Configuration)\$(PlatformTarget)\</OutDir>
<IntDir>$(SolutionDir)obj\$(Configuration)\$(PlatformTarget)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="envoy.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="envoy.h" />
<ClInclude Include="lua.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\luajit.native.2.0.5\build\native\luajit.native.targets" Condition="Exists('..\packages\luajit.native.2.0.5\build\native\luajit.native.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\luajit.native.2.0.5\build\native\luajit.native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\luajit.native.2.0.5\build\native\luajit.native.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="envoy.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="envoy.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="lua.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

292
envoy/lua.h Normal file
View File

@@ -0,0 +1,292 @@
#pragma once
#include <vector>
#include <memory>
#include <lua.hpp>
#define ASSERT(...)
#define UNUSED(x) (void)(x)
#ifndef alignof
#define alignof(T) std::alignment_of<T>::value
#endif
namespace lua {
/**
* Base macro for declaring a Lua/C function. Any function declared will need to be exported via
* the exportedFunctions() function in BaseLuaObject. See BaseLuaObject below for more
* information. This macro declares a static "thunk" which checks the user data, optionally checks
* for object death (again see BaseLuaObject below for more info), and then invokes a normal
* object method. The actual object method needs to be implemented by the class.
* @param Class supplies the owning class name.
* @param Name supplies the function name.
* @param Index supplies the stack index where "this" (Lua/C userdata) is found.
*/
#define DECLARE_LUA_FUNCTION_EX(Class, Name, Index) \
static int static_##Name(lua_State* state) { \
Class* object = lua::alignAndCast<Class>( \
luaL_checkudata(state, Index, typeid(Class).name())); \
object->checkDead(state); \
return object->Name(state); \
} \
int Name(lua_State* state);
/**
* Declare a Lua function in which userdata is in stack slot 1. See DECLARE_LUA_FUNCTION_EX()
*/
#define DECLARE_LUA_FUNCTION(Class, Name) DECLARE_LUA_FUNCTION_EX(Class, Name, 1)
/**
* Declare a Lua function in which userdata is in upvalue slot 1. See DECLARE_LUA_FUNCTION_EX()
*/
#define DECLARE_LUA_CLOSURE(Class, Name) DECLARE_LUA_FUNCTION_EX(Class, Name, lua_upvalueindex(1))
/**
* Calculate the maximum space needed to be aligned.
*/
template <typename T> size_t maximumSpaceNeededToAlign() {
// The allocated memory can be misaligned up to `alignof(T) - 1` bytes. Adding it to the size to
// allocate.
return sizeof(T) + alignof(T) - 1;
}
template <typename T> inline T* alignAndCast(void* mem) {
size_t size = maximumSpaceNeededToAlign<T>();
return static_cast<T*>(std::align(alignof(T), sizeof(T), mem, size));
}
/**
* Create a new user data and assign its metatable.
*/
template <typename T> inline T* allocateLuaUserData(lua_State* state) {
void* mem = lua_newuserdata(state, maximumSpaceNeededToAlign<T>());
luaL_getmetatable(state, typeid(T).name());
ASSERT(lua_istable(state, -1));
lua_setmetatable(state, -2);
return alignAndCast<T>(mem);
}
/**
* This is the base class for all C++ objects that we expose out to Lua. The goal is to hide as
* much ugliness as possible. In general, to use this, do the following:
* 1) Make your class derive from BaseLuaObject<YourClass>
* 2) Define methods using DECLARE_LUA_FUNCTION* macros
* 3) Export your functions by declaring a static exportedFunctions() method in your class.
* 4) Optionally manage "death" status on your object. (See checkDead() and markDead() below).
* 5) Generally you will want to hold your objects inside a LuaRef or a LuaDeathRef. See below
* for more information on those containers.
*
* It's very important to understand the Lua memory model: Once an object is created, *it is
* owned by Lua*. Lua can GC it at any time. If you want to make sure that does not happen, you
* must hold a ref to it in C++, generally via LuaRef or LuaDeathRef.
*/
template <class T> class BaseLuaObject {
public:
using ExportedFunctions = std::vector<std::pair<const char*, lua_CFunction>>;
virtual ~BaseLuaObject() = default;
/**
* Create a new object of this type, owned by Lua. This type must have previously been registered
* via the registerType() routine below.
* @param state supplies the owning Lua state.
* @param args supplies the variadic constructor arguments for the object.
* @return a pair containing a pointer to the new object and the state it was created with. (This
* is done for convenience when passing a created object to a LuaRef or a LuaDeathRef.
*/
template <typename... ConstructorArgs>
static std::pair<T*, lua_State*> create(lua_State* state, ConstructorArgs&&... args) {
// Memory is allocated via Lua and it is raw. We use placement new to run the constructor.
T* mem = allocateLuaUserData<T>(state);
return {new (mem) T(std::forward<ConstructorArgs>(args)...), state};
}
/**
* Register a type with Lua.
* @param state supplies the state to register with.
*/
static void registerType(lua_State* state) {
std::vector<luaL_Reg> to_register;
// Fetch all of the functions to be exported to Lua so that we can register them in the
// metatable.
ExportedFunctions functions = T::exportedFunctions();
for (auto function : functions) {
to_register.push_back({function.first, function.second});
}
// Always register a __gc method so that we can run the object's destructor. We do this
// manually because the memory is raw and was allocated by Lua.
to_register.push_back(
{"__gc", [](lua_State* state) {
T* object = alignAndCast<T>(luaL_checkudata(state, 1, typeid(T).name()));
object->~T();
return 0;
}});
// Add the sentinel.
to_register.push_back({nullptr, nullptr});
// Register the type by creating a new metatable, setting __index to itself, and then
// performing the register.
luaL_newmetatable(state, typeid(T).name());
lua_pushvalue(state, -1);
lua_setfield(state, -2, "__index");
luaL_register(state, nullptr, to_register.data());
}
/**
* This function is called as part of the DECLARE_LUA_FUNCTION* macros. The idea here is that
* we cannot control when Lua destroys things. However, we may expose wrappers to a script that
* should not be used after some event. This allows us to mark objects as dead so that if they
* are used again they will throw a Lua error and not reach our code.
* @param state supplies the calling LuaState.
*/
int checkDead(lua_State* state) {
if (dead_) {
return luaL_error(state, "object used outside of proper scope");
}
return 0;
}
/**
* Mark an object as dead so that a checkDead() call will throw an error. See checkDead().
*/
void markDead() {
dead_ = true;
onMarkDead();
}
/**
* Mark an object as live so that a checkDead() call will not throw an error. See checkDead().
*/
void markLive() {
dead_ = false;
onMarkLive();
}
protected:
/**
* Called from markDead() when an object is marked dead. This is effectively a C++ destructor for
* Lua/C objects. Objects can perform inline cleanup or mark other objects as dead if needed. It
* can also be used to protect objects from use if they get assigned to a global variable and
* used across coroutines.
*/
virtual void onMarkDead() {}
/**
* Called from markLive() when an object is marked live. This is a companion to onMarkDead(). See
* the comments there.
*/
virtual void onMarkLive() {}
private:
bool dead_{};
};
/**
* This is basically a Lua smart pointer. The idea is that given a Lua object, if we want to
* guarantee that Lua won't destroy it, we need to reference it. This wraps the reference
* functionality. While a LuaRef owns an object it's guaranteed that Lua will not GC it.
* TODO(mattklein123): Add dedicated unit tests. This will require mocking a Lua state.
*/
template <typename T> class LuaRef {
public:
/**
* Create an empty LuaRef.
*/
LuaRef() { reset(); }
/**
* Create a LuaRef from an object.
* @param object supplies the object. Generally this is the return value from a Object::create()
* call. The object must be at the top of the Lua stack.
* @param leave_on_stack supplies whether to leave the object on the stack or not when the ref
* is constructed.
*/
LuaRef(const std::pair<T*, lua_State*>& object, bool leave_on_stack) {
reset(object, leave_on_stack);
}
~LuaRef() { unref(); }
T* get() { return object_.first; }
/**
* Same as the LuaRef non-default constructor, but post-construction.
*/
void reset(const std::pair<T*, lua_State*>& object, bool leave_on_stack) {
unref();
if (leave_on_stack) {
lua_pushvalue(object.second, -1);
}
object_ = object;
ref_ = luaL_ref(object_.second, LUA_REGISTRYINDEX);
ASSERT(ref_ != LUA_REFNIL);
}
/**
* Return a LuaRef to its default/empty state.
*/
void reset() {
unref();
object_ = std::pair<T*, lua_State*>{};
ref_ = LUA_NOREF;
}
/**
* Push the referenced object back onto the stack.
*/
void pushStack() {
ASSERT(object_.first);
lua_rawgeti(object_.second, LUA_REGISTRYINDEX, ref_);
}
protected:
void unref() {
if (object_.second != nullptr) {
luaL_unref(object_.second, LUA_REGISTRYINDEX, ref_);
}
}
std::pair<T*, lua_State*> object_;
int ref_;
};
/**
* This is a variant of LuaRef which also marks an object as dead during destruction. This is
* useful if an object should not be used after the scope of the pcall() or resume().
* TODO(mattklein123): Add dedicated unit tests. This will require mocking a Lua state.
*/
template <typename T> class LuaDeathRef : public LuaRef<T> {
public:
~LuaDeathRef() { markDead(); }
void markDead() {
if (this->object_.first) {
this->object_.first->markDead();
}
}
void markLive() {
if (this->object_.first) {
this->object_.first->markLive();
}
}
void reset(const std::pair<T*, lua_State*>& object, bool leave_on_stack) {
markDead();
LuaRef<T>::reset(object, leave_on_stack);
}
void reset() {
markDead();
LuaRef<T>::reset();
}
};
}

41
envoy/main.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "envoy.h"
int callLua(lua_State* state, const char *func)
{
lua::LuaDeathRef<lua::StreamHandleWrapper> handle;
lua_getglobal(state, func);
if (lua_isfunction(state, -1)) {
handle.reset(lua::StreamHandleWrapper::create(state), true);
lua_call(state, 1, 0);
}
lua_pop(state, 1);
return 0;
}
int main(int argc, char *argv[])
{
if (argc < 1) {
printf("usage: envoy-apisix [lua file]\n");
return 0;
}
lua_State* state = luaL_newstate();
luaL_openlibs(state);
lua::BufferWrapper::registerType(state);
lua::HeaderMapIterator::registerType(state);
lua::HeaderMapWrapper::registerType(state);
lua::MetadataMapWrapper::registerType(state);
lua::MetadataMapIterator::registerType(state);
lua::StreamInfoWrapper::registerType(state);
lua::StreamHandleWrapper::registerType(state);
if (luaL_dofile(state, argv[1])) {
printf("script load error: %s\n", lua_tostring(state, -1));
return 0;
}
callLua(state, "envoy_on_request");
lua_close(state);
return 0;
}

4
envoy/packages.config Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="luajit.native" version="2.0.5" targetFramework="Native" />
</packages>