Open Simon-L opened 11 months ago
Hi @Simon-L and thanks for this PR! I think poll
would be a great addition to the API. I have a little different thought about the API though, how about if poll
would return the OSC packet and it would be up to the user to dispatch it? This would make the API a bit more flexible IMHO in regards to different threading scenarios (e.g. sending the packet to a different thread for dispatch)
The signature could look like this:
--- Poll raw OSC packets.
-- @param[opt] ... Plugin specific arguments.
-- @return status, osc packet bytes or nil/error
-- @usage
-- -- nil is a valid return value so always check status and packet
-- -- before accessing the data.
-- local status, packet = losc:poll()
-- if status and packet then
-- -- do something with packet
-- end
function losc:poll(...)
if not self.plugin then
error('"poll" must be implemented using a plugin.')
end
return pcall(self.plugin.poll, self.plugin, ...)
end
This would be the implementation (for luasocket
)
-- non-blocking
function M:open(host, port, timeout)
host = host or self.options.recvAddr
host = socket.dns.toip(host)
port = port or self.options.recvPort
self.handle:setsockname(host, port)
self.handle:settimeout(timeout or 0.0)
end
function M:poll()
return (self.handle:receive())
end
And the main loop of your example would look like this:
local i = 0
while true do
print("Loop iteration " .. i)
require'socket'.select(nil, nil, 0.25) -- equivalent for sleep() to simulate other tasks
local status, data = osc:poll()
if status and data then
local ok, err = pcall(Pattern.dispatch, data, udp)
if not ok then
print(err)
end
end
i = i + 1
end
We could also add losc:dispatch(data)
to the API as a convenience function for the above.
Let me know what you think!
@davidgranstrom I like the idea of having the dispatch
be separate from the poll()
/plugins. I think this could be taken further and fully separate the dispatch/handler system into its own class (dispatcher
as a sibling of pattern
, packet
, serializer
) and could be completely optional for users of your library (eg. an app that just forwards raw packets to another endpoint wouldn't necessarily care about osc addresses) That being said I don't mind poll()
executing the dispatching directly. It follows the original spirit of your library and it works great in my usage case!
Hey there thanks for the thoughts. I absolutely agree about not automatically dispatching although semantically speaking a non-blocking mode doesn't imply dispatching any differently than the blocking mode, but I get the idea!
This also brings to the table the idea of being able to (re)route osc messages.
@halee88 As far as I can tell from the code and @davidgranstrom's examples above, Pattern.dispatch
is already very much decoupled from the rest of the library, which is very handy for what you suggest.
@Simon-L ahh good catch! I didn't see that pattern
had encapsulated everything needed
Please do not merge as is :)
Related to #33 and #32 Attempted to add necessary methods for non-blocking, as far as I can tell this is working.
Basically it sets a timeout on receive so poll() just returns and other things can happen inbetween polling for new messages, what do you think? I haven't checked using other plugins with these changes.
Note that the new example has a temporary line to run from the source repo and bypas globally installed losc