Last active
November 8, 2015 10:37
-
-
Save CoderPuppy/10176291 to your computer and use it in GitHub Desktop.
Chat Server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Chat Server by CoderPuppy | |
| local protocol = 'cpup/chat' | |
| local tArgs = { ... } | |
| local function printUsage() | |
| print('Usages:') | |
| print('chatserver.lua <hostname>') | |
| end | |
| local function openModem() | |
| local modemFound = false | |
| for i, side in ipairs(peripheral.getNames()) do | |
| if peripheral.getType(side) == 'modem' then | |
| if not rednet.isOpen(side) then | |
| rednet.open(side) | |
| end | |
| modemFound = true | |
| end | |
| end | |
| if not modemFound then | |
| print('No modems found.') | |
| end | |
| return modemFound | |
| end | |
| -- 'chat host' | |
| -- Get hostname | |
| local hostname = tArgs[1] | |
| if hostname == nil then | |
| printUsage() | |
| return | |
| end | |
| -- Host server | |
| if not openModem() then | |
| return | |
| end | |
| rednet.host(protocol, hostname) | |
| print('0 users connected.') | |
| local users = {} | |
| local nUsers = 0 | |
| function send(msgType, msg, userID) | |
| if userID then | |
| local user = users[userID] | |
| if user then | |
| -- print('sending ' .. msgType .. ' to ' .. user.username) | |
| -- print('sending: ' .. textutils.serialize({ | |
| -- msgType = msgType; | |
| -- msg = msg; | |
| -- -- userID = userID; | |
| -- -- id = user.id; | |
| -- username = user.username; | |
| -- })) | |
| rednet.send(user.id, { | |
| side = 'server'; | |
| msgType = msgType; | |
| msg = msg; | |
| userID = userID; | |
| }, protocol) | |
| end | |
| else | |
| for userID in pairs(users) do | |
| send(msgType, msg, userID) | |
| end | |
| end | |
| end | |
| local tCommands | |
| tCommands = { | |
| ['me'] = function(user, sArgs) | |
| if string.len(sArgs) > 0 then | |
| send('action', { user.userID, user.username, sArgs }) | |
| else | |
| send('msg', { -1, '@', 'Usage: /me [words]' }, user.userID) | |
| end | |
| end, | |
| ['nick'] = function(user, sArgs) | |
| if string.len(sArgs) > 0 then | |
| local oldName = user.username | |
| user.username = sArgs | |
| send('nick', { user.userID, oldName, sArgs }) | |
| else | |
| send('msg', { -1, -1, '@', 'Usage: /nick [nickname]' }, user.userID) | |
| end | |
| end, | |
| ['users'] = function(user, sArgs) | |
| send('msg', { -1, '@', 'Connected Users:' }, user.userID) | |
| local sUsers = '' | |
| for userID, user in pairs(users) do | |
| sUsers = sUsers .. ' ' .. user.username | |
| end | |
| send('msg', { -1, '@', sUsers }, user.userID) | |
| end, | |
| ['help'] = function(user, sArgs) | |
| send('msg', { -1, '@', 'Available commands:' }, user.userID) | |
| local sCommands = '' | |
| for sCommand, fnCommand in pairs(tCommands) do | |
| sCommands = sCommands .. ' /' .. sCommand | |
| end | |
| send('msg', { -1, '@', sCommands..' /logout' }, user.userID) | |
| end, | |
| } | |
| -- Setup ping pong | |
| local pingPongTimers = {} | |
| function ping(userID) | |
| local user = users[userID] | |
| send('pingtc', nil, userID) | |
| local timer = os.startTimer(15) | |
| user.bPingPonged = false | |
| pingPongTimers[timer] = userID | |
| end | |
| function printUsers() | |
| local x,y = term.getCursorPos() | |
| term.setCursorPos(1, y - 1) | |
| term.clearLine() | |
| if nUsers == 1 then | |
| print(nUsers .. ' user connected.') | |
| else | |
| print(nUsers .. ' users connected.') | |
| end | |
| end | |
| -- Handle messages | |
| local ok, error = pcall(function() | |
| parallel.waitForAny(function() | |
| while true do | |
| local sEvent, timer = os.pullEvent('timer') | |
| local userID = pingPongTimers[timer] | |
| if userID and users[userID] then | |
| local user = users[userID] | |
| if user then | |
| if not user.bPingPonged then | |
| send('leave', { user.userID, user.username, 'Timeout' }) | |
| users[userID] = nil | |
| nUsers = nUsers - 1 | |
| printUsers() | |
| else | |
| ping(userID) | |
| end | |
| end | |
| end | |
| end | |
| end, | |
| function() | |
| while true do | |
| local nSenderID, msg = rednet.receive(protocol) | |
| if type(msg) == 'table' then | |
| local userID = msg.userID | |
| local user = users[userID] | |
| -- print('got: ' .. textutils.serialize({ | |
| -- msgType = msg.msgType; | |
| -- msg = msg.msg; | |
| -- -- userID = userID; | |
| -- -- nSenderID = nSenderID; | |
| -- username = user and user.username or msg.msg | |
| -- })) | |
| if msg.msgType == 'login' then | |
| -- Login from new client | |
| local username = msg.msg | |
| if userID and username then | |
| users[userID] = { | |
| id = nSenderID; | |
| userID = userID; | |
| username = username; | |
| } | |
| nUsers = nUsers + 1 | |
| printUsers() | |
| send('join', { userID, username }) | |
| ping(userID) | |
| end | |
| else | |
| -- Something else from existing client | |
| if user and user.id == nSenderID then | |
| -- print(msg.msgType) | |
| if msg.msgType == 'logout' then | |
| send('leave', { user.userID, user.username, msg.msg }) | |
| users[userID] = nil | |
| nUsers = nUsers - 1 | |
| printUsers() | |
| elseif msg.msgType == 'chat' then | |
| local chat = msg.msg | |
| if chat then | |
| local sCommand = string.match(chat, '^/([a-z]+)') | |
| if sCommand then | |
| local fnCommand = tCommands[sCommand] | |
| if fnCommand then | |
| local sArgs = string.sub(chat, string.len(sCommand)+3) | |
| fnCommand(user, sArgs) | |
| else | |
| send('msg', { -1, '@', 'Unrecognised command: /'..sCommand }, user.userID) | |
| end | |
| else | |
| send('msg', { user.userID, user.username, chat }) | |
| end | |
| end | |
| elseif msg.msgType == 'pingts' then | |
| send('pongtc', nil, user.userID) | |
| elseif msg.msgType == 'pongts' then | |
| user.bPingPonged = true | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end) | |
| end) | |
| if not ok then | |
| printError(error) | |
| end | |
| -- Unhost server | |
| send('kick') | |
| rednet.unhost(protocol) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment