how do i fix this error with fivem i get script error - server

SCRIPT ERROR: #sessionmanager/server/host_lock.lua:25: attempt to compare number with nil
[script:sessionmanage]> handler (#sessionmanager/server/host_lock.lua:25)
the script:
-- whitelist c2s events
RegisterServerEvent('hostingSession')
RegisterServerEvent('hostedSession')
-- event handler for pre-session 'acquire'
local currentHosting
local hostReleaseCallbacks = {}
-- TODO: add a timeout for the hosting lock to be held
-- TODO: add checks for 'fraudulent' conflict cases of hosting attempts (typically whenever the host can not be reached)
AddEventHandler('hostingSession', function()
-- if the lock is currently held, tell the client to await further instruction
if currentHosting then
TriggerClientEvent('sessionHostResult', source, 'wait')
-- register a callback for when the lock is freed
table.insert(hostReleaseCallbacks, function()
TriggerClientEvent('sessionHostResult', source, 'free')
end)
return
end
-- if the current host was last contacted less than a second ago
if GetHostId() >= 1 then
if GetPlayerLastMsg(GetHostId()) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
hostReleaseCallbacks = {}
currentHosting = source
TriggerClientEvent('sessionHostResult', source, 'go')
-- set a timeout of 5 seconds
SetTimeout(5000, function()
if not currentHosting then
return
end
currentHosting = nil
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
end)
end)
AddEventHandler('hostedSession', function()
-- check if the client is the original locker
if currentHosting ~= source then
-- TODO: drop client as they're clearly lying
print(currentHosting, '~=', source)
return
end
-- free the host lock (call callbacks and remove the lock value)
for _, cb in ipairs(hostReleaseCallbacks) do
cb()
end
currentHosting = nil
end)
EnableEnhancedHostSupport(true)
i tried searching on google but i didnt found anything

correct the block:
if GetHostId() >= 1 then
if GetPlayerLastMsg(GetHostId()) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end
here you need to check for nil or not allow nil when comparing numbers:
local HostId = GetHostId() or 0
if HostId >= 1 then
if GetPlayerLastMsg(HostId) < 1000 then
TriggerClientEvent('sessionHostResult', source, 'conflict')
return
end
end

Related

Attempt to call global function is nil, but function is not shown in debugger?

I am using Eclipse LDT for development, using the packaged Lua EE and Interpreter for Lua 5.2. I need to call the commandDatabase() method from my main method, though when I try, I receive the error:
"attempt to call global 'commandDatabase' (a nil value)".
I have looked up this error, and I am, as far as I can tell, defining methods in the right order.
Lua - attempt to call global 'contains' (a nil value)
When I view it in the debugger, the interpreter does not seem to find any methods I define between commandSystem and commandHelp. It shows each other function in the Variables area as e.g. ["commandSystem"] = function() but commandDatabase() does not appear
I have tried calling a wrapper method like so:
function commandDatabaseStep()
return commandDatabase()
end
... but this did not work either (same error)
The relevant code:
-- System command
function commandSystem()
...
end
-- Database command
function commandDatabase()
if arguments[2] == "no_arg1" then
print("The 'database' command must have at least one argument: [generate, wipe, dump, delete, get <system_name>]", true)
return 2
elseif arguments[2] == "generate" then
local file = io.open(database, "w+")
file:write("#ssmhub database")
file:close(file)
return 1
elseif arguments[2] == "dump" then
print("= DUMP START =")
for line in io.lines(database) do
print(line)
end
print("= DUMP END =")
return 1
-- 1+
elseif arguments[2] == "get" then
-- 2+
if isEmpty(arguments[3]) then
print("The 'database get' command must have a <name> parameter")
return 0
-- 2-
else -- 3+
local file = io.open(database, "r")
for line in io.lines(file) do -- 4+
local state = ""
local id = ""
local dividersFound = 0
line:gsub(".", function(c) -- 5+
if c == "|" then -- 6+
if dividersFound == 0 then -- 7+
state = state .. c
end -- 7-
if dividersFound == 1 then -- 8+
id = id .. c
end -- 8-
dividersFound = dividersFound + 1
end -- 6-
end) -- 5-
io.close(file)
end -- 4-
end -- 3-
else -- 9+
print("Illegal argument for command. Use 'help' for a list of commands and arguments.")
return 0
end -- 9-
end -- 2-
end -- 1-
function commandHelp()
...
end
-- Main
function main()
arguments = readProgramArguments()
commandArgument = arguments[1]
commandCompleteCode = 0
-- Process help and system commands
if commandArgument == "database" then
commandCompleteCode = commandDatabase()
end
end main()
As #luther pointed out, I had one-too-many end-s in commandDatabase.
This wasn't flagged in my IDE because I had not end-ed commandSystem, so commandSystem was nested inside of it.
To fix: add an end to commandSystem, and remove the end which I tagged '-- 1-'.

Reading data only when present

I'm trying to read the data from the COM3 port.
I'm using this code:
in = fscanf(s);
if(in == 'A')
fclose(s);
break;
end
The problem is that when no data is sent to the com3 port, the fscanf() will wait for a certain time interval and then give a timeout.
Is there a way to read data only when it is present?
Read only when data present
You can read out the BytesAvailable-property of the serial object s to know how many bytes are in the buffer ready to be read:
bytes = get(s,'BytesAvailable'); % using getter-function
bytes = s.BytesAvailable; % using object-oriented-addressing
Then you can check the value of bytes to match your criteria. Assuming a char is 1 byte, then you can check for this easily before reading the buffer.
if (bytes >= 1)
in = fscanf(s);
% do the handling of 'in' here
end
Minimize the time to wait
You can manually set the Timeout-property of the serial object s to a lower value to continue execution earlier as the default timeout.
set(s,'Timeout',1); % sets timeout to 1 second (default is 10 seconds)
Most likely you will get the following warning:
Unsuccessful read: A timeout occurred before the Terminator was
reached..
It can be suppressed by executing the following command before fscanf.
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
Here is an example:
s = serial('COM3');
set(s,'Timeout',1); % sets timeout to 1 second (default is 10 seconds)
fopen(s);
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
in = fscanf(s);
warning('on','MATLAB:serial:fscanf:unsuccessfulRead');
if(in == 'A')
fclose(s);
break;
end

Best way to handle multiple connections at the same time

I have an application which listens to multiple connections and verifies whether the user is active or not
I use a 1 thread socket handling method with WSAASyncSelect.
The problem is that sometimes when a lot of users connecting at the same time some users get no reply
i think it is because the "send" hasn't been called yet and the program has received another connection so it goes again to handle the new connection ignoring the previous one. Like WSAASyncSelect has triggered and now it processing a new connection instead of completing the previous request.
So what to do to fix this issue? i tried to stop the events from WSAASyncSelect temporary by calling it with zero parameters when handling the connection until finish it then re enable network events but that didn't help either.
Here are the codes that handling the events (recieve then decrypt and then compare the bytes then send data according to what in listbox ie Active user or not)
This called upon receive of FD_READ
WSAAsyncSelect s, frmMain.hwnd, 0, 0 'Disabling Notifications event
Do Until bytesRecieved = SOCKET_ERROR
bytesRecieved = recv(wParam, buffer(Bytes), 500, 0)
If bytesRecieved > 0 Then
Bytes = Bytes + bytesRecieved
ElseIf bytesRecieved = 0 Then
Exit Sub
End If
Loop
Call MemCopy(ByVal decryptedArrival, buffer(0), Bytes)
WSAAsyncSelect s, frmMain.hwnd, WINSOCKMSG, FD_CONNECT + FD_READ + FD_CLOSE + FD_ACCEPT + FD_WRITE
If frmMain.chkSaveLog.value = vbChecked Then
frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Receiving a connection (" & wParam & ")" & vbNewLine
AutoScroll
If frmMain.chkAutoSave.value = vbChecked Then
strCurrentLogLine = Now & " Receiving a connection (" & wParam & ")"
AutoSaveLog (strCurrentLogLine)
frmMain.cmdClearLogs.Enabled = True
End If
End If
Below here is a decryption of bytes then comparing by ID as byte identifier like 1 = check for update
2 - send user info etc
in a Select Case statement following by a send Api.
And the accepting procedure
This called upon receive of FD_ACCEPT
Function AcceptConnection(wParam As Long)
lpString = String(32, 0)
AcSock = accept(wParam, sockaddress, Len(sockaddress))
strTempIP = getascip(sockaddress.sin_addr)
frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Getting a connection from IP address: " & _
strTempIP & " (" & AcSock & ")" & vbNewLine
AutoScroll
If frmMain.chkAutoSave.value = vbChecked Then
strCurrentLogLine = Now & " Getting a connection from IP address: " & strTempIP & " (" & AcSock & ")" & vbNewLine
AutoSaveLog (strCurrentLogLine)
End If
End Function
Are there any suggestions for a better performance?
What you showed is NOT the correct way to use WSAAsyncSelect(). Try something more like this instead:
When creating a listening socket:
lSock = socket(...)
bind(lSock, ...)
listen(lSock, ...)
WSAAsyncSelect lSock, frmMain.hwnd, WINSOCKMSG, FD_ACCEPT
When a listening socket receives FD_ACCEPT:
Function AcceptConnection(wParam As Long)
AcSock = accept(wParam, sockaddress, Len(sockaddress))
If AcSock = INVALID_SOCKET Then
Exit Sub
End If
WSAAsyncSelect AcSock, frmMain.hwnd, WINSOCKMSG, FD_READ + FD_CLOSE + FD_WRITE
...
End Function
When an accepted client socket receives FD_READ:
Function ReadConnection(wParam As Long)
Do
bytesRecieved = recv(wParam, ReadBuffer(ReadBytes), 500, 0)
If bytesRecieved = SOCKET_ERROR Then
If WSAGetLastError() <> WSAEWOULDBLOCK Then
Exit Sub
End If
ElseIf bytesRecieved = 0 Then
Exit Sub
Else
ReadBytes = ReadBytes + bytesRecieved
End If
Loop Until bytesRecieved = SOCKET_ERROR
' process ReadBuffer up to ReadBytes number of bytes as needed...
' remove processed bytes from front of ReadBuffer and decrement ReadBytes accordingly
...
End Function
When an accepted client socket receives FD_WRITE:
Function WriteConnection(wParam As Long)
While SendBytes > 0
bytesSent = send(wParam, SendBuffer(0), SendBytes, 0)
If bytesSent = SOCKET_ERROR Then
Exit Sub
End If
' remove bytesSent number of bytes from front of SendBuffer ...
SendBytes = SendBytes - bytesSent;
End While
End Function
The trick is that you need to allocate separate ReadBuffer and SendBuffer buffers for each accepted client. Make sure that each time you receive FD_READ that you are appending bytes only to the ReadBuffer of the socket that triggered FD_READ, and each time you receive FD_WRITE that you are removing bytes only from the SendBuffer of the socket that triggered FD_WRITE.
When recv() has no more bytes to read, process that socket's ReadBuffer as needed, removing only complete messages from the front and leaving incomplete messages for later processing.
When send() fails with WSAEWOULDBLOCK, append any unsent bytes to the SendBuffer of the socket that caused send() to fail. When you receive an FD_WRITE event for a socket, check that socket's SenBuffer and resend any bytes that are in it, stopping when the buffer is exhausted or an WSAEWOULDBLOCK error occurs.
Very easy, and quite effective, way to do it is to fork out for every incoming connection. This will most likely require you to restructure your application, but the basic flow should be as follows:
1. New connection is opened to the server
2. Server accepts the connection and forks out
3. The fork closes the original socket for listening, so only the parent will be accepting new connections
4. And then your magic happens, separate from the original thread.
This way you do not have to worry about issues of concurrency, as long as your machine can handle all the traffic and load because each connections is independent.

Console application via network in eiffel?

Hey I'm working in project, but i cant manage to connect from a IP not located in the same network (LAN). The code bellow works fine locally, but I cant figure out how to make work from different IP located in different locations?, and google cant see to help, any ideas?
class
RG_NETWORK_SERVER
inherit
STORABLE
NETWORK_SERVER
redefine
receive,
received,
close
end
create
make_server
feature
connections: LINKED_LIST [RG_CONNECTION]
max_to_poll: INTEGER
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
poll: MEDIUM_POLLER
make_server
require
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_message_out.make
message_out := l_message_out
create l_connections.make
connections := l_connections
connections.compare_objects
execute
end
process_message
local
stop: BOOLEAN
pos: INTEGER
do
from
connections.start
until
connections.after or stop
loop
if connections.item.is_waiting then
if attached {RG_MESSAGE} retrieved (connections.item.active_medium) as l_message_in then
if l_message_in.new then
connections.item.set_client_name (l_message_in.client_name)
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just joined the server%N")
elseif l_message_in.over then
poll.remove_associated_read_command (connections.item.active_medium)
connections.remove
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just gone%N")
stop := True
else
message_out := l_message_in.deep_twin
message_out.put_front (" has just sent that :%N")
message_out.put_front (message_out.client_name)
message_out.put_front ("-> ")
end
pos := connections.index
-- l_message_in.print_message
message_out.print_message
broadcast
connections.go_i_th (pos)
-- Post status to client
create message_out.make
message_out.extend ("Got it! %N")
message_out.independent_store (connections.item.active_medium)
end
end
if not stop then
connections.forth
end
end
end
broadcast
local
client_name: detachable STRING
do
client_name := message_out.client_name
if client_name /= Void then
from
connections.start
until
connections.after
loop
if connections.item.client_name /~ client_name then
message_out.independent_store (connections.item.active_medium)
end
connections.forth
end
end
end
receive
do
in.accept
if attached {like outflow} in.accepted as l_outflow then
l_outflow.set_blocking
new_client (l_outflow)
end
from
connections.start
until
connections.after
loop
connections.item.initialize
connections.forth
end
poll.execute (max_to_poll, 1000)
end
new_client (a_flow: attached like outflow)
local
new_connection: RG_CONNECTION
do
if max_to_poll <= a_flow.descriptor then
max_to_poll := a_flow.descriptor + 1
end
create new_connection.make (a_flow)
connections.extend (new_connection)
create message_out.make
message_out.extend ("Welcome! %N")
message_out.independent_store (a_flow)
poll.put_read_command (new_connection)
end
end
and the client:
class
RG_NETWORK_CLIENT
inherit
NETWORK_CLIENT
redefine
received
end
create
make_join
feature
make_join(ip:STRING)
require
is_ip_void : ip /= Void
local
l_client_name: detachable like client_name
do
check_name
l_client_name := client_name
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
send_name_to_server
auto_scan_server
processing
end
feature
connection: RG_CONNECTION
std_input: detachable RG_CONNECTION
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
client_name: STRING
over: BOOLEAN
poll: MEDIUM_POLLER
input_poll: detachable MEDIUM_POLLER
max_to_poll: INTEGER
waiting:BOOLEAN
send_name_to_server
do
create message_out.make
message_out.set_client_name (client_name)
message_out.set_new (True)
message_out.set_over (False)
send (message_out)
end
processing
do
from
over := False
until
over
loop
scan_from_server
if not over then
read_content
end
end
cleanup
end
read_content
local
temp: detachable STRING
do
io.put_string ("Enter message: ")
io.readline
temp := io.laststring
if temp /= Void and not temp.is_empty then
if temp.is_equal ("bye") then
over := True
end
create message_out.make
message_out.extend (temp)
message_out.extend ("%N")
message_out.set_over (over)
message_out.set_client_name (client_name)
message_out.set_new (False)
send (message_out)
auto_scan_server
end
end
check_name
local
l_name: detachable STRING
do
io.putstring ("Enter your name : ")
io.readline
l_name := io.laststring
check
l_name_attached: l_name /= Void
end
client_name := l_name.twin
end
scan_from_server
local
l_received: like received
do
connection.initialize
poll.execute (max_to_poll, 1000)
if connection.is_waiting then
receive
l_received := received
if l_received /= Void then
waiting := FALSE
l_received.print_message
if l_received.over then
over := True
end
end
end
end
auto_scan_server
do
waiting := True
from until not waiting
loop
scan_from_server
end
end
end
The work around is the work with the samples provided from Eiffel, it works as longest the two persons are connected in the same network. for example as follow:
Here we define if the user has receive the message or is waiting for one, also redefine the poll_command to be able to use it.
inherit
POLL_COMMAND
redefine
make
end
create
make
feature {NONE} -- Initialization
make (s: IO_MEDIUM)
do
Precursor (s)
create client_name.make_empty
end
feature
is_waiting: BOOLEAN
client_name: STRING
execute (arg: ANY)
do
is_waiting := True
end
initialize
do
is_waiting := False
end
set_client_name (s: STRING)
require
s_exists: s /= Void
do
client_name := s.twin
end
end
Then following the chat sample, that can be found in the samples folder, in the message handler, we create the follow:
set_client_name (s: STRING)
require
s_not_void: s /= Void
do
client_name := s.twin
end
set_new (flag: BOOLEAN)
do
new := flag
end
Later in the connection class we are able to connect to a server ip, which it can be pass true command line or via GUI input.
make_join (name: STRING; ip: STRING; gc: RG_CLIENT)
require
is_ip_void: ip /= Void
do
-- Connects to IP on port 1337
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
-- Sets client name and refrence
client_name := name
p_client := gc
-- Sends name to server and receives ID
client_id := send_name_to_server
-- Launches instance as thread
make_thread
launch
execute
end
Then in the server class...
make_server (gs: RG_SERVER)
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
-- Instantiate reference and create server listening on port 1337
game_server := gs
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_connections.make
connections := l_connections
connections.compare_objects
-- Launches instance as tread
make_thread
launch
end
There is a bit more code, but this is a good sample in how to do it, there must be a method to handle the connections, but this is a good start, also remember that all this is based on their samples, chat sample is a good point of start..
enjoy eiffel while is not crashing .

Moai: Graphics that reacts to commands via Sockets

I need a program that can create pre-defined shapes on screen according to that commands I send to it via TCP.
I'm trying to listen to a port and so that I can use them. Before waiting of a command (via network) I have the commands required to create a square (I plan to change its attributes via network commands)
The problem is it is not creating any graphics or opening the window as it should be..
require "socket"
require "mime"
require "ltn12"
host = "localhost"
port = "8080"
server, error = socket.bind(host, port)
if not server then print("server: " .. tostring(error)) os.exit() end
screen=MOAISim.openWindow ( "test", 640, 640 )
viewport = MOAIViewport.new (screen)
viewport:setSize ( 640, 640 )
viewport:setScale ( 640, 640 )
layer = MOAILayer2D.new ()
layer:setViewport ( viewport )
MOAISim.pushRenderPass ( layer )
function fillSquare (x,y,radius,red,green,blue)
a = red/255
b = green/255
c = blue/255
MOAIGfxDevice.setPenColor ( a, b, c) -- green
MOAIGfxDevice.setPenWidth ( 2 )
MOAIDraw.fillCircle ( x, y, radius, 4 ) -- x,y,r,steps
end
function onDraw ( )
fillSquare(0,64,64, 0,0,255)
end
scriptDeck = MOAIScriptDeck.new ()
scriptDeck:setRect ( -64, -64, 64, 64 )
scriptDeck:setDrawCallback ( onDraw)
prop = MOAIProp2D.new ()
prop:setDeck ( scriptDeck )
layer:insertProp ( prop )
while 1 do
print("server: waiting for client command...")
control = server:accept()
command, error = control:receive()
print(command,error)
error = control:send("hi from Moai\n")
end
It is waiting of the command from client at control = server:accept() but it is not opening up the graphics window as it should.. Is there any command to force it to open or render
Thank you
MOAI doesn't run your scripts in a separate thread. A blocking call (server:accept) or forever loop (while true do) will block your MOAI app and it will appear to freeze while it merrily sits in your script forever.
So you have to do two things:
Use non-blocking calls. In this case, you need to set your server's timeout to 0. That makes server:accept return immediately. Check it's return value to see if you got a connection.
Put your while loop in a coroutine and yield once per iteration.
You'll need to handle the client the same way, using non-blocking calls in a coroutine loop.
function clientProc(client)
print('client connected:', client)
client:settimeout(0) -- make client socket reads non-blocking
while true do
local command, err = client:receive('*l')
if command then
print('received command:', command)
err = client:send("hi from Moai\n")
elseif err == 'closed' then
print('client disconnected:', client)
break
elseif err ~= 'timeout' then
print('error: ', err)
break
end
coroutine.yield()
end
client:close()
end
function serverProc()
print("server: waiting for client connections...")
server:settimeout(0) -- make server:accept call non-blocking
while true do
local client = server:accept()
if client then
MOAICoroutine.new():run(clientProc, client)
end
coroutine.yield()
end
end
MOAICoroutine.new():run(serverProc)
Set the timeout for the server socket, since the accept is a blocking call.
server:settimeout(1)
Thanks Mud...I found that before u replied so the following coroutine works
function threadFunc()
local action
while 1 do
stat, control = server:accept()
--print(control,stat)
while 1 do
if stat then
command, error = stat:receive()
print("Comm: ", command, error)
if command then
stat:close()
print("server: closing connection...")
break
else
break
end
--[[
error = stat:send("hi")
if error then
stat:close()
print("server: closing connection...",error)
break
end ]] --
else
break
end
end
coroutine.yield()
end
end
That was very helpful though