CoconutCockpit Posted January 23, 2022 Posted January 23, 2022 I would like to export some data out of a mission while it's running using socket.http, but I can't for the life of me get it to work. I've editod my MissionScripting.lua file so nothing is sanitzed and I have access to the require module. Looking at other (older) threads on the forum here, as far as I can tell the following code should work? package.path = package.path..";"..lfs.currentdir().."\\LuaSocket\\?.lua" package.cpath = package.cpath..";"..lfs.currentdir().."\\LuaSocket\\?.dll" local http = require("socket.http") But it errors out with: 2022-01-23 16:36:37.313 ERROR SCRIPTING: Mission script error: [string "G:/My Drive/Coconut Cockpit/Missions/DCS_CaucasusTraining/Scripts/init.lua"]:58: module 'socket.http' not found: no field package.preload['socket.http'] no file '.\socket\http.lua' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\lua\socket\http.lua' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\lua\socket\http\init.lua' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\socket\http.lua' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\socket\http\init.lua' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\\LuaSocket\socket\http.lua'socket.http no file '.\lua-socket\http.dll' no file '.\socket\http.dll' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\lua-socket\http.dll' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\socket\http.dll' no file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\\LuaSocket\socket\http.dll' no module 'socket.http' in file 'C:\Program Files\Eagle Dynamics\DCS World OpenBeta\bin\lua-socket.dll' stack traceback: [C]: ? [C]: in function 'require' [string "G:/My Drive/Coconut Cockpit/Missions/DCS_CaucasusTraining/Scripts/init.lua"]:58: in main chunk [string "ROOT_PATH = "G:/My Drive/Coconut Cockpit/Missions/DCS_CaucasusTraining/Scripts/"..."]:8: in main chunk Does anyone have an idea what I'm doing wrong? Any help is appreciated! Coconut Cockpit Instagram
CoconutCockpit Posted January 23, 2022 Author Posted January 23, 2022 Don't quite know if because of all my trying and retrying I didn't restart DCS after making changes to MissionScripting.lua, but the following code seems to be working just fine now. So for anyone coming here from Google, give this a try: package.path = package.path..";"..lfs.currentdir().."\\LuaSocket\\?.lua" package.cpath = package.cpath..";"..lfs.currentdir().."\\LuaSocket\\?.dll" local socket = require("socket") require("mime") require("ltn12") require("url") require("http") Coconut Cockpit Instagram
Igneous01 Posted January 25, 2022 Posted January 25, 2022 I believe http is not supported in the socket package with the version of lua supplies by the dcs scripting environment. You can either create TCP sockets or UDP sockets, and you must handle the send/receive manually. I've done some of this work myself in an older MissionScripting.lua as an example. This code has been battle tested quite a bit and the socket connections were pretty reliable. You send messages via json strings, which are just lua objects encoded into a json string and sent over the wire. Anything listening on the other end can use a json parser library to read back the receive and parse the message. It's not as simple as using a rest api or http, but it does the job. Scripts\\ServerGameGUI.lua package.path = package.path..";.\\LuaSocket\\?.lua;" package.cpath = package.cpath..";.\\LuaSocket\\?.dll;" local JSONPath = lfs.writedir() .. "Scripts\\JSON.lua" local _errormsg = "" net.log("JSON File Path: " .. JSONPath) KI = {} -- UDP Port Numbers to communicate with the server side mod KI.Config.GAMEGUI_RECEIVE_PORT = 6005 -- the port to listen on for server side messages KI.Config.GAMEGUI_SEND_TO_PORT = 6006 -- the port to send messages to server side KI.Config.SERVER_SESSION_RECEIVE_PORT = 6007 -- the port to listen for server side session/server info -- Initialize Sockets KI.UDPSendSocket = socket.udp() KI.UDPReceiveSocket = socket.udp() KI.UDPReceiveSocket:setsockname("*", KIServer.Config.GAMEGUI_RECEIVE_PORT) KI.UDPReceiveSocket:settimeout(.0001) --receive timer --=============================================================================-- -- TCPSocket INIT KI.TCPSocket = { Object = nil, IsConnected = false } function KI.TCPSocket.Connect() net.log("KI.TCPSocket.Connect called") -- if the socket handle is not nil, invoke close on it just in case it was still left open if KI.TCPSocket.Object ~= nil then KI.TCPSocket.Object:close() end -- start connection KI.TCPSocket.Object = socket.tcp() KI.TCPSocket.Object:settimeout(5) KI.TCPSocket.Object:setoption("tcp-nodelay", true) KI.TCPSocket.IsConnected = false local _r, _err = KI.TCPSocket.Object:connect(KI.Config.TCP_SERVER_IP, KI.Config.TCP_SERVER_PORT) KI.TCPSocket.Object:settimeout(.0001) if _r ~= 1 or _err then net.log("KI.TCPSocket.Connect - ERROR - Failed to connect to TCP Server (Reason: " .. _err .. ")") KI.TCPSocket.IsConnected = false return false else KI.TCPSocket.IsConnected = true return true end end function KI.TCPSocket.Disconnect() net.log("KI.TCPSocket.Disconnect called") KI.TCPSocket.Object:close() KI.TCPSocket.IsConnected = false end -- Creates the message in the correct format the server expects -- Encodes into JSON, and appends size of message in first 6 characters of string function KI.TCPSocket.CreateMessage(action_name, dest, is_bulk_query, data) net.log("KI.TCPSocket.CreateMessage called") local _msg = { Action = action_name, Destination = dest, BulkQuery = is_bulk_query, Data = data, } local _jsonmsg = KI.JSON:encode(_msg) -- sending 6 char header that is size of msg string local _m = string.format("%06d", string.len(_jsonmsg)) .. _jsonmsg net.log("KI.TCPSocket.CreateMessage - dumping message") net.log(_m) return _m end -- Decodes message from JSON string into LUA Table Object function KI.TCPSocket.DecodeMessage(msg) net.log("KI.TCPSocket.DecodeMessage called") local _err = "" local _result, _luaObject = xpcall(function() return KI.JSON:decode(msg) end, function(err) _err = err end) if _result and _luaObject ~= nil then net.log("KI.TCPSocket.DecodeMessage - Message Decoded") return _luaObject elseif _err ~= "" then net.log("KI.TCPSocket.DecodeMessage ERROR - " .. _err) return nil else net.log("KI.TCPSocket.DecodeMessage ERROR - UNKNOWN ERROR") return nil end end function KIServer.TCPSocket.SendUntilComplete(msg, timeout) net.log("KIServer.TCPSocket.SendUntilComplete called") if not KIServer.TCPSocket.IsConnected then net.log("KIServer.TCPSocket.SendUntilComplete - ERROR - Socket is not connected to DB server") return false end if timeout then KIServer.TCPSocket.Object:settimeout(timeout) -- set the timeout (used to handle particularly large messages) else KIServer.TCPSocket.Object:settimeout(.0001) end local bytes_sent = 0 local msg_size = string.len(msg) -- copy the original msg parameter as we want to manipulate the copy without changing the original (but if strings are not by ref - why bother?) local _msgCopy = msg while bytes_sent ~= msg_size do local _indexSent, _error, _lastIndexSent = KIServer.TCPSocket.Object:send(_msgCopy) -- successful send if _indexSent then bytes_sent = bytes_sent + _indexSent else -- error encountered - check third parameter to see if at least some data was sent and retry if _lastIndexSent ~= 0 then net.log("KIServer.TCPSocket.SendUntilComplete - partial send occurred (reason: " .. _error .. ") - Continuing") bytes_sent = bytes_sent + _lastIndexSent else -- complete failure - log net.log("KIServer.TCPSocket.SendUntilComplete - ERROR in sending data (reason: " .. _error .. ")") KIServer.TCPSocket.Disconnect() return false end end -- net.log("KIServer.TCPSocket.SendUntilComplete - bytes sent: "..tostring(bytes_sent)) -- net.log("KIServer.TCPSocket.SendUntilComplete - sent string: '" .. _msgCopy:sub(1, bytes_sent).."'") _msgCopy = _msgCopy:sub(bytes_sent + 1) -- shrink the msg down to what has not been sent -- net.log("KIServer.TCPSocket.SendUntilComplete - Remaining buffer length: " .. tostring(string.len(_msgCopy)) .. " data : '" .. _msgCopy .. "'") end return true end function KIServer.TCPSocket.ReceiveUntilComplete(timeout) net.log("KIServer.TCPSocket.ReceiveUntilComplete called") if timeout then KIServer.TCPSocket.Object:settimeout(timeout) else KIServer.TCPSocket.Object:settimeout(.0001) end local header, _error = KIServer.TCPSocket.Object:receive(6) if header and header:len() == 6 then local msg_size = tonumber(header) local msg, _error = KIServer.TCPSocket.Object:receive(msg_size) if msg and msg:len() == msg_size then net.log("KIServer.TCPSocket.ReceiveUntilComplete - received data transmission") return msg elseif msg and msg:len() < msg_size then net.log("KIServer.TCPSocket.ReceiveUntilComplete - partial data received (Reason: " .. _error .. ")") net.log("KIServer.TCPSocket.ReceiveUntilComplete - trying again") local partmsg, _error = KIServer.TCPSocket.Object:receive(msg_size - msg:len()) -- check if the partial message came through and is the size we are expecting it to be if partmsg and partmsg:len() == (msg_size - msg:len()) then msg = msg .. partmsg return msg else net.log("KIServer.TCPSocket.ReceiveUntilComplete - second try failed to receive (Reason: " .. _error .. ")") KIServer.TCPSocket.Disconnect() return nil end else net.log("KIServer.TCPSocket.ReceiveUntilComplete - ERROR in receiving body data (Reason: " .. _error .. ")") KIServer.TCPSocket.Disconnect() return nil end else net.log("KIServer.TCPSocket.ReceiveUntilComplete - WARNING - did not receive header data (reason: " .. _error .. ")") if _error == "closed" then KIServer.TCPSocket.Disconnect() -- disconnect the socket if the server closed the connection end return nil end end -- end Server TCP Socket -- ========================================================================================================== -- Developer of Kaukasus Insurgency - a customizable Dynamic PvE Campaign with cloud hosting and stats tracking. (Alpha) http://kaukasusinsurgency.com/
Recommended Posts