Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Skip to content
- Why GitHub?
- Enterprise
- Explore
- Marketplace
- Pricing
- Search
- Sign in
- Sign up
- 9 20 2 alekso56/ComputercraftLua
- Code Issues 0 Pull requests 0 Projects 0 Security Insights
- ComputercraftLua/rom/programs/rednet/chat
- @alekso56 alekso56 1.62
- 553b7e7 on 5 Apr 2014
- 436 lines (392 sloc) 14.1 KB
- local tArgs = { ... }
- local function printUsage()
- print( "Usages:" )
- print( "chat host <hostname>" )
- print( "chat join <hostname> <nickname>" )
- end
- local sOpenedModem = nil
- local function openModem()
- for n,sModem in ipairs( peripheral.getNames() ) do
- if peripheral.getType( sModem ) == "modem" then
- if not rednet.isOpen( sModem ) then
- rednet.open( sModem )
- sOpenedModem = sModem
- end
- return true
- end
- end
- print( "No modems found." )
- return false
- end
- local function closeModem()
- if sOpenedModem ~= nil then
- rednet.close( sOpenedModem )
- sOpenedModem = nil
- end
- end
- -- Colours
- local highlightColour, textColour
- if term.isColour() then
- textColour = colours.white
- highlightColour = colours.yellow
- else
- textColour = colours.white
- highlightColour = colours.white
- end
- local sCommand = tArgs[1]
- if sCommand == "host" then
- -- "chat host"
- -- Get hostname
- local sHostname = tArgs[2]
- if sHostname == nil then
- printUsage()
- return
- end
- -- Host server
- if not openModem() then
- return
- end
- rednet.host( "chat", sHostname )
- print( "0 users connected." )
- local tUsers = {}
- local nUsers = 0
- function send( sText, nUserID )
- if nUserID then
- local tUser = tUsers[ nUserID ]
- if tUser then
- rednet.send( tUser.nID, {
- sType = "text",
- nUserID = nUserID,
- sText = sText,
- }, "chat" )
- end
- else
- for nUserID, tUser in pairs( tUsers ) do
- rednet.send( tUser.nID, {
- sType = "text",
- nUserID = nUserID,
- sText = sText,
- }, "chat" )
- end
- end
- end
- -- Setup ping pong
- local tPingPongTimer = {}
- function ping( nUserID )
- local tUser = tUsers[ nUserID ]
- rednet.send( tUser.nID, {
- sType = "ping to client",
- nUserID = nUserID,
- }, "chat" )
- local timer = os.startTimer( 15 )
- tUser.bPingPonged = false
- tPingPongTimer[ timer ] = nUserID
- 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 nUserID = tPingPongTimer[ timer ]
- if nUserID and tUsers[ nUserID ] then
- local tUser = tUsers[ nUserID ]
- if tUser then
- if not tUser.bPingPonged then
- send( "* "..tUser.sUsername.." has timed out" )
- tUsers[ nUserID ] = nil
- nUsers = nUsers - 1
- printUsers()
- else
- ping( nUserID )
- end
- end
- end
- end
- end,
- function()
- while true do
- local tCommands
- tCommands = {
- ["me"] = function( tUser, sContent )
- if string.len(sContent) > 0 then
- send( "* "..tUser.sUsername.." "..sContent )
- else
- send( "* Usage: /me [words]", tUser.nUserID )
- end
- end,
- ["nick"] = function( tUser, sContent )
- if string.len(sContent) > 0 then
- local sOldName = tUser.sUsername
- tUser.sUsername = sContent
- send( "* "..sOldName.." is now known as "..tUser.sUsername )
- else
- send( "* Usage: /nick [nickname]", tUser.nUserID )
- end
- end,
- ["users"] = function( tUser, sContent )
- send( "* Connected Users:", tUser.nUserID )
- local sUsers = "*"
- for nUserID, tUser in pairs( tUsers ) do
- sUsers = sUsers .. " " .. tUser.sUsername
- end
- send( sUsers, tUser.nUserID )
- end,
- ["help"] = function( tUser, sContent )
- send( "* Available commands:", tUser.nUserID )
- local sCommands = "*"
- for sCommand, fnCommand in pairs( tCommands ) do
- sCommands = sCommands .. " /" .. sCommand
- end
- send( sCommands.." /logout", tUser.nUserID )
- end,
- }
- local nSenderID, tMessage = rednet.receive( "chat" )
- if type( tMessage ) == "table" then
- if tMessage.sType == "login" then
- -- Login from new client
- local nUserID = tMessage.nUserID
- local sUsername = tMessage.sUsername
- if nUserID and sUsername then
- tUsers[ nUserID ] = {
- nID = nSenderID,
- nUserID = nUserID,
- sUsername = sUsername,
- }
- nUsers = nUsers + 1
- printUsers()
- send( "* "..sUsername.." has joined the chat" )
- ping( nUserID )
- end
- else
- -- Something else from existing client
- local nUserID = tMessage.nUserID
- local tUser = tUsers[ nUserID ]
- if tUser and tUser.nID == nSenderID then
- if tMessage.sType == "logout" then
- send( "* "..tUser.sUsername.." has left the chat" )
- tUsers[ nUserID ] = nil
- nUsers = nUsers - 1
- printUsers()
- elseif tMessage.sType == "chat" then
- local sMessage = tMessage.sText
- if sMessage then
- local sCommand = string.match( sMessage, "^/([a-z]+)" )
- if sCommand then
- local fnCommand = tCommands[ sCommand ]
- if fnCommand then
- local sContent = string.sub( sMessage, string.len(sCommand)+3 )
- fnCommand( tUser, sContent )
- else
- send( "* Unrecognised command: /"..sCommand, tUser.nUserID )
- end
- else
- send( "<"..tUser.sUsername.."> "..tMessage.sText )
- end
- end
- elseif tMessage.sType == "ping to server" then
- rednet.send( tUser.nID, {
- sType = "pong to client",
- nUserID = nUserID,
- }, "chat" )
- elseif tMessage.sType == "pong to server" then
- tUser.bPingPonged = true
- end
- end
- end
- end
- end
- end )
- end )
- if not ok then
- printError( error )
- end
- -- Unhost server
- for nUserID, tUser in pairs( tUsers ) do
- rednet.send( tUser.nID, {
- sType = "kick",
- nUserID = nUserID,
- }, "chat" )
- end
- rednet.unhost( "chat" )
- closeModem()
- elseif sCommand == "join" then
- -- "chat join"
- -- Get hostname and username
- local sHostname = tArgs[2]
- local sUsername = tArgs[3]
- if sHostname == nil or sUsername == nil then
- printUsage()
- return
- end
- -- Connect
- if not openModem() then
- return
- end
- write( "Looking up " .. sHostname .. "... " )
- local nHostID = rednet.lookup( "chat", sHostname )
- if nHostID == nil then
- print( "Failed." )
- return
- else
- print( "Success." )
- end
- -- Login
- local nUserID = math.random( 1, 2147483647 )
- rednet.send( nHostID, {
- sType = "login",
- nUserID = nUserID,
- sUsername = sUsername,
- }, "chat" )
- -- Setup ping pong
- local bPingPonged = true
- local pingPongTimer = os.startTimer( 0 )
- function ping()
- rednet.send( nHostID, {
- sType = "ping to server",
- nUserID = nUserID,
- }, "chat" )
- bPingPonged = false
- pingPongTimer = os.startTimer( 15 )
- end
- -- Handle messages
- local w,h = term.getSize()
- local parentTerm = term.current()
- local titleWindow = window.create( parentTerm, 1, 1, w, 1, true )
- local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true )
- local promptWindow = window.create( parentTerm, 1, h, w, 1, true )
- historyWindow.setCursorPos( 1, h-2 )
- term.clear()
- term.setTextColour( textColour )
- term.redirect( promptWindow )
- promptWindow.restoreCursor()
- function drawTitle()
- local x,y = titleWindow.getCursorPos()
- local w,h = titleWindow.getSize()
- local sTitle = sUsername.." on "..sHostname
- titleWindow.setTextColour( highlightColour )
- titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 )
- titleWindow.clearLine()
- titleWindow.write( sTitle )
- promptWindow.restoreCursor()
- end
- function printMessage( sMessage )
- term.redirect( historyWindow )
- print()
- if string.match( sMessage, "^\*" ) then
- -- Information
- term.setTextColour( highlightColour )
- write( sMessage )
- term.setTextColour( textColour )
- else
- -- Chat
- local sUsernameBit = string.match( sMessage, "^\<[^\>]*\>" )
- if sUsernameBit then
- term.setTextColour( highlightColour )
- write( sUsernameBit )
- term.setTextColour( textColour )
- write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) )
- else
- write( sMessage )
- end
- end
- term.redirect( promptWindow )
- promptWindow.restoreCursor()
- end
- drawTitle()
- local ok, error = pcall( function()
- parallel.waitForAny( function()
- while true do
- local sEvent, timer = os.pullEvent()
- if sEvent == "timer" then
- if timer == pingPongTimer then
- if not bPingPonged then
- printMessage( "Server timeout." )
- return
- else
- ping()
- end
- end
- elseif sEvent == "term_resize" then
- local w,h = parentTerm.getSize()
- titleWindow.reposition( 1, 1, w, 1 )
- historyWindow.reposition( 1, 2, w, h-2 )
- promptWindow.reposition( 1, h, w, 1 )
- end
- end
- end,
- function()
- while true do
- local nSenderID, tMessage = rednet.receive( "chat" )
- if nSenderID == nHostID and type( tMessage ) == "table" and tMessage.nUserID == nUserID then
- if tMessage.sType == "text" then
- local sText = tMessage.sText
- if sText then
- printMessage( sText )
- end
- elseif tMessage.sType == "ping to client" then
- rednet.send( nSenderID, {
- sType = "pong to server",
- nUserID = nUserID,
- }, "chat" )
- elseif tMessage.sType == "pong to client" then
- bPingPonged = true
- elseif tMessage.sType == "kick" then
- return
- end
- end
- end
- end,
- function()
- local tSendHistory = {}
- while true do
- promptWindow.setCursorPos( 1,1 )
- promptWindow.clearLine()
- promptWindow.setTextColor( highlightColour )
- promptWindow.write( ": ")
- promptWindow.setTextColor( textColour )
- local sChat = read( nil, tSendHistory )
- if string.match( sChat, "^/logout" ) then
- break
- else
- rednet.send( nHostID, {
- sType = "chat",
- nUserID = nUserID,
- sText = sChat,
- }, "chat" )
- table.insert( tSendHistory, sChat )
- end
- end
- end )
- end )
- -- Close the windows
- term.redirect( parentTerm )
- -- Print error notice
- local w,h = term.getSize()
- term.setCursorPos( 1, h )
- term.clearLine()
- term.setCursorBlink( false )
- if not ok then
- printError( error )
- end
- -- Logout
- rednet.send( nHostID, {
- sType = "logout",
- nUserID = nUserID,
- }, "chat" )
- closeModem()
- -- Print disconnection notice
- print( "Disconnected." )
- else
- -- "chat somethingelse"
- printUsage()
- end
- © 2019 GitHub, Inc.
- Terms
- Privacy
- Security
- Status
- Help
- Contact GitHub
- Pricing
- API
- Training
- Blog
- About
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement