I created a websocket server and client plug-in!

I finished my first native plug-in for Solar2d last night! It allows you to create a websocket server in your Lua code on iOS, Android, TVOS, Mac, and their respective simulators. It even works in the Corona simulator. HTML5 is obviously not supported because you can host a server in a browser. Windows (builds and simulator) is not yet supported because I don’t have a Windows computer on me at the moment, and I might have to find another c library to make it happen (my current implementation depends on unix-styled APIs).

Using it is simple. Here’s an example of a server and a client implementation on the same device.

local SolarWebSockets = require "plugin.solarwebsockets"

local message = display.newText("debug messages here", 120, 320, nil, 6)

local clients = {}
local json = require("json")
local function wsListener( event )
    message.text = json.encode(event)
    if event.isServer then
        if event.name == "join" then
            print("join", "clients #", #event.clients)
            print(event.clientId)
            print(event.clientIp)
            clients = event.clients
            for i=1, #event.clients do
                print(
                    "client "..tostring(i),
                    tostring(event.clients[i]),
                    tostring(event.clients[i].clientId),
                    tostring(event.clients[i].clientIp)
                )
            end
        end
        if event.name == "message" then
            print("got message")
            print(event.clientId)
            print(event.clientIp)
            print(event.message)
            SolarWebSockets.sendClient(event.clientId,"echo "..event.message)
            SolarWebSockets.sendAllClients("someone said "..event.message)
            if event.message == "kick" then
                local clientToKick = clients[1]
                if clientToKick then
                    print("going to kick "..tostring(clientToKick.clientId))
                    SolarWebSockets.kick(clientToKick.clientId)
                end
            end
        end
        if event.name == "leave" then
            print("leave","clients #", #event.clients)
            print(event.clientId)
            print(event.clientIp)
            clients = event.clients
            for i=1, #event.clients do
                print(
                    "client "..tostring(i),
                    tostring(event.clients[i]),
                    tostring(event.clients[i].clientId),
                    tostring(event.clients[i].clientIp)
                )
            end
        end
    elseif event.isClient then
        if event.name == "join" then
            -- connected
        end
        if event.name == "message" then
            print("got message from server")
            print(event.message)
            -- send reply
            -- SolarWebSockets.send("reply "..event.message)
        end
        if event.name == "leave" then
            -- not connected anymore
            print("left server")
            print("error code: ",tostring(event.errorCode))
            print("error message: ",tostring(event.errorMessage))
        end
    end
end

SolarWebSockets.init( wsListener )

local widget = require("widget")

widget.newButton({
   left = 50,
   width = 100,
   top = 50,
   label = "Start Server",
   shape = "rect",
   onRelease = function()
       SolarWebSockets.startServer()
   end,
   fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
})
SolarWebSockets.startServer()

widget.newButton({
    left = 50,
    width = 100,
    top = 150,
    label = "Kill Server",
    shape = "rect",
    onRelease = function()
        SolarWebSockets.killServer()
    end,
    fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
})

widget.newButton({
   left = 50,
   width = 100,
   top = 250,
   label = "Kick someone",
   shape = "rect",
   onRelease = function()
       local clientToKick = clients[1]
       if clientToKick then
           print("going to kick "..tostring(clientToKick.clientId))
           SolarWebSockets.kick(clientToKick.clientId)
       end
   end,
   fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
})


-- client
widget.newButton({
    left = 150,
    width = 100,
    top = 50,
    label = "Connect to Server",
    shape = "rect",
    onRelease = function()
        -- wss not supported on iOS...yet
        SolarWebSockets.connect("wss://echo.websocket.org")
    end,
    fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
 })
 
widget.newButton({
    left = 150,
    width = 100,
    top = 150,
    label = "SendMessage",
    shape = "rect",
    onRelease = function()
       SolarWebSockets.sendServer("sample message")
    end,
    fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
})
 
widget.newButton({    left = 150,
    width = 100,
    top = 250,
    label = "Disconnect",
    shape = "rect",
    onRelease = function()
       SolarWebSockets.disconnect()
    end,
    fillColor = { default={ 1, 1, 1 }, over={ .2, 0.2, 0.2 } }
})

And you just include it like this

plugins = {
	["plugin.solarwebsockets"] =
	{
		publisherId = "io.joehinkle",
	},
},

I’m using this for local multiplayer games. It’s really solid from my tests so far, as I’m using websocket server implementations in C and Java (for Android).

I’m going to open source this soon and see if I can get it on the Solar2D direction also. Hope you guys like it or find use.

7 Likes

Greate! I used it but what import command i need?

It isn’t up yet–I just have it on my local machine. I’m going to work with Vlad to get I published today/tomorrow. I’ll let you know when it’s up.

1 Like

It’s been fun watching you develop this and I’m excited to give it a whirl!

So looking forwards to seeing this. So much potential! :slight_smile:

Here’s the repo. I was working on it after midnight and got both client and servers working in in. Anyways leave it a star because it gives me dopamine.

And I’m working at this hour because I’m really sick, and slept for about 5-6 hours during the day. I felt amazing in the middle the night, so I knocked it out. Hope you guys enjoy. I’m going to sleep.

1 Like

And starred :slight_smile:

I’m gonna have a play with this in the coming weeks. I’ve gotta say, I’ve been waiting for a real socket server implementation on Solar2D (or Corona as was) for years!

Well done!

1 Like

I had as well. I think I went nuts trying a lua socket server that just wasn’t working, and then thought “okay let’s just solve this once and for all!”

1 Like

Hey guys, so I got the repo in Solar2d’s org up, but the GitHub Actions isn’t triggering yet. I’ll post once that is up and running.

Update: It’s working! I haven’t tested it in the Simulator yet though

Okay the plugin is working on Solar/Corona version 3600 and above. Just add:

plugins =
	{
		["plugin.solarwebsockets"] = {
            publisherId = "io.joehinkle",
        },
},

Also, there is currently a bug in the simulator version of the plugin. If you build the app though it works. I’m going to put a patch up sometime this weekend. It think it was just a name-change issue when I changed the name of the dylib.

Please test this and give me feedback! Also put up a PR if you find an issue.

:slight_smile:

Another update: that macOS bug was really easy, it’s fixed! Just waiting for this PR to be approved and it will automatically work in the simulator :slight_smile: https://github.com/solar2d/plugins.solar2d.com/pull/1

2 Likes

This is still an issue with web/html5 builds. It’s only possible to support a websocket client (server is actually impossible in the browser), but the client seems to be broken. It’s probably an issue in the way it’s packaged.

Update: web/html5 builds are now working fine in version v4. No changes needed on your end. It should just work