init commit
This commit is contained in:
204
envoy/envoy.cpp
Normal file
204
envoy/envoy.cpp
Normal 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
130
envoy/envoy.h
Normal 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
105
envoy/envoy.vcxproj
Normal 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>
|
||||
36
envoy/envoy.vcxproj.filters
Normal file
36
envoy/envoy.vcxproj.filters
Normal 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
292
envoy/lua.h
Normal 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
41
envoy/main.cpp
Normal 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
4
envoy/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="luajit.native" version="2.0.5" targetFramework="Native" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user