SHARE
TWEET

Untitled

a guest Aug 19th, 2019 92 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Skip to content
  2. Why GitHub?
  3. Enterprise
  4. Explore
  5. Marketplace
  6. Pricing
  7. Search
  8.  
  9. Sign in
  10. Sign up
  11. 9 20 2 alekso56/ComputercraftLua
  12.  Code  Issues 0  Pull requests 0  Projects 0  Security  Insights
  13. ComputercraftLua/rom/programs/rednet/chat
  14. @alekso56 alekso56 1.62
  15. 553b7e7 on 5 Apr 2014
  16. 436 lines (392 sloc)  14.1 KB
  17.    
  18.  
  19. local tArgs = { ... }
  20.  
  21. local function printUsage()
  22.     print( "Usages:" )
  23.     print( "chat host <hostname>" )
  24.     print( "chat join <hostname> <nickname>" )
  25. end
  26.  
  27. local sOpenedModem = nil
  28. local function openModem()
  29.     for n,sModem in ipairs( peripheral.getNames() ) do
  30.         if peripheral.getType( sModem ) == "modem" then
  31.             if not rednet.isOpen( sModem ) then
  32.                 rednet.open( sModem )
  33.                 sOpenedModem = sModem
  34.             end
  35.             return true
  36.         end
  37.     end
  38.     print( "No modems found." )
  39.     return false
  40. end
  41.  
  42. local function closeModem()
  43.     if sOpenedModem ~= nil then
  44.         rednet.close( sOpenedModem )
  45.         sOpenedModem = nil
  46.     end
  47. end
  48.  
  49. -- Colours
  50. local highlightColour, textColour
  51. if term.isColour() then
  52.     textColour = colours.white
  53.     highlightColour = colours.yellow
  54. else
  55.     textColour = colours.white
  56.     highlightColour = colours.white
  57. end
  58.  
  59. local sCommand = tArgs[1]
  60. if sCommand == "host" then
  61.     -- "chat host"
  62.     -- Get hostname
  63.     local sHostname = tArgs[2]
  64.     if sHostname == nil then
  65.         printUsage()
  66.         return
  67.     end
  68.  
  69.     -- Host server
  70.     if not openModem() then
  71.         return
  72.     end
  73.     rednet.host( "chat", sHostname )
  74.     print( "0 users connected." )
  75.  
  76.     local tUsers = {}
  77.     local nUsers = 0
  78.     function send( sText, nUserID )
  79.         if nUserID then
  80.             local tUser = tUsers[ nUserID ]
  81.             if tUser then
  82.                 rednet.send( tUser.nID, {
  83.                     sType = "text",
  84.                     nUserID = nUserID,
  85.                     sText = sText,
  86.                 }, "chat" )
  87.             end
  88.         else
  89.             for nUserID, tUser in pairs( tUsers ) do
  90.                 rednet.send( tUser.nID, {
  91.                     sType = "text",
  92.                     nUserID = nUserID,
  93.                     sText = sText,
  94.                 }, "chat" )
  95.             end
  96.         end
  97.     end
  98.  
  99.     -- Setup ping pong
  100.     local tPingPongTimer = {}
  101.     function ping( nUserID )
  102.         local tUser = tUsers[ nUserID ]
  103.         rednet.send( tUser.nID, {
  104.             sType = "ping to client",
  105.             nUserID = nUserID,
  106.         }, "chat" )
  107.  
  108.         local timer = os.startTimer( 15 )
  109.         tUser.bPingPonged = false
  110.         tPingPongTimer[ timer ] = nUserID
  111.     end
  112.  
  113.     function printUsers()
  114.         local x,y = term.getCursorPos()
  115.         term.setCursorPos( 1, y - 1 )
  116.         term.clearLine()
  117.         if nUsers == 1 then
  118.             print( nUsers .. " user connected." )
  119.         else
  120.             print( nUsers .. " users connected." )
  121.         end
  122.     end
  123.  
  124.     -- Handle messages
  125.     local ok, error = pcall( function()
  126.         parallel.waitForAny( function()
  127.             while true do
  128.                 local sEvent, timer = os.pullEvent( "timer" )
  129.                 local nUserID = tPingPongTimer[ timer ]
  130.                 if nUserID and tUsers[ nUserID ] then
  131.                     local tUser = tUsers[ nUserID ]
  132.                     if tUser then
  133.                         if not tUser.bPingPonged then
  134.                             send( "* "..tUser.sUsername.." has timed out" )
  135.                             tUsers[ nUserID ] = nil
  136.                             nUsers = nUsers - 1
  137.                             printUsers()
  138.                         else
  139.                             ping( nUserID )
  140.                         end
  141.                     end
  142.                 end
  143.             end
  144.         end,
  145.         function()
  146.             while true do
  147.                 local tCommands
  148.                 tCommands = {
  149.                     ["me"] = function( tUser, sContent )
  150.                         if string.len(sContent) > 0 then
  151.                             send( "* "..tUser.sUsername.." "..sContent )
  152.                         else
  153.                             send( "* Usage: /me [words]", tUser.nUserID )
  154.                         end
  155.                     end,
  156.                     ["nick"] = function( tUser, sContent )
  157.                         if string.len(sContent) > 0 then
  158.                             local sOldName = tUser.sUsername
  159.                             tUser.sUsername = sContent
  160.                             send( "* "..sOldName.." is now known as "..tUser.sUsername )
  161.                         else
  162.                             send( "* Usage: /nick [nickname]", tUser.nUserID )
  163.                         end
  164.                     end,
  165.                     ["users"] = function( tUser, sContent )
  166.                         send( "* Connected Users:", tUser.nUserID )
  167.                         local sUsers = "*"
  168.                         for nUserID, tUser in pairs( tUsers ) do
  169.                             sUsers = sUsers .. " " .. tUser.sUsername
  170.                         end
  171.                         send( sUsers, tUser.nUserID )
  172.                     end,
  173.                     ["help"] = function( tUser, sContent )
  174.                         send( "* Available commands:", tUser.nUserID )
  175.                         local sCommands = "*"
  176.                         for sCommand, fnCommand in pairs( tCommands ) do
  177.                             sCommands = sCommands .. " /" .. sCommand
  178.                         end
  179.                         send( sCommands.." /logout", tUser.nUserID )
  180.                     end,
  181.                 }
  182.  
  183.                 local nSenderID, tMessage = rednet.receive( "chat" )
  184.                 if type( tMessage ) == "table" then
  185.                     if tMessage.sType == "login" then
  186.                         -- Login from new client
  187.                         local nUserID = tMessage.nUserID
  188.                         local sUsername = tMessage.sUsername
  189.                         if nUserID and sUsername then
  190.                             tUsers[ nUserID ] = {
  191.                                 nID = nSenderID,
  192.                                 nUserID = nUserID,
  193.                                 sUsername = sUsername,
  194.                             }
  195.                             nUsers = nUsers + 1
  196.                             printUsers()
  197.                             send( "* "..sUsername.." has joined the chat" )
  198.                             ping( nUserID )
  199.                         end
  200.  
  201.                     else
  202.                         -- Something else from existing client
  203.                         local nUserID = tMessage.nUserID
  204.                         local tUser = tUsers[ nUserID ]
  205.                         if tUser and tUser.nID == nSenderID then
  206.                             if tMessage.sType == "logout" then
  207.                                 send( "* "..tUser.sUsername.." has left the chat" )
  208.                                 tUsers[ nUserID ] = nil
  209.                                 nUsers = nUsers - 1
  210.                                 printUsers()
  211.  
  212.                             elseif tMessage.sType == "chat" then
  213.                                 local sMessage = tMessage.sText
  214.                                 if sMessage then
  215.                                     local sCommand = string.match( sMessage, "^/([a-z]+)" )
  216.                                     if sCommand then
  217.                                         local fnCommand = tCommands[ sCommand ]
  218.                                         if fnCommand then
  219.                                             local sContent = string.sub( sMessage, string.len(sCommand)+3 )
  220.                                             fnCommand( tUser, sContent )
  221.                                         else
  222.                                             send( "* Unrecognised command: /"..sCommand, tUser.nUserID )
  223.                                         end
  224.                                     else
  225.                                         send( "<"..tUser.sUsername.."> "..tMessage.sText )
  226.                                     end
  227.                                 end
  228.  
  229.                             elseif tMessage.sType == "ping to server" then
  230.                                 rednet.send( tUser.nID, {
  231.                                     sType = "pong to client",
  232.                                     nUserID = nUserID,
  233.                                 }, "chat" )
  234.  
  235.                             elseif tMessage.sType == "pong to server" then
  236.                                 tUser.bPingPonged = true
  237.  
  238.                             end
  239.                         end
  240.                     end
  241.                  end
  242.             end
  243.         end )
  244.     end )
  245.     if not ok then
  246.         printError( error )
  247.     end
  248.  
  249.     -- Unhost server
  250.     for nUserID, tUser in pairs( tUsers ) do
  251.         rednet.send( tUser.nID, {
  252.             sType = "kick",
  253.             nUserID = nUserID,
  254.         }, "chat" )
  255.     end
  256.     rednet.unhost( "chat" )
  257.     closeModem()
  258.  
  259. elseif sCommand == "join" then
  260.     -- "chat join"
  261.     -- Get hostname and username
  262.     local sHostname = tArgs[2]
  263.     local sUsername = tArgs[3]
  264.     if sHostname == nil or sUsername == nil then
  265.         printUsage()
  266.         return
  267.     end
  268.  
  269.     -- Connect
  270.     if not openModem() then
  271.         return
  272.     end
  273.     write( "Looking up " .. sHostname .. "... " )
  274.     local nHostID = rednet.lookup( "chat", sHostname )
  275.     if nHostID == nil then
  276.         print( "Failed." )
  277.         return
  278.     else
  279.         print( "Success." )
  280.     end
  281.  
  282.     -- Login
  283.     local nUserID = math.random( 1, 2147483647 )
  284.     rednet.send( nHostID, {
  285.         sType = "login",
  286.         nUserID = nUserID,
  287.         sUsername = sUsername,
  288.     }, "chat" )
  289.  
  290.     -- Setup ping pong
  291.     local bPingPonged = true
  292.     local pingPongTimer = os.startTimer( 0 )
  293.  
  294.     function ping()
  295.         rednet.send( nHostID, {
  296.             sType = "ping to server",
  297.             nUserID = nUserID,
  298.         }, "chat" )
  299.         bPingPonged = false
  300.         pingPongTimer = os.startTimer( 15 )
  301.     end
  302.  
  303.     -- Handle messages
  304.     local w,h = term.getSize()
  305.     local parentTerm = term.current()
  306.     local titleWindow = window.create( parentTerm, 1, 1, w, 1, true )
  307.     local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true )
  308.     local promptWindow = window.create( parentTerm, 1, h, w, 1, true )
  309.     historyWindow.setCursorPos( 1, h-2 )
  310.  
  311.     term.clear()
  312.     term.setTextColour( textColour )
  313.     term.redirect( promptWindow )
  314.     promptWindow.restoreCursor()
  315.  
  316.     function drawTitle()
  317.         local x,y = titleWindow.getCursorPos()
  318.         local w,h = titleWindow.getSize()
  319.         local sTitle = sUsername.." on "..sHostname
  320.         titleWindow.setTextColour( highlightColour )
  321.         titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 )
  322.         titleWindow.clearLine()
  323.         titleWindow.write( sTitle )
  324.         promptWindow.restoreCursor()
  325.     end
  326.  
  327.     function printMessage( sMessage )
  328.         term.redirect( historyWindow )
  329.         print()
  330.         if string.match( sMessage, "^\*" ) then
  331.             -- Information
  332.             term.setTextColour( highlightColour )
  333.             write( sMessage )
  334.             term.setTextColour( textColour )
  335.         else
  336.             -- Chat
  337.             local sUsernameBit = string.match( sMessage, "^\<[^\>]*\>" )
  338.             if sUsernameBit then
  339.                 term.setTextColour( highlightColour )
  340.                 write( sUsernameBit )
  341.                 term.setTextColour( textColour )
  342.                 write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) )
  343.             else
  344.                 write( sMessage )
  345.             end
  346.         end
  347.         term.redirect( promptWindow )
  348.         promptWindow.restoreCursor()
  349.     end
  350.  
  351.     drawTitle()
  352.  
  353.     local ok, error = pcall( function()
  354.         parallel.waitForAny( function()
  355.             while true do
  356.                 local sEvent, timer = os.pullEvent()
  357.                 if sEvent == "timer" then
  358.                     if timer == pingPongTimer then
  359.                         if not bPingPonged then
  360.                             printMessage( "Server timeout." )
  361.                             return
  362.                         else
  363.                             ping()
  364.                         end
  365.                     end
  366.  
  367.                 elseif sEvent == "term_resize" then
  368.                     local w,h = parentTerm.getSize()
  369.                     titleWindow.reposition( 1, 1, w, 1 )
  370.                     historyWindow.reposition( 1, 2, w, h-2 )
  371.                     promptWindow.reposition( 1, h, w, 1 )
  372.  
  373.                 end
  374.             end
  375.         end,
  376.         function()
  377.             while true do
  378.                 local nSenderID, tMessage = rednet.receive( "chat" )
  379.                 if nSenderID == nHostID and type( tMessage ) == "table" and tMessage.nUserID == nUserID then
  380.                     if tMessage.sType == "text" then
  381.                         local sText = tMessage.sText
  382.                         if sText then
  383.                             printMessage( sText )
  384.                         end
  385.  
  386.                     elseif tMessage.sType == "ping to client" then
  387.                         rednet.send( nSenderID, {
  388.                             sType = "pong to server",
  389.                             nUserID = nUserID,
  390.                         }, "chat" )
  391.  
  392.                     elseif tMessage.sType == "pong to client" then
  393.                         bPingPonged = true
  394.  
  395.                     elseif tMessage.sType == "kick" then
  396.                         return
  397.  
  398.                     end
  399.                 end
  400.             end
  401.         end,
  402.         function()
  403.             local tSendHistory = {}
  404.             while true do
  405.                 promptWindow.setCursorPos( 1,1 )
  406.                 promptWindow.clearLine()
  407.                 promptWindow.setTextColor( highlightColour )
  408.                 promptWindow.write( ": ")
  409.                 promptWindow.setTextColor( textColour )
  410.  
  411.                 local sChat = read( nil, tSendHistory )
  412.                 if string.match( sChat, "^/logout" ) then
  413.                     break
  414.                 else
  415.                     rednet.send( nHostID, {
  416.                         sType = "chat",
  417.                         nUserID = nUserID,
  418.                         sText = sChat,
  419.                     }, "chat" )
  420.                     table.insert( tSendHistory, sChat )
  421.                 end
  422.             end
  423.         end )
  424.     end )
  425.  
  426.     -- Close the windows
  427.     term.redirect( parentTerm )
  428.  
  429.     -- Print error notice
  430.     local w,h = term.getSize()
  431.     term.setCursorPos( 1, h )
  432.     term.clearLine()
  433.     term.setCursorBlink( false )
  434.     if not ok then
  435.         printError( error )
  436.     end
  437.  
  438.     -- Logout
  439.     rednet.send( nHostID, {
  440.         sType = "logout",
  441.         nUserID = nUserID,
  442.     }, "chat" )
  443.     closeModem()
  444.  
  445.     -- Print disconnection notice
  446.     print( "Disconnected." )
  447.  
  448. else
  449.     -- "chat somethingelse"
  450.     printUsage()
  451.  
  452. end
  453. © 2019 GitHub, Inc.
  454. Terms
  455. Privacy
  456. Security
  457. Status
  458. Help
  459. Contact GitHub
  460. Pricing
  461. API
  462. Training
  463. Blog
  464. About
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top