PDA

View Full Version : Girder response to ievent from remote client



aurdoc
February 27th, 2004, 11:03 AM
I have been very successful in generating ievents to Girder from TCP clients.
I can not find any information, however, on how to send a message from Girder to the client. Is this possible? If LUA must be used how do I find information on how to use LUA to achieve my goal? How does LUA keep track of the logged clients?

Wagner
February 28th, 2004, 07:39 PM
When you receive an event from the built in IES in Girder, the first payload in the event (pld1) is the IP of the computer the event came from. I don't know if that answers your question or not.

aurdoc
February 29th, 2004, 12:58 PM
Thanks. This partly answers my question. By deduction, I assume, that I must use the LUA to replay.

Do you know where I may obtain any documentation on the interface between LUA and Girder's IES?

Promixis
February 29th, 2004, 07:41 PM
You can use luasockets. The best example of this comes from netremote.

aurdoc
February 29th, 2004, 09:29 PM
Thanks Mike for the hint. Although I am not familiar with LUA I have a lot of experience with communication software. A brief look at LUASockets did not give me the answer I am seeking.

I guess I am still confused on how this all works. Girder IES accepts a connection on port 1024. It now owns the socket. To send a packet on the same socket I must tell Girder to do so, unless Girder uses the socket only as a half-duplex channel (for receiving), i.e. I must open a separat socket to transmit data back. Obviously Girder does send data back otherwise it could not support the logging protocol.

I am hoping that there is a Girder call I can make to send data back out on the same socket it recieved the request. I am filling pretty stupid since it seems that nobody else seem to be confused about this issue. Therefore there must be some obvious answer which I am still missing.

Promixis
March 1st, 2004, 05:02 AM
Here is the netremote/girder code. I think it will help you get going.



--------------------------------------------------------------------------------
-- NetRemote Feedback Interface Gavin Brock --
--------------------------------------------------------------------------------
-- Requires:
--
-- NetRemote:
-- http://www.netremote.org
--
-- Girder:
-- http://www.girder.nl/
--
-- Girder LUA Events Plugin:
-- http://www.girder.nl/phpBB2/viewtopic.php?t=3864
--
--------------------------------------------------------------------------------

print("Loading NetRemote Feedback.lua")

--------------------------------------------------------------------------------
-- Start with some LUA incantations
--------------------------------------------------------------------------------

local Public, Private = {}, {}
NetRemote = Public

Public.VERSION = 0.06


--------------------------------------------------------------------------------
-- Possible User Settings
--------------------------------------------------------------------------------

-- Connection Timeout in seconds
Public.TIMEOUT = 5



--------------------------------------------------------------------------------
-- Girder Specific stuff here
--------------------------------------------------------------------------------

-- Handle all NRCLIENT.REGISTER Internet Events
-- pld1 should be the IP, pld2 is the port to connect back to
--
AddEventHandlerName(203, "NRCLIENT.REGISTER", "GirderRegisterNRClient")
print("LOAD")

function GirderRegisterNRClient()
local err = %Private.Register(pld1,pld2)
if err then print("GirderRegisterNRClient Error: err") end
result = 1 -- Pass on to other handlers
end



--------------------------------------------------------------------------------
-- PRIVATE FUNCTIONS
--------------------------------------------------------------------------------


--------------------------------------------------------------------------------
-- Package Varaibles
--------------------------------------------------------------------------------

-- A hash of client objects
Private.Clients = {}

-- Cache of all label feedback
Private.LabelCache = {}

-- Cache of all image feedback (filenames)
Private.ImageCache = {}


--------------------------------------------------------------------------------
-- Register -- NR requests the establishment of a TCP session
--------------------------------------------------------------------------------

function Private.Register(ipaddr,port)
if (ipaddr and port and ipaddr ~= '' and port ~= '') then
print("Registering "..ipaddr..":"..port)

local sock, err = connect(ipaddr, port)
if not sock then return nil, err end

sock:timeout(%Public.TIMEOUT)

err = sock:send("quintessence\n")
if err then
sock:close()
return err
end

local x = sock:receive()

err = sock:send("EMPTYPASS\n")
if err then
sock:close()
return err
end

local y = sock:receive()

local client = {
["sock"]=sock
}

local Clients = %Private.Clients
if (Clients[ipaddr]) then
%Private.Destroy(Clients[ipaddr])
end

Clients[ipaddr] = client
print("Connected")

%Private.SyncState(client)

else
print("Got a bad IP/Port")

end
end


--------------------------------------------------------------------------------
-- SyncState -- Send all cached values to a new client
--------------------------------------------------------------------------------

function Private.SyncState(client)

-- The Image Cache
local imagecache = %Private.ImageCache
for label, file in imagecache do
local data = %Private.PackImage(label,file)
-- print("Sync image data "..data)
if data then %Private.Send(client,data) end
end

-- The Label Cache
local labelcache = %Private.LabelCache
for label, value in labelcache do
local data = %Private.PackLabel(label,value)
-- print("Sync label data "..data)
if data then %Private.Send(client,data) end
end

end


--------------------------------------------------------------------------------
-- Quote -- Double quote a string an escape any quotes
--------------------------------------------------------------------------------

function Private.Quote(string)
string = gsub(string, "\\", "\\\\") -- \
string = gsub(string, "\"", "\\\"") -- "
string = gsub(string, "\n", "\\\n") -- \n
string = "\""..string.."\""
return string
end


--------------------------------------------------------------------------------
-- SendToAll -- Send a payload to all clients
--------------------------------------------------------------------------------

function Private.SendToAll(data)
local Clients = %Private.Clients
--print("Send data "..data)

for ipaddr, client in Clients do
err = %Private.Send(client,data)

if (err) then
print("Disconnect: "..err)
%Private.Destroy(client)
Clients[ipaddr] = nil
end
end
end


--------------------------------------------------------------------------------
-- Send -- Send a payload to a client object
--------------------------------------------------------------------------------

function Private.Send(client,data)
local sock = client.sock
if (sock) then
local err, bytes = sock:send(data)
if err then return err end
else
return "Invalid socket for client"
end
end


--------------------------------------------------------------------------------
-- Destroy -- Close down a client
--------------------------------------------------------------------------------

function Private.Destroy(client)
if client.sock then client.sock:close() end
end


--------------------------------------------------------------------------------
-- PackLabel -- Take a label and value and pack it into a payload
--------------------------------------------------------------------------------

function Private.PackLabel(label,value)
label = %Private.Quote(label)
value = %Private.Quote(value)
return "SET "..label.." "..value.."\n"
end


--------------------------------------------------------------------------------
-- PackImage -- Take an image file and pack it into a payload
--------------------------------------------------------------------------------

function Private.PackImage(label,file)
label = %Private.Quote(label)

local fh, err = openfile(file,"rb") -- Read-Only Binary File
if (fh) then

-- Get image data as a variable
local imgdata = read(fh,"*a");
closefile(fh)

-- Get the size of the data
local imglength = strlen(imgdata)

-- Extract the image type from the file name
local _, _, imgtype = strfind(file,"%.([^%.]+)$")
imgtype = strlower(imgtype)
if (imgtype == "jpeg") then imgtype = "jpg" end

-- Check the imgtypes
-- TODO

-- Build the data message and send
return "SETIMAGE "..label.." "..imgtype.." "..
imglength.."\n"..imgdata.."\n"
else
return "SETIMAGE "..label.." jpg 0\n"
end
end



--------------------------------------------------------------------------------
-- PUBLIC FUNCTIONS
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- NetRemote.SendLabel -- Set a button label value
-- Input
-- label: The name of the button to setfor k=1,getn(dvd) do
-- value: The sting to send to the label
-- Returns
-- err: The last error received
--------------------------------------------------------------------------------


function Public.SendLabel(label,value)

-- Cache the data
local cache = %Private.LabelCache
if (value == '') then
cache[label] = nil
else
cache[label] = value
end

-- Build the data message and send
local data = %Private.PackLabel(label,value)
if data then %Private.SendToAll(data) end
end


--------------------------------------------------------------------------------
-- NetRemote.SendImage -- Set a button's image
-- Input
-- label: The name of the button to set
-- file: The full path of the image file to send
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.SendImage(label,file)
local cache = %Private.ImageCache

if (value == '') then
cache[label] = nil
else
cache[label] = file
end

local data = %Private.PackImage(label,file)
if data then %Private.SendToAll(data) end
end


--------------------------------------------------------------------------------
-- NetRemote.JumpHome -- Jump to a "home" panel
-- Input
-- panel (optional): The name a home panel to jump to
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.JumpHome(panel)
-- Quote the panel name or use a zero length string
if panel then panel = %Private.Quote(panel) else panel = '' end

-- Build the data message and send
local data = "JUMP H "..panel.."\n"
local err = %Private.SendToAll(data)

return err
end


--------------------------------------------------------------------------------
-- NetRemote.JumpDevice -- Jump to a "device" panel
-- Input
-- device (optional): The name a device to jump to
-- panel (optional): The name a device's to jump to
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.JumpDevice(device, panel)
-- Quote the panel and device name or use a zero length string
if panel then panel = %Private.Quote(panel) else panel = '' end
if device then device = %Private.Quote(device) else device = '' end

-- Build the data message and send
local data = "JUMP D "..device.." "..panel.."\n"
local err = %Private.SendToAll(data)

return err
end


--------------------------------------------------------------------------------
-- NetRemote.JumpMacro -- Jump to a "macro" panel
-- Input
-- device (optional): The name a device to jump to
-- panel (optional): The name a device's to jump to
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.JumpMacro(device,panel)
-- Quote the panel and device name or use a zero length string
if panel then panel = %Private.Quote(panel) else panel = '' end
if device then device = %Private.Quote(device) else device = '' end

-- Build the data message and send
local data = "JUMP M "..device.." "..panel.."\n"
local err = %Private.SendToAll(data)

return err
end


--------------------------------------------------------------------------------
-- NetRemote.BatchStart -- Begin a batch of messages. Batched actions are not
-- performed until the end of the batch. This helps with screen redraws.
-- Input
-- none
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.BatchStart()
local data = "BATCHSTART\n"
local err = %Private.SendToAll(data)
return err
end


--------------------------------------------------------------------------------
-- NetRemote.BatchComplete -- End the batch of messages.
-- Input
-- none
-- Returns:
-- err: The last error received
--------------------------------------------------------------------------------

function Public.BatchComplete()
local data = "BATCHCOMPLETE\n"
local err = %Private.SendToAll(data)
return err
end


--------------------------------------------------------------------------------
-- Finally, let other code know that the NetRemote.* functions have been defined
--------------------------------------------------------------------------------

TriggerEvent("NetRemote.Loaded", 18, Public.VERSION)

--------------------------------------------------------------------------------
-- That's all folks...
--------------------------------------------------------------------------------

aurdoc
March 3rd, 2004, 11:30 AM
Hi Mike,

Thanks for answering my questions. I have looked at the "Netremote Feedback Interface" code and I have done some experiments. As result I now have another question

I have created a very simple LUA Test file that contains the following code:

----
----
AddEventHandlerName(203, "HTPC.Test", "TestEvent")

function TestEvent()
print("--------Test Event--------")
print("Test Event pld1: "..pld1)
print("Test Event pld2: "..pld2)
print("------End Test Event------")
end
-----
-----

The Girder plugins: "Internet Event Server", Logging, "LuaEvents 1.0.1" and "LuaSocket Library" are all enabled and configured to default mode. I am using Girder 3.3.

My client connects to Girder Internet Server (MD5 hash and all) and then I send the "HTPC.Test\n" to Girder. The logger gives me the following result:

EVENT: Dev: 203 HTPC.Test Pld1: 127.0.0.1
LUA: return Lua TestEvent global
PRINT: ------End Test Event------
PRINT: Test Event pld2:
PRINT: Test Event pld1: 127.0.0.1
PRINT: --------Test Event--------
LUA: call Lua TestEvent global
LUA EVENTS: 'Name' type event processing using: 'TestEvent'

(I removed the times to keep it simple). Indeed pld1 contains the IP address but pld2 is empty. "Netremote Feedback Interface" assumes that pld2 contains the port ID. My test returns pld2 = "".

Any suggestions?

Promixis
March 3rd, 2004, 11:53 AM
It looks like you got it working. There is no port sent with the payload. Netremote sends the port to reply on as a second payload.

aurdoc
March 3rd, 2004, 02:52 PM
So if I understand it correctly, Netremote Feedback Interface is basically a half-duplex connection.

The client connects to Girder (via quintessence\n and MD5 hash). When the client sends an event, which requires a response, it sends first a payload containing a portID - the client's receiving port. Two connections must be made: one by the client to upload data to Girder, the other from the Girder Event Handles (via LUASockets' connect() function) to download data to the client.

Two separate connection must be made to complete the circuit.

Is this right?

Promixis
March 3rd, 2004, 07:23 PM
Yes, that is correct. The current luasockets would otherwise create a blocking connection which obviously wouldn't work well :). There is a third party activex control that could be used with luacom that would do non blocking connections. I don't have the url handy but can get it for you if you are interested.

aurdoc
March 3rd, 2004, 08:46 PM
Thanks again. Now that I understend the method I think I can handle the solution. I will try it tomorrow and let you know how is going. I really appreciate your help.