Lua: attempt to index local '' (a nil value) - lua

Please help: I am attempting to index local firstClipArr (a nil value) but I cannot figure out how to solve it for the life of me. Here's the code:
function updateRemoteAmmo( ammoTable )
if not client or getElementData(client,"loggedin") ~= 1 then
return
end
local items = getItems( client )
local weaponCheck = { }
for _, itemCheck in ipairs( items ) do
if (itemCheck[1] == 115) then -- Weapon item
local weaponItemDetails = explode(':', itemCheck[2])
local weaponAmmoCountValid = 0
local firstClip = 0
local firstClipInventorySlot = 0
local firstClipArr = nil
for itemCheckBulletsSlot, itemCheckBullets in ipairs( items ) do
if (itemCheckBullets[1] == 116) then
local weaponBulletDetails = explode(':', itemCheckBullets[2])
if tonumber(weaponBulletDetails[1]) == tonumber(weaponItemDetails[1]) then
if (firstClip == 0 and tonumber(weaponBulletDetails[2]) > 0) then
firstClip = tonumber(weaponBulletDetails[2])
firstClipInventorySlot = itemCheckBulletsSlot
firstClipArr = weaponBulletDetails
end
weaponAmmoCountValid = weaponAmmoCountValid + weaponBulletDetails[2]
end
end
end
local weaponSyncPacket = false
for _, tableValue in ipairs(ammoTable) do
if tonumber(tableValue[1]) == tonumber(weaponItemDetails[1]) then
weaponSyncPacket = tableValue
end
end
if not weaponSyncPacket then
return
end
local fakebullet = false
if (getElementData(client, "cf:"..weaponItemDetails[1])) then
fakebullet = true
weaponAmmoCountValid = weaponAmmoCountValid + 1
end
if (weaponAmmoCountValid > weaponSyncPacket[2]) then -- There has been shot with this gun
local totalBulletsShot = weaponAmmoCountValid - weaponSyncPacket[2]
local update = updateItemValue(client, firstClipInventorySlot,firstClipArr[1] ..":"..weaponSyncPacket[3] ..":".. firstClipArr[3])
if not update then
outputDebugString("fail")
end
weaponAmmoCountValid = weaponAmmoCountValid - totalBulletsShot
end
table.insert(weaponCheck, {weaponItemDetails[1], weaponAmmoCountValid, fakebullet} )
end
end

Related

Unable to assign property AnimationId. Content expected, got nil

I don't know what's happening, but i'm getting that error in output. Apparently every animations of the Anims table and normalcombo table exists, and the property too. I tested it in Commandbar but didn't work. I don't know how to fix it and don't know what's the problem. Please help me. Code below:
--Local Script
local Replicated = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local Remote = Replicated.CombateEvent
local Player = game.Players.LocalPlayer
local Char = Player.CharacterAdded:Wait()
local Humanoid = Char:WaitForChild("Humanoid")
local istoolequipped = false
script.Parent.Equipped:Connect(function()
istoolequipped = true
end)
script.Parent.Unequipped:Connect(function()
istoolequipped = false
end)
local lastM1Time = 0
local lastM1End = 0
local combo = 1
local canAir = true
local Anims = {
"rbxassetid://12270296026",
"rbxassetid://12290262661",
"rbxassetid://12290234803",
}
local normalcombo = {
"rbxassetid://12303443278",
"rbxassetid://12303443278",
"rbxassetid://12303527113",
"rbxassetid://12303770582"
}
function hb(size, cframe, ignore, char)
local hitbox = Instance.new("Part", workspace)
hitbox.Size = size
hitbox.CFrame = cframe
hitbox.Anchored = true
hitbox.CanCollide = false
hitbox.Transparency = .6
hitbox.Name = "hb"
hitbox.Material = Enum.Material.ForceField
hitbox.CanQuery = false
local connection
connection = hitbox.Touched:Connect(function()
connection:Disconnect()
end)
local lasttarget
for _, v in pairs(hitbox:GetTouchingParts()) do
if v.Parent:FindFirstChild("Humanoid") and table.find(ignore, v.Parent.Name) == nil then
if lasttarget then
if (lasttarget.Position - char.PrimaryPart.Position).Magnitude > (v.Position - char.PrimaryPart.Position).Magnitude then
lasttarget = v.Parent.PrimaryPart
end
else
lasttarget = v.Parent.PrimaryPart
end
end
end
hitbox:Destroy()
if lasttarget then
return lasttarget.Parent
else
return nil
end
end
UIS.InputBegan:Connect(function(input, istyping)
if istyping then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 and tick() - lastM1Time > .3 and tick() - lastM1End > .7 and istoolequipped then
if tick() - lastM1Time > .7 then
combo = 0
end
lastM1Time = tick()
local animation = Instance.new("Animation", workspace.Animation)
local air = nil
if UIS:IsKeyDown("Space") and canAir == true and combo == 2 then
canAir = false
air = "Up"
animation.AnimationId = Anims[1]
elseif UIS:IsKeyDown("Space") and combo == 3 and not canAir then
air = "Down"
animation.AnimationId = Anims[2]
else
animation.AnimationId = normalcombo[combo]
end
local load = Humanoid:LoadAnimation(animation)
load:Play()
animation:Destroy()
local hitTarg = hb(Vector3.new(3,5,3), Char.PrimaryPart.CFrame * CFrame.new(0,0,-3), {Char}, Char)
local Info = {
["Target"] = hitTarg,
["Combo"] = combo,
["Character"] = Char,
["Air"] = air
}
Remote:FireServer("Combo", Info)
if combo == #normalcombo then
combo = 1
lastM1End = tick()
else
combo += 1
end
Humanoid.WalkSpeed = 0
task.wait(.4)
Humanoid.WalkSpeed = 16
end
end)
The error send me to this line: "animation.AnimationId = normalcombo[combo]"
The error is telling you that normalcombo[combo] is returning nil when it should be a content url. That means that combo isn't a value between 1 and #normalcombo (4).
The only place where that could be is here :
if tick() - lastM1Time > .7 then
combo = 0
end
Here you are resetting the combo counter, but you set it too low. Arrays in lua are 1-indexed. You need to set it to :
combo = 1

(ROBLOX) Dont add gui when other player join

I would explain better here, I'm doing a role game and I do ranks enter image description here
But if somebody another joins then the text over the head will Destroy and to another player spawn the GUI.
The script:
local ServerStorage = game:GetService("ServerStorage")
local Tag = ServerStorage.Tag
local CloneTag = Tag:Clone()
local NameTag = CloneTag.NameTag
local RankTag = CloneTag.RankTag
local VIPTag = CloneTag.VIPTag
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(char)
CloneTag.Parent = char.Head
if player:IsInGroup(14472135) then
if player:GetRankInGroup(14472135) == 1 then
NameTag.Text = player.Name
RankTag.Text = "Trainee"
elseif player:GetRankInGroup(14472135) == 2 then
NameTag.Text = player.Name
RankTag.Text = "Police"
elseif player:GetRankInGroup(14472135) == 3 then
NameTag.Text = player.Name
RankTag.Text = "Specialist"
elseif player:GetRankInGroup(14472135) == 4 then
NameTag.Text = player.Name
RankTag.Text = "Sergeant"
elseif player:GetRankInGroup(14472135) == 252 then
NameTag.Text = player.Name
RankTag.Text = "Corporal"
elseif player:GetRankInGroup(14472135) == 253 then
NameTag.Text = player.Name
RankTag.Text = "Major"
elseif player:GetRankInGroup(14472135) == 254 then
NameTag.Text = player.Name
RankTag.Text = "Lieutenant"
VIPTag.Visible = true
elseif player:GetRankInGroup(14472135) == 255 then
NameTag.Text = player.Name
RankTag.Text = "Colonel"
VIPTag.Visible = true
end
else
NameTag.Text = player.Name
RankTag.Text = "Immigrant"
end
end)
end)
Any Suggestion?
Thanks
As I said in my comment, you simply move the variables so that the cloning is done when a character spawns. There are also ways to make this code better. (1) You can use a table to specify each rank's text, which will shorten it. You can use another table (or the same table with more detailed table values) to store the visibility of the VIP tag. (2) You also don't need to do NameTag.Text = player.Name in every if-elseif body, you can move it out of the if so that it will always happen.
I can show a quick example of fix #1:
local ranks = {
[1] = "Trainee",
[2] = "Police",
[3] = "Specialist",
--...
[255] = "Colonel"
}
local rankVIP = {
[254] = true,
[255] = true
}
and then, all you need to set someone's rank label's text is this:
local rankInGroup = player:GetRankInGroup(14472135)
RankTag.Text = ranks[rankInGroup]
VIPTag.Visible = rankVIP[rankInGroup] or false
Here, the or false means "if I couldn't find this (if this is nothing, if this is nil), make the visibility false. If I did find something, then it will be that."
With all of the fixes and improvements, here is the new code:
local ServerStorage = game:GetService("ServerStorage")
local Tag = ServerStorage.Tag
local ranks = {
[1] = "Trainee",
[2] = "Police",
[3] = "Specialist",
[4] = "Sergeant",
[252] = "Corporal",
[253] = "Major",
[254] = "Lieutenant",
[255] = "Colonel"
}
local rankVIP = {
[254] = true,
[255] = true
}
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(char)
local CloneTag = Tag:Clone()
local NameTag = CloneTag.NameTag
local RankTag = CloneTag.RankTag
local VIPTag = CloneTag.VIPTag
NameTag.Text = player.Name
CloneTag.Parent = char.Head
if player:IsInGroup(14472135) then
local rankInGroup = player:GetRankInGroup(14472135)
RankTag.Text = ranks[rankInGroup]
VIPTag.Visible = rankVIP[rankInGroup] or false
else
RankTag.Text = "Immigrant"
end
end)
end)

CORS issue on ESP32 with nodemcu lua

I want to create Esp32 based server and wanted to implement local REST api's so I took https://github.com/abobija/api32 help and written some api's everything working with chrome/postman but when tried to use with my mobile app not able to get the response but can able to post the data to esp32.
I'm getting this error
Access to XMLHttpRequest at 'http://192.168.0.10/' from origin 'http://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
my code is
Title : Library for easy way of creating HTTP JSON Api Service for ESP32
Author : Alija Bobija
Author-Website : https://abobija.com
GitHub Repo : https://github.com/abobija/api32
Dependencies:
- sjson
- encoder
]]
local Api32 = {}
local function str_starts_with(haystack, needle)
return haystack:sub(1, #needle) == needle
end
local function str_ends_with(str, ending)
return ending == "" or str:sub(-#ending) == ending
end
local function str_split(inputstr, sep)
if sep == nil then sep = "%s" end
local result = {}
for str in inputstr:gmatch("([^"..sep.."]+)") do table.insert(result, str) end
return result
end
local function json_parse(json_str)
local ok
local result
ok, result = pcall(sjson.decode, json_str)
if ok then return result end
return nil
end
local function json_stringify(table)
local ok
local json
ok, json = pcall(sjson.encode, table)
if ok then return json end
return nil
end
local function get_http_header_value(hname, hlines)
for _, hline in pairs(hlines) do
if str_starts_with(hline:lower(), hname:lower()) then
local colon_index = hline:find(':')
if colon_index ~= nil then
return hline:sub(colon_index + 2)
end
end
end
return nil
end
local function get_auth_from_http_header(hlines)
local auth_line = get_http_header_value('Authorization', hlines)
if auth_line == nil then return nil end
local parts = str_split(auth_line)
if #parts == 2 and parts[1]:lower() == 'basic' then
local key = parts[2]
parts = nil
local ok
local decoded_key
ok, decoded_key = pcall(encoder.fromBase64, key)
key = nil
if ok then
parts = str_split(decoded_key, ':')
decoded_key = nil
if #parts == 2 then
return {
user = parts[1],
pwd = parts[2]
}
end
end
end
return nil
end
local function parse_http_header(request, params)
local options = {
parse_auth = false
}
if params ~= nil then
if params.parse_auth ~= nil then options.parse_auth = params.parse_auth end
end
local hlines = str_split(request, "\r\n")
if #hlines > 0 then
local hline1_parts = str_split(hlines[1])
if #hline1_parts == 3 and hline1_parts[3] == 'HTTP/1.1' then
local result = {
method = hline1_parts[1],
path = hline1_parts[2],
std = hline1_parts[3]
}
hline1_parts = nil
result.content_length = get_http_header_value('Content-Length', hlines)
if options.parse_auth then
result.auth = get_auth_from_http_header(hlines)
end
hlines = nil
if result.content_length ~= nil then
result.content_length = tonumber(result.content_length)
end
return result
end
end
return nil
end
-- Extends one level only
local function extend(tbl, with)
if with ~= nil then
for k, v in pairs(with) do
if tbl[k] == nil then
tbl[k] = with[k]
end
end
end
return tbl
end
Api32.create = function(conf)
local self = extend({
http_body_min = 10,
http_body_max = 512,
port = 80,
auth = nil
}, conf)
local endpoints = {}
self.on = function(method, path, handler)
table.insert(endpoints, {
method = method,
path = path,
handler = handler
})
return self
end
self.on_get = function(path, handler)
return self.on('GET', path, handler)
end
self.on_post = function(path, handler)
return self.on('POST', path, handler)
end
local get_endpoint = function(method, path)
for _, ep in pairs(endpoints) do
if ep.method == method and ep.path == path then return ep end
end
return nil
end
local srv = net.createServer(net.TCP, 30)
local sending = false
local http_header = nil
local http_req_body_buffer = nil
local function stop_rec()
sending = false
http_header = nil
http_req_body_buffer = nil
end
local is_authorized = function()
return self.auth == nil or (
http_header ~= nil
and http_header.auth ~= nil
and self.auth.user == http_header.auth.user
and self.auth.pwd == http_header.auth.pwd
)
end
local function parse_http_request(sck)
local res = {}
local stream_file = nil
local send = function(_sck)
sending = true
local close_socket = false
if #res > 0 then
_sck:send(table.remove(res, 1))
elseif stream_file ~= nil then
local line = stream_file:readline()
if line ~= nil then
_sck:send(line)
else
stream_file:close()
stream_file = nil
close_socket = true
end
else
close_socket = true
end
if close_socket then
sending = false
_sck:close()
res = nil
end
end
sck:on('sent', send)
local response_status = '200 OK'
local content_type = 'application/json'
local response_body = nil
res[1] = 'HTTP/1.1 '
res[2] = 'Content-Type: CTYPE; charset=UTF-8\r\n'
if http_header == nil then
response_status = '400 Bad Request'
else
if not is_authorized() then
response_status = '401 Unauthorized'
res[#res + 1] = 'WWW-Authenticate: Basic realm="User Visible Realm", charset="UTF-8"\r\n'
else
local ep = get_endpoint(http_header.method, http_header.path)
if ep == nil then
response_status = '404 Not Found'
else
http_header = nil
if type(ep.handler) == 'function' then -- custom handler
local jreq = json_parse(http_req_body_buffer)
http_req_body_buffer = nil
local jres = ep.handler(jreq)
jreq = nil
response_body = json_stringify(jres)
jres = nil
elseif type(ep.handler) == 'string' then -- static file
-- ep.handler is filename in this case
http_req_body_buffer = nil
if not file.exists(ep.handler) then
response_status = '404 Not Found'
else
if str_ends_with(ep.handler, 'html') then
content_type = 'text/html'
end
stream_file = file.open(ep.handler)
end
end
end
end
end
res[1] = res[1] .. response_status .. "\r\n"
res[2] = res[2]:gsub('CTYPE', content_type)
res[#res + 1] = "\r\n"
if response_body ~= nil then
res[#res + 1] = response_body
response_body = nil
end
stop_rec()
send(sck)
end
local on_receive = function(sck, data)
if sending then return end
if http_header == nil then
local eof_head = data:find("\r\n\r\n")
local head_data = nil
if eof_head ~= nil then
head_data = data:sub(1, eof_head - 1)
http_req_body_buffer = data:sub(eof_head + 4)
end
data = nil
if head_data ~= nil then
http_header = parse_http_header(head_data, {
parse_auth = self.auth ~= nil
})
head_data = nil
end
if http_header ~= nil then
if http_header.content_length == nil
or http_header.content_length < self.http_body_min
or http_header.content_length > self.http_body_max then
-- It seems like request body is too short, too big or does not exist at all.
-- Parse request immediatelly
return parse_http_request(sck)
end
else
-- Received some data which does not represent the http header.
-- Let's parse it anyway because error 400 shoud be sent back to the client
return parse_http_request(sck)
end
end
if data ~= nil and http_header ~= nil then
-- Buffering request body
if http_req_body_buffer == nil then
http_req_body_buffer = data
else
http_req_body_buffer = http_req_body_buffer .. data
end
end
-- Check if body has received
if http_req_body_buffer ~= nil then
local http_body_len = http_req_body_buffer:len()
if (http_header.content_length ~= nil and http_body_len >= http_header.content_length)
or http_body_len >= self.http_body_max then
-- Received enough bytes of request body.
return parse_http_request(sck)
end
end
end
srv:listen(self.port, function(conn)
stop_rec()
conn:on('receive', on_receive)
conn:on('disconnection', stop_rec)
end)
return self
end
return Api32
and another module api32local
local M = {}
_G[moduleName] = M
if api == nil then
api = require('api32')
.create()
.on_get('/', function() return{message = 'Welcome to the API32!'} end)
.on_post("/house_lamp",function(jreq,raw_data)
if jreq==nil or raw_data==nil then return end
gpio.write(BLUE_LED, jreq.state)
print("led Post Command")
return{"lamp_status updated"}
end)
end
return M
for wifi
wifi.mode(wifi.SOFTAP)
cfg={}
cfg.ip='192.168.0.10'
cfg.netmask='255.255.255.0'
cfg.gateway='192.168.0.1'
cfg.dns='8.8.8.8'
wifi.ap.setip(cfg)
wifi.ap.config({
ssid = "****",
pwd = "*123456#",
auth=wifi.AUTH_OPEN,
auto = false
})
Myapi32_init=require'api32local'
wifi.ap.on("sta_connected", function(event, info) Myapi32_init.init_api32() print("MAC_id"..info.mac,"Name"..info.id) end)
wifi.start()
please help me debugging issue. Can't able to understand where to use cross origin headers and how, and about preflight concept which are importent for angular based android app to communicate locally(without internet) through http with ESP32

Value doesn't save in dataStore

I need to save multies for my game. When i test it the value turns into 0.
Tried to make different dataStore only for multies but still doesn't work.
Console gives no errors. Only prints the value of Stat that doesn't change bc of multi.
DataTable also prints after closing the game that all multies are 0.
Code:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local dataStore1 = DataStoreService:GetDataStore("Test1")
local function waitForRequestBudget(requestType)
local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
while currentBudget < 1 do
currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
task.wait(5)
end
end
local function setupPlayerData(player: player)
local userID = player.UserId
local key = "Player_"..userID
local AgMulti = Instance.new("IntValue", player)
AgMulti.Name = "AgMulti"
AgMulti.Value = 1
local ReiatsuMulti = Instance.new("IntValue", player)
ReiatsuMulti.Name = "ReiatsuMulti"
ReiatsuMulti.Value = 1
local StrengthMulti = Instance.new("IntValue", player)
StrengthMulti.Name = "StrengthMulti"
StrengthMulti.Value = 1
local DuraMulti = Instance.new("IntValue", player)
DuraMulti.Name = "DuraMulti"
DuraMulti.Value = 1
local success, returnValue
repeat
waitForRequestBudget(Enum.DataStoreRequestType.GetAsync)
success, returnValue = pcall(dataStore1.GetAsync,dataStore1, key)
until success or not Players:FindFirstChild(player.Name)
success, returnValue = pcall(dataStore1.GetAsync,dataStore1, key)
if success then
if returnValue == nil then
returnValue = {
DuraMulti = 1,
StrengthMulti = 1,
ReiatsuMulti = 1,
AgMulti = 1,
}
end
StrengthMulti.Value = if returnValue.StrengthMulti ~= nil then returnValue.StrengthMulti else 0
DuraMulti.Value = if returnValue.DuraMulti ~= nil then returnValue.DuraMulti else 0
ReiatsuMulti.Value = if returnValue.ReiatsuMulti ~= nil then returnValue.ReiatsuMulti else 0
AgMulti.Value = if returnValue.AgMulti ~= nil then returnValue.AgMulti else 0
else
player:Kick("There was an error loading your Data. Roblox's DataStore might be down, try again later, or contact us!")
print(player.Name.."Data loading Error!")
end
end
local function save(player)
local userID = player.UserId
local key = "Player_"..userID
local strengthmulti = player.StrengthMulti.Value
local duramulti = player.DuraMulti.Value
local reiatsumulti = player.ReiatsuMulti.Value
local agmulti = player.AgMulti.Value
local dataTable = {
StrengthMulti = strengthmulti,
DuraMulti = duramulti,
ReiatsuMulti = reiatsumulti,
AgMulti = agmulti,
}
print(dataTable)
local success, returnValue
repeat
waitForRequestBudget(Enum.DataStoreRequestType.GetAsync)
success, returnValue = pcall(dataStore1.UpdateAsync, dataStore1, key, function()
return dataTable
end)
until success
if success then
print("Data Saved!")
else
print("Data saving Error!")
end
end
local function onShutDown()
if RunService:IsStudio() then
task.wait(2)
else
local finished = Instance.new("BindableEvent")
local allPlayers = Players:GetPlayers()
local leftPlayers = #allPlayers
for _, player in ipairs(allPlayers) do
coroutine.wrap(function()
save(player)
leftPlayers -=1
if leftPlayers == 0 then
finished:Fire()
end
end)
end
finished.Event:Wait()
end
end
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(setupPlayerData)(player)
end
Players.PlayerAdded:Connect(setupPlayerData)
Players.PlayerRemoving:Connect(save)
game:BindToClose(onShutDown)
while true do
task.wait(300)
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(save)(player)
end
end

Lua self method call attempt (a nil value)

I wrote a small class to receive data over TCP, but periodically (not constantly, sometimes the script runs long enough and receives data) I get an error:
.\modules\tcp.lua:83: attempt to call method '_parsing' (a nil value)
I can't figure out why the object loses the method that it had in the self and which worked. When creating the class I am using the module https://github.com/kikito/middleclass
After creating an object, I call in while loop:
feed:receive()
Class sample
os.setlocale("C")
package.path = package.path .. ";./libs/?.lua";
package.path = package.path .. ";./libs/luasocket/lua/?.lua";
package.cpath = package.cpath .. ";./libs/luasocket/?.dll";
package.cpath = package.cpath .. ";./libs/luasocket/mime/?.dll";
package.cpath = package.cpath .. ";./libs/luasocket/socket/?.dll";
local class = require "middleclass";
local socket = require "socket";
local struct = require "struct";
local msgpack = require "msgpack";
local type = type
local table = table
local string = string
local TCP = class("TCP")
function TCP:initialize(address, port, logger, onOpen, onClose, onMessages)
self.address = address
self.port = port
self.logger = logger
self.onOpen = onOpen
self.onClose = onClose
self.onMessages = onMessages
self.socket = nil
self.connected = false
self.seq_in = 0
self.chunk_in = ""
self.seq_out = 0
self.chunk_out = ""
end
function TCP:_connection_made()
if not self.socket then
self.socket = socket.tcp()
local status, _ = self.socket:connect(self.address, self.port)
if status then
self.socket:setoption("reuseaddr", true)
self.socket:setoption("tcp-nodelay", true)
self.socket:setoption("keepalive", true)
self.socket:settimeout(0)
self.logger:info("Connection open "..self.address..":"..self.port.."")
self.connected = true
if self.onOpen then
self.onOpen()
end
else
self.socket = nil
end
end
end
function TCP:_connection_close()
self.logger:info("Connection close "..self.address..":"..self.port.."")
self.socket = nil
self.connected = false
self.seq_in = 0
self.chunk_in = ""
self.seq_out = 0
self.chunk_out = ""
if self.onClose then
self.onClose()
end
end
function TCP:_receive()
local data, error, partial = self.socket:receive("*a")
if (not data) and (error ~= "timeout") then
self.logger:error("Connection error "..error)
self:_connection_close()
return nil, error
end
data = data or partial
if not data then
return nil, error
else
return self:_parsing(data)
end
end;
function TCP:_parsing(data)
local messages = {}
if self.chunk_in ~= "" then
data = self.chunk_in..data
self.chunk_in = ""
end
while string.len(data) ~= 0 do
if string.len(data) >= 10 then
local size, seq = struct.unpack("<HL", data)
if string.len(data) >= size + 10 then
if seq ~= self.seq_in + 1 then
self.logger:warn("Connection expected seq: "..(self.seq_in + 1)..", received seq: "..seq)
end
self.seq_in = seq
local msg = msgpack.unpack(string.sub(data, 11, 10 + size))
data = string.sub(data, 11 + size)
table.insert(messages, msg)
else
self.chunk_in = self.chunk_in..data
data = ""
end
else
self.chunk_in = self.chunk_in..data
data = ""
end
end
if self.onMessages then
self.onMessages(messages)
else
return messages, ""
end
end;
function TCP:_send(msg)
self.logger:debug("Try to send message", msg)
if type(msg) == "table" then
local data = msgpack.pack(msg)
self.seq_out = self.seq_out + 1
local frame = struct.pack("<HL", string.len(data), self.seq_out)
local index, error = self.socket:send(frame..data)
if error then
self.logger:error("Connection send error "..error)
if error == "closed" then
self:_connection_close()
end
end
end
end
function TCP:open()
if not self.connected then
self:_connection_made()
end
end
function TCP:close()
if self.connected then
self:_connection_close()
end
end
function TCP:receive()
if not self.connected then
self:_connection_made()
else
return self:_receive()
end
end
function TCP:send(msg)
if not self.connected then
return nil
else
return self:_send(msg)
end
end
return TCP

Resources