Ok, so I did more testing. Here's what I found.
Andreas Is correct, the plugin appears to be handled as a coroutine... at least when it's called via the MA Cmdline, not when the plugin is loaded. Here's a code snip-it of a test function I made to test this. See the notes I left as comments.
local function loopTest() local socket = require("socket") -- use for time instead of os.time() for more precision local startTime = socket.gettime()*1000 local count = 0 while count < 999999 do count = count + 1 end local endTime = socket.gettime()*1000 local totalTime = endTime - startTime Echo("Loop test ran in " .. totalTime .. " milliseconds") end loopTest() -- Runs when plugin is loaded (startup, saving plugin changes) -- Runs in MainTask -- Not run in coroutine, error if coroutine.yield is called -- Will freeze UI while running (blocks other code from running) -- completes test in ~16 milliseconds return loopTest -- Runs when plugin is called via CmdLine -- Runs in LUA coroutine, coroutine.yield works (but not needed) -- Does not block other code from running. Grey bar appears on plugin pool item while running and UI still works -- Completes test in ~840 milliseconds
Big takeaway here is that code not in functions is executed when the console is started or when you click "Save" after making changes in the plugin editor. This makes sense so that the functions can be made available for reference by the LUA engine (ie "loading" the plugin). Note that this code is run in MainTask, not a coroutine, compared to when you call the plugin via the MA cmdline or by tapping the pool object, it will run in a LUA coroutine. This can also be seen in the output of the System Monitor. (Notice the significant time differences!)
So I came to realize that the initial flaw in my testing earlier was that I didn't put the testing code into functions and it was getting executed inside and hogging up the MainTask as soon as I clicked save... DOH
(PS, gotta laugh a little when the test ends and you see watchdog errors for DataBase, LuaEngine, and Graphics... Those might be a little important lol)
Going back to trying to run a TCP server from an MA plugin...
Since the plugins are run as coroutines and not threads, calling server:connect() or client:receive() still causes the UI to freeze while it waits for a connection/data to be received. The only solution I could find is setting a small enough timeout for those functions so that it doesn't cause too much issue on the rest of the system. Not ideal, but it works I guess.
For those curious, the code I used to test the TCP server is below. The coroutine.yield(2) calls were so that I could see the Echo outputs in the System Monitor and so I know which functions were causing the UI to freeze. If I remove all coroutine.yield(2) calls, the UI will freeze until the plugin is finished. I used Telnet via PuTTY as a client.
local function tcpTest() local socket = require("socket") local server = assert(socket.bind("*", 8956)) server:settimeout(10) coroutine.yield(2) local client = server:accept() ----- UI FREEZES HERE ----- will un-freeze once connection established or timeout expires Echo("client accepted") coroutine.yield(2) client:settimeout(10) local line, err = client:receive() ----- UI FREEZES HERE ----- will un-freeze once message received or timeout expires Echo("received") coroutine.yield(2) if not err then client:send(line .. "\n") -- UI might freeze here, but PuTTY receives the message too quickly to notice Echo("sent") coroutine.yield(2) end client:close() server:close() Echo("client closed") coroutine.yield(2) end return tcpTest