Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d757235
feat(lua): stage A - hloop lua_State slot, coroutine scheduler, hloop…
ithewei Jul 28, 2026
34e0791
feat(lua): stage B - coroutine-based async HttpLuaHandler on IO thread
ithewei Jul 28, 2026
2fc977e
refactor(lua): bind hvlua runtime to an EventLoop (TLS) for parity wi…
ithewei Jul 28, 2026
a7870d5
refactor(lua): implement hloop.* + scheduler + hv.dns in pure C
ithewei Jul 29, 2026
f3d439b
refactor(lua): split lua_hv_core into pure-C lua_hv_base + C++ lua_hv…
ithewei Jul 29, 2026
7eac88f
refactor(lua): unify under hv.* namespace + hvlua_* file naming
ithewei Jul 29, 2026
b804661
feat(lua): event-layer TCP/UDP IO binding (coroutine-synchronous)
ithewei Jul 29, 2026
61882aa
feat(lua): hv.http coroutine-synchronous HTTP client binding
ithewei Jul 29, 2026
6f490eb
refactor(evpp): hoist is_loop_owner into EventLoopThread base class
ithewei Jul 29, 2026
d2d4c29
refactor(redis): rebuild AsyncRedisClient/RedisSubscriber on TcpClient
ithewei Jul 30, 2026
8199c75
feat(lua): hv.redis / hv.ws / hv.mqtt coroutine-synchronous bindings
ithewei Jul 30, 2026
33774e8
fix(lua): CMake HVLUA_WITH_* parity + redis __gc reentrancy guard
ithewei Jul 30, 2026
27a50a5
feat(lua): align event API names with C++ classes + connect/listen al…
ithewei Jul 30, 2026
c4d4304
test(lua): use make_shared<EventLoop> in http_lua_handler_test
ithewei Jul 30, 2026
68443dc
test(lua): clearer names for the two http-lua test files
ithewei Jul 30, 2026
c44679b
build(lua): list --with-lua in configure help
ithewei Jul 30, 2026
4a82260
docs(lua): add docs/cn/lua.md + mark lua binding done in PLAN
ithewei Jul 30, 2026
051f083
fix(lua): address Copilot review findings on PR #857
ithewei Jul 30, 2026
0945b2b
feat(httpd): parse [script] section and register HttpService::Script
ithewei Jul 30, 2026
a11c735
fix(lua): address code-review findings on PR #857 (C1/C2/C3 + H2/H4/M1)
ithewei Jul 30, 2026
b2bf8a5
fix(mqtt): don't run/stop a caller-supplied loop (add is_loop_owner)
ithewei Jul 30, 2026
8250e12
docs(evpp): document the external-loop-must-be-running contract
ithewei Jul 30, 2026
9971da3
refactor(lua): hvlua_task_step returns completion; don't re-read co a…
ithewei Jul 30, 2026
491041b
feat(lua): auto-reconnect for hv.ws and hv.mqtt
ithewei Jul 30, 2026
f910d59
fix(lua): crash + leak fixes from runtime review (A1/A2/A3/B + UDP)
ithewei Jul 30, 2026
994a5bb
refactor(lua): extract reconnect config parsing into hvlua_util (shar…
ithewei Jul 30, 2026
febd265
refactor(lua): extract client metatable registration into hvlua_new_c…
ithewei Jul 30, 2026
6210e52
fix(lua): harden json, stop, and client coroutine lifetimes
ithewei Jul 30, 2026
cacf94b
fix(lua): clean up pending async state on loop teardown
ithewei Jul 30, 2026
465e03d
fix(event): harden loop and client teardown races
ithewei Jul 30, 2026
56bdb2d
fix(build): align lua feature gates across make and cmake
ithewei Jul 30, 2026
a67be10
fix(build): complete make feature gate parity
ithewei Jul 30, 2026
81ce454
fix(lua): reject coroutine resumes during state teardown
ithewei Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ if(WITH_LUA)
else()
set(LIBS ${LIBS} lua)
endif()
# lua bindings that wrap higher-level modules are conditionally compiled on
# HVLUA_WITH_* (kept in sync with Makefile.in): enabled only when both WITH_LUA
# and the underlying module are on. Without these, the http/redis/ws/mqtt
# binding bodies are #ifdef'd out and hv.http/redis/ws/mqtt silently become nil.
if(WITH_EVPP AND WITH_HTTP AND WITH_HTTP_CLIENT)
add_definitions(-DHVLUA_WITH_HTTP)
endif()
if(WITH_EVPP AND WITH_REDIS)
add_definitions(-DHVLUA_WITH_REDIS)
endif()
if(WITH_EVPP AND WITH_MQTT)
add_definitions(-DHVLUA_WITH_MQTT)
endif()
endif()

if(WIN32 OR MINGW)
Expand Down Expand Up @@ -236,6 +249,15 @@ if(WITH_PROTOCOL)
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} protocol)
endif()

if(WITH_LUA)
set(LIBHV_HEADERS ${LIBHV_HEADERS} lua/hvlua.h lua/hvlua_json.h lua/hvlua_util.h)
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} lua)
if(NOT WITH_EVPP)
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${CPPUTIL_HEADERS})
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} cpputil)
endif()
endif()

if(WITH_EVPP)
set(LIBHV_HEADERS ${LIBHV_HEADERS} ${CPPUTIL_HEADERS} ${EVPP_HEADERS})
set(LIBHV_SRCDIRS ${LIBHV_SRCDIRS} cpputil evpp)
Expand Down
68 changes: 49 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ LIBHV_HEADERS += $(PROTOCOL_HEADERS)
LIBHV_SRCDIRS += protocol
endif

ifeq ($(WITH_LUA), yes)
LIBHV_HEADERS += lua/hvlua.h lua/hvlua_json.h lua/hvlua_util.h
LIBHV_SRCDIRS += lua
ifneq ($(WITH_EVPP), yes)
LIBHV_HEADERS += $(CPPUTIL_HEADERS)
LIBHV_SRCDIRS += cpputil
endif
endif

ifeq ($(WITH_EVPP), yes)
LIBHV_HEADERS += $(CPPUTIL_HEADERS) $(EVPP_HEADERS)
LIBHV_SRCDIRS += cpputil evpp
Expand Down Expand Up @@ -101,6 +110,12 @@ ifeq ($(WITH_MQTT), yes)
EXAMPLES += mqtt_sub mqtt_pub mqtt_client_test
endif

ifeq ($(WITH_LUA), yes)
ifeq ($(WITH_EVPP), yes)
EXAMPLES += hvlua
endif
endif

examples: $(EXAMPLES)
@echo "make examples done."

Expand Down Expand Up @@ -179,6 +194,9 @@ socks5_proxy_server: prepare
host: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/host.c"

hvlua: prepare libhv
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -o bin/hvlua examples/hvlua.cpp -Llib -lhv -pthread $(LUA_LIBS)

multi-acceptor-processes: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS)" SRCS="examples/multi-thread/multi-acceptor-processes.c"

Expand All @@ -200,22 +218,20 @@ tinyproxyd: prepare
nmap: prepare libhv
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil examples/nmap" DEFINES="PRINT_DEBUG"

ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_REDIS), yes)
redis_client_example: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil evpp redis" SRCS="examples/redis_client_test.cpp"

redis_subscriber_example: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) cpputil evpp redis" SRCS="examples/redis_subscriber_test.cpp"
endif
endif

wrk: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http" SRCS="examples/wrk.cpp"

httpd: prepare
$(RM) examples/httpd/*.o
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client http/server examples/httpd"
$(MAKEF) TARGET=$@ SRCDIRS="$(LIBHV_SRCDIRS) util cpputil evpp http http/client http/server examples/httpd"

consul: prepare libhv
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client examples/consul" DEFINES="PRINT_DEBUG"
Expand All @@ -228,13 +244,13 @@ wget: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/wget.cpp"

http_server_test: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/server" SRCS="examples/http_server_test.cpp"
$(MAKEF) TARGET=$@ SRCDIRS="$(LIBHV_SRCDIRS)" SRCS="examples/http_server_test.cpp"

http_client_test: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/http_client_test.cpp"

websocket_server_test: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/server" SRCS="examples/websocket_server_test.cpp"
$(MAKEF) TARGET=$@ SRCDIRS="$(LIBHV_SRCDIRS) util cpputil evpp http http/server" SRCS="examples/websocket_server_test.cpp"

websocket_client_test: prepare
$(MAKEF) TARGET=$@ SRCDIRS="$(CORE_SRCDIRS) util cpputil evpp http http/client" SRCS="examples/websocket_client_test.cpp"
Expand Down Expand Up @@ -281,7 +297,7 @@ protorpc_server: prepare protorpc_protoc
SRCS="examples/protorpc/protorpc_server.cpp examples/protorpc/protorpc.c" \
LIBS="protobuf"

unittest: prepare
unittest: prepare libhv
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/rbtree_test unittest/rbtree_test.c base/rbtree.c
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/hbase_test unittest/hbase_test.c base/hbase.c
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -o bin/mkdir_p unittest/mkdir_test.c base/hbase.c
Expand Down Expand Up @@ -312,31 +328,45 @@ unittest: prepare
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -o bin/ping unittest/ping_test.c protocol/icmp.c base/hsocket.c base/htime.c -DPRINT_DEBUG
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -o bin/ftp unittest/ftp_test.c protocol/ftp.c base/hsocket.c base/htime.c
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Iprotocol -Iutil -o bin/sendmail unittest/sendmail_test.c protocol/smtp.c base/hsocket.c base/htime.c util/base64.c
$(MAKE) libhv
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Issl -Ievent -o bin/hdns_test unittest/hdns_test.c -Llib -lhv -pthread
$(CC) -g -Wall -O0 -std=c99 -I. -Ibase -Issl -Ievent -o bin/hdns_benchmark unittest/hdns_benchmark.c -Llib -lhv -pthread
ifeq ($(WITH_EVPP), yes)
$(MAKE) libhv
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -o bin/tcpclient_dns_test unittest/tcpclient_dns_test.cpp -Llib -lhv -pthread
ifeq ($(WITH_LUA), yes)
$(MAKE) libhv
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ihttp -Ihttp/server -o bin/http_lua_handler_test unittest/http_lua_handler_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
else
$(RM) bin/http_lua_handler_test
endif
ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_REDIS), yes)
$(MAKE) libhv
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Ievent -Icpputil -Iredis -o bin/redis_protocol_test unittest/redis_protocol_test.cpp redis/RedisMessage.cpp
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Iredis -Ievpp -o bin/redis_async_client_test unittest/redis_async_client_test.cpp unittest/redis_test_server.cpp -Llib -lhv -pthread
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Iredis -Ievpp -o bin/redis_client_test unittest/redis_client_test.cpp unittest/redis_test_server.cpp -Llib -lhv -pthread
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Iredis -Ievpp -o bin/redis_batch_test unittest/redis_batch_test.cpp unittest/redis_test_server.cpp -Llib -lhv -pthread
$(CXX) -g -Wall -O0 -std=c++11 -I. -Ibase -Issl -Ievent -Icpputil -Iredis -Ievpp -o bin/redis_subscriber_test unittest/redis_subscriber_test.cpp unittest/redis_test_server.cpp -Llib -lhv -pthread
else
$(RM) bin/redis_protocol_test bin/redis_async_client_test bin/redis_client_test bin/redis_batch_test bin/redis_subscriber_test
endif
else
$(RM) bin/tcpclient_dns_test
$(RM) bin/redis_protocol_test bin/redis_async_client_test bin/redis_client_test bin/redis_batch_test bin/redis_subscriber_test
endif
ifeq ($(WITH_LUA), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -o bin/lua_binding_test unittest/lua_binding_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -o bin/lua_io_test unittest/lua_io_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_HTTP), yes)
ifeq ($(WITH_HTTP_SERVER), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -Ihttp -Ihttp/server -o bin/http_script_handler_test unittest/http_script_handler_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
ifeq ($(WITH_HTTP_CLIENT), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -Ihttp -Ihttp/server -Ihttp/client -o bin/http_lua_handler_test unittest/http_lua_handler_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
endif
endif
ifeq ($(WITH_HTTP_SERVER), yes)
ifeq ($(WITH_HTTP_CLIENT), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA -DHVLUA_WITH_HTTP $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -Ihttp -Ihttp/server -Ihttp/client -o bin/lua_http_test unittest/lua_http_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA -DHVLUA_WITH_HTTP $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -Ihttp -Ihttp/server -Ihttp/client -o bin/lua_ws_test unittest/lua_ws_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
endif
endif
endif
ifeq ($(WITH_MQTT), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA -DHVLUA_WITH_MQTT $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Ievpp -Ilua -Imqtt -o bin/lua_mqtt_test unittest/lua_mqtt_test.cpp -Llib -lhv -pthread $(LUA_LIBS)
endif
ifeq ($(WITH_REDIS), yes)
$(CXX) -g -Wall -O0 -std=c++11 -DWITH_LUA -DHVLUA_WITH_REDIS $(LUA_CFLAGS) -I. -Ibase -Issl -Ievent -Icpputil -Iredis -Ievpp -Ilua -o bin/lua_redis_test unittest/lua_redis_test.cpp unittest/redis_test_server.cpp -Llib -lhv -pthread $(LUA_LIBS)
endif
endif
endif

run-unittest: unittest
Expand Down
19 changes: 19 additions & 0 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,25 @@ endif
ifeq ($(WITH_LUA), yes)
CPPFLAGS += -DWITH_LUA $(LUA_CFLAGS)
LDFLAGS += $(LUA_LIBS)
# lua bindings that wrap higher-level modules are enabled only when both the lua
# binding and the underlying module are built (HVLUA_WITH_* preprocessor macros).
ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_HTTP), yes)
ifeq ($(WITH_HTTP_CLIENT), yes)
CPPFLAGS += -DHVLUA_WITH_HTTP
endif
endif
endif
ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_REDIS), yes)
CPPFLAGS += -DHVLUA_WITH_REDIS
endif
endif
ifeq ($(WITH_EVPP), yes)
ifeq ($(WITH_MQTT), yes)
CPPFLAGS += -DHVLUA_WITH_MQTT
endif
endif
endif

CPPFLAGS += $(addprefix -D, $(DEFINES))
Expand Down
1 change: 1 addition & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ modules:
--with-http-server compile http server module? (DEFAULT: $WITH_HTTP_SERVER)
--with-mqtt compile mqtt module? (DEFAULT: $WITH_MQTT)
--with-redis compile redis module? (DEFAULT: $WITH_REDIS)
--with-lua compile lua module? (DEFAULT: $WITH_LUA)

features:
--enable-uds enable Unix Domain Socket? (DEFAULT: $ENABLE_UDS)
Expand Down
4 changes: 2 additions & 2 deletions docs/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
- rudp: KCP
- evpp: c++ EventLoop interface similar to muduo and evpp
- http client/server: include https http1/x http2
- http server sync/async/ctx/state/script handlers
- websocket client/server
- mqtt client
- redis client
- async DNS
- http lua handler
- lua binding

## Plan

- lua binding
- js binding
- hrpc = libhv + protobuf
- rudp: FEC, ARQ, UDT, QUIC
Expand Down
55 changes: 51 additions & 4 deletions docs/cn/HttpLuaHandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,61 @@ end

## hv API

首版只提供少量宿主能力:
脚本运行在所属 IO 线程的 **协程** 里,因此可以用 **同步写法** 调用异步能力:调用会挂起当前请求的协程、把控制权交还事件循环,结果就绪后在同一线程恢复,全程不阻塞 loop。

所有脚本可用能力都挂在统一的全局 `hv` 表下:

```lua
hv.version() -- libhv 版本串, 如 "1.3.4"
hv.log(...) -- 日志 (INFO), 等价 hv.logi
hv.logd(...) / hv.logi(...) / hv.logw(...) / hv.loge(...) -- debug/info/warn/error
hv.json.encode(tbl) -- table -> json string
hv.json.decode(str) -- json string -> table

hv.setTimeout(ms, fn) -- 定时器 (返回句柄)
hv.setInterval(ms, fn)
hv.clearTimer(handle)
hv.sleep(ms) -- 协程同步 sleep: 挂起当前协程 ms 毫秒, 不阻塞 loop
hv.resolveDns(host) -- 协程同步 DNS 解析: 返回 { ip, ... } 或 nil, err
hv.run() / hv.stop() -- 运行/停止当前线程的 event loop (独立脚本用; HTTP handler 内不需要)

-- TCP/UDP (协程同步, event 层, 仅当前 loop)
local conn, err = hv.connect(host, port [, timeout_ms]) -- TCP 客户端
hv.tcpServer(host, port, function(conn) ... end) -- 每连接一个协程
local sock = hv.udpClient(host, port)
hv.udpServer(host, port, function(sock, data, peer) ... end)
-- conn: conn:read() / conn:readline() / conn:readuntil(d) / conn:readbytes(n)
-- conn:setUnpack(opts) / conn:write(s) / conn:close() / conn:fd() / conn:peeraddr()
-- sock: sock:sendto(s) / sock:recvfrom() -> data,peer / sock:close()
```

`conn:setUnpack(opts)` 让后续 `conn:read()` 每次返回一个完整的包(参考 libhv `hio_set_unpack`):

```lua
conn:setUnpack({
mode = "length_field", -- none|fixed|delimiter|length_field
body_offset = 5, length_field_offset = 1,
length_field_bytes = 4, length_field_coding = "be", -- be|le|varint|asn1
-- delimiter 模式: delimiter = "\r\n" ; fixed 模式: fixed_length = 16
})
```

示例(handler 内部“同步”写法,实际异步,loop 不阻塞):

```lua
hv.log(...)
hv.now()
function handle(ctx)
local addrs, err = hv.resolveDns("example.com")
if err then
ctx:status(502)
return ctx:json({ ok = false, error = err })
end
return ctx:json({ ok = true, addrs = addrs })
end
```

暂不暴露 `hv.event_loop`、TCP/HTTP client、Redis 等能力,避免脚本直接操作底层事件循环。后续可以按业务需要增加受控的 `hv.redis`、`hv.http` 等模块。
多个请求会在同一 IO 线程上并发交错执行:某个请求在 `hv.resolveDns` / `hv.sleep` 处挂起时,同线程的其它请求会继续推进。注意协作式调度的语义——跨越挂起点不要对全局状态做原子性假设。

> `hv.setTimeout` / `hv.resolveDns` 对应 `event/` 层能力,`hv.log` / `hv.version` 对应 `base/` 层,`hv.json` 对应 `cpputil/`;实现分别在 `lua/hvlua_event.c`、`lua/hvlua_base.c`、`lua/hvlua_json.cpp`。TCP/HTTP client、Redis 等高层 client 绑定后续按 `WITH_LUA` / `WITH_REDIS` 等开关编入。

## 热更新

Expand Down
4 changes: 4 additions & 0 deletions docs/cn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
- [hbase: 基础函数](hbase.md)
- [hlog: 日志](hlog.md)

## lua接口

- [Lua Binding: hv.* Lua 绑定](lua.md)

## c++接口

- [class EventLoop: 事件循环类](EventLoop.md)
Expand Down
Loading
Loading