123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- local skynet = require "skynet"
- require "skynet.manager"
- local socket = require "skynet.socket"
- local websocket = require "http.websocket"
- local socketdriver = require "skynet.socketdriver"
- local logger = require "logger"
- local traceback = debug.traceback
- local stringify = require "stringify"
- local nodelay
- local watchdog
- local connection = {} -- fd -> connection : { fd , client, agent , ip, mode }
- local forwarding = {} -- agent -> connection
- local client_number = 0
- local maxclient -- max client
- local function unforward(c)
- if c.agent then
- forwarding[c.agent] = nil
- c.agent = nil
- c.client = nil
- end
- end
- local function close_fd(fd)
- local c = connection[fd]
- if c then
- socketdriver.close(fd)
- unforward(c)
- connection[fd] = nil
- client_number = client_number - 1
- end
- end
- local handle = {}
- function handle.connect(fd)
- -- print("ws connect from: " .. tostring(fd))
- if client_number >= maxclient then
- socketdriver.close(fd)
- return
- end
- if nodelay then
- socketdriver.nodelay(fd)
- end
- client_number = client_number + 1
- local addr = websocket.addrinfo(fd)
- local c = {
- fd = fd,
- ip = addr,
- }
- connection[fd] = c
- skynet.send(watchdog, "lua", "socket", "open", fd, addr)
- end
- function handle.handshake(fd, header, url)
- -- local addr = websocket.addrinfo(fd)
- -- print("ws handshake from: " .. tostring(fd), "url", url, "addr:", addr)
- -- print("----header-----")
- -- for k,v in pairs(header) do
- -- print(k,v)
- -- end
- -- print("--------------")
- end
- function handle.message(fd, msg)
- -- print("ws ping from: " .. tostring(fd), msg.."\n")
- local sz = #msg
- -- recv a package, forward it
- local c = connection[fd]
- local agent = c.agent
- if agent then
- -- It's safe to redirect msg directly , gateserver framework will not free msg.
- skynet.redirect(agent, c.client, "client", fd, msg, sz)
- else
- skynet.send(watchdog, "lua", "socket", "data", fd, msg)
- -- skynet.tostring will copy msg to a string, so we must free msg here.
- skynet.trash(msg,sz)
- end
- end
- function handle.ping(fd)
- -- print("ws ping from: " .. tostring(fd) .. "\n")
- end
- function handle.pong(fd)
- -- print("ws pong from: " .. tostring(fd))
- end
- function handle.close(fd, code, reason)
- -- print("ws close from: " .. tostring(fd), code, reason)
- close_fd(fd)
- skynet.send(watchdog, "lua", "socket", "close", fd)
- end
- function handle.error(fd)
- -- print("ws error from: " .. tostring(fd))
- close_fd(fd)
- skynet.send(watchdog, "lua", "socket", "error", fd)
- end
- local CMD = {}
- function CMD.open(source, conf)
- watchdog = conf.watchdog or source
- local address = conf.address or "0.0.0.0"
- local port = assert(conf.port)
- local protocol = conf.protocol or "ws"
- maxclient = conf.maxclient or 1024
- nodelay = conf.nodelay
- local fd = socket.listen(address, port)
- logger.trace("Listen websocket port:%s protocol:%s", port, protocol)
- socket.start(fd, function(fd, addr)
- logger.trace(string.format("accept client socket_fd: %s addr:%s", fd, addr))
- websocket.accept(fd, handle, protocol, addr)
- end)
- end
- function CMD.forward(source, fd, client, address)
- local c = assert(connection[fd])
- unforward(c)
- c.client = client or 0
- c.agent = address or source
- forwarding[c.agent] = c
- end
- function CMD.accept(source, fd)
- local c = assert(connection[fd])
- unforward(c)
- end
- function CMD.kick(source, fd)
- websocket.close(fd)
- end
- skynet.register_protocol {
- name = "client",
- id = skynet.PTYPE_CLIENT,
- }
- skynet.start(function()
- skynet.dispatch("lua", function(session, source, cmd, ...)
- local f = CMD[cmd]
- if not f then
- skynet.error("simplewebsocket can't dispatch cmd ".. (cmd or nil))
- skynet.ret(skynet.pack({ok=false}))
- return
- end
- if session == 0 then
- f(source, ...)
- else
- skynet.ret(skynet.pack(f(source, ...)))
- end
- end)
- skynet.register(".ws_gate")
- skynet.error("ws_gate booted...")
- end)
|