diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ffd08aa786b01d173daf8575f45e8606efe2e65c..4860ec58209b176aa9597553df222c92d49f74ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ lua_source(lua_sources lua/load_cfg.lua) lua_source(lua_sources lua/bsdsocket.lua) lua_source(lua_sources lua/errno.lua) lua_source(lua_sources lua/log.lua) +lua_source(lua_sources lua/box_net_box.lua) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/luafun) lua_source(lua_sources ../third_party/luafun/fun.lua) diff --git a/src/lua/box_net_box.lua b/src/lua/box_net_box.lua new file mode 100644 index 0000000000000000000000000000000000000000..865e32037e261b79fa264407815525146442f58b --- /dev/null +++ b/src/lua/box_net_box.lua @@ -0,0 +1,214 @@ +-- net_box.lua (internal file) + +local msgpack = require 'msgpack' +local fiber = require 'fiber' +local socket = require 'socket' +local log = require 'log' + +local PING = 64 +local SELECT = 1 +local INSERT = 2 +local REPLACE = 3 +local UPDATE = 4 +local DELETE = 5 +local CALL = 6 +local TYPE = 0x00 +local SYNC = 0x01 +local SPACE_ID = 0x10 +local INDEX_ID = 0x11 +local LIMIT = 0x12 +local OFFSET = 0x13 +local ITERATOR = 0x14 +local KEY = 0x20 +local TUPLE = 0x21 +local FUNCTION_NAME = 0x22 +local DATA = 0x30 +local ERROR = 0x31 +local GREETING_SIZE = 128 + + +local function request(header, body) + header = msgpack.encode(header) + body = msgpack.encode(body) + + local len = msgpack.encode(string.len(header) + string.len(body)) + + return len .. header .. body +end + +local _sync = -1 + +local proto = { + -- sync + sync = function(self) + _sync = _sync + 1 + if _sync >= 0x7FFFFFFF then + _sync = 0 + end + return _sync + end, + + + ping = function(sync) + return request( + { SYNC = sync, TYPE = PING }, + {} + ) + end, + + + -- lua call + call = function(sync, proc, args) + if args == nil then + args = {} + end + return request( + { SYNC = sync, TYPE = CALL }, + { FUNCTION_NAME = proc, TUPLE = args } + ) + end, + + -- insert + insert = function(sync, spaceno, tuple) + return request( + { SYNC = sync, TYPE = INSERT }, + { SPACE_ID = spaceno, TUPLE = tuple } + ) + end, + + -- replace + replace = function(sync, spaceno, tuple) + return request( + { SYNC = sync, TYPE = REPLACE }, + { SPACE_ID = spaceno, TUPLE = tuple } + ) + end, + + -- delete + delete = function(sync, spaceno, key) + return request( + { SYNC = sync, TYPE = DELETE }, + { SPACE_ID = spaceno, KEY = key } + ) + end, + + -- update + -- select + +} + + +local function connect(self) + if self.state == 'connected' or self.state == 'connecting' then + return + end + + self.state = 'connecting' + + self.dns = socket.getaddrinfo(self.host, self.port, + nil, { protocol = 'tcp' }) + if not self.is_run then + return + end + + if self.dns == nil or #self.dns < 1 then + self:fatal("Cant resolve address %s:%s: %s", self.host, self.port, + self.errno.strerror(self.errno())) + return + end + + for i, addr in pairs(self.dns) do + if self.s ~= nil then + self.s:close() + end + self.s = socket(addr.family, addr.type, addr.protocol) + if self.s ~= nil then + if self.s:sysconnect(addr.host, addr.port) then + self.state = 'connected' + return + end + end + end + + if self.s ~= nil then + self:fatal("Cant resolve address %s:%s: %s", self.host, self.port, + self.s:errstr()) + self.s:close() + else + self:fatal("Cant resolve address %s:%s: %s", self.host, self.port, + self.errno.strerror(self.errno())) + end +end + +local function run(self) + fiber.wrap( + function() + while self.is_run do + if self.state == 'connected' then + self:io() + else + connect(self) + end + end + end + ) +end + +local connector = { + + new = function(parent, host, port, opts) + if opts == nil then + opts = {} + end + local self = { + host = host, + port = port, + state = 'init', + is_run = true, + opts = opts + } + + setmetatable(self, { __index = parent }) + + run(self) + return self + end, + + + on_error = function(self, message) end, + on_connect = function(self) end, + io = function(self) fiber.sleep(1) end, + + + fatal = function(self, msg, ...) + msg = string.format(msg, ...) + self.state = 'error' + self.message = msg + if self.s then + self.s:close() + self.s = nil + end + self:on_error(msg) + end +} + + +local remote = { + __index = { + new = function(class, host, port, user, password, opts) + local self = connector:new(host, port, opts) + self.user = user + self.password = password + + setmetatable(self, class) + return self + end, + + proto = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + __index = connector + } +} + +setmetatable(remote, remote) + +return remote diff --git a/src/lua/init.cc b/src/lua/init.cc index 0b47d3dd87f53324fce5513c21d00a4bba44e165..9991647815326e74a7acd68de76792166f175411 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -71,12 +71,18 @@ struct lua_State *tarantool_L; /* contents of src/lua/ files */ extern char uuid_lua[], session_lua[], msgpackffi_lua[], fun_lua[], load_cfg_lua[], interactive_lua[], digest_lua[], init_lua[], - log_lua[]; + log_lua[], box_net_box_lua[]; static const char *lua_sources[] = { init_lua, session_lua, load_cfg_lua, NULL }; -static const char *lua_modules[] = { "msgpackffi", msgpackffi_lua, - "fun", fun_lua, "digest", digest_lua, +static const char *lua_modules[] = { + "msgpackffi", msgpackffi_lua, + "fun", fun_lua, + "digest", digest_lua, "interactive", interactive_lua, - "uuid", uuid_lua, "log", log_lua, NULL }; + "uuid", uuid_lua, + "log", log_lua, + "net.box", box_net_box_lua, + NULL +}; /* * {{{ box Lua library: common functions */ diff --git a/test/box/box.net.box.result b/test/box/box.net.box.result new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/box/box.net.box.test.lua b/test/box/box.net.box.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..ea6f98b3c33ad2e61a40b4da5812fd680a5ee71f --- /dev/null +++ b/test/box/box.net.box.test.lua @@ -0,0 +1,8 @@ +remote = require 'net.box' + +port = box.cfg.primary_port + +cn = remote:new('localhost', port) +cn + +cn.proto.ping(0)