Paste: FactorBot - IRC Bot

Author: dom96
Mode: factor
Date: Sun, 27 Dec 2009 21:18:55
Plain Text |
! Copyright (C) 2009 dom96.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel io.sockets io splitting sequences namespaces combinators
io.encodings.utf8 math generalizations eval arrays continuations debugger
io.streams.string ;
IN: irc-bot

: global-print ( msg -- )
    global [ print flush ] bind ;

: privmsg (  splitmsg sendmsg -- )
    "PRIVMSG " swap 2 swap nth " :" 3append swap
    ! By this point we basically have
    ! PRIVMSG #chan :
    append ! Appends the message
    "\r\n" append write flush ;

: execute-string ( string -- output )
    [
        [ 1array [ parse-string call ] with-datastack drop ]
        [ nip print-error ] recover
    ] with-string-writer ;

: handle-line ( line -- ) 
    dup " " split
    swap dup global-print
    
    
    { 
        #! PING
        { [ "PING" ?head ] [ "PONG" prepend "\r\n" append dup write flush global-print drop ] }
        
        #! 001
        { [ over 1 swap nth "001" = ] [ "001 received, joining channel." global-print "JOIN #Factor\r\n" write flush drop drop ] }
        
        #! PRIVMSG
        { 
          [   
              swap
              ! Make sure this message has at least 4 commands
              dup length 4 >=
              [
                  1 over nth
                  "PRIVMSG" = ! This will return t
              ]
              [ f ]
              if
          ]
          [
              
              ! Add commands here
              3 over nth {
                  { ":|about"
                      [ dup "FactorBot 0.1 | This took me"
                      " about 2 days to figure out | Thanks to the helpful"
                      " community at #concatenative\r\n" 3append swap privmsg  ]
                  }
                  { ":|quit"
                      [
                          0 over nth
                          "!" split
                          0 swap nth
                          ":dom96" =
                          [ 0 over remove-nth 3 [ 0 over remove-nth swap drop ] times " " join "QUIT :" "\r\n" surround write flush ]
                          [ dup "Your not allowed to use this command" swap privmsg ]
                          if
                      ]
                  }
                  { ":|say"
                      [
                          ! This line removes the first 4 items from the split msg
                          dup 0 over remove-nth 3 [ 0 over remove-nth swap drop ] times " " join swap 
                          privmsg
                      ]
                  }
                  { ":|eval"
                      [
                          ! This line removes the first 4 items from the split msg
                          dup 0 over remove-nth 3 [ 0 over remove-nth swap drop ] times " " join
                          execute-string
                          "\n" split
                          [ swap dup 2over drop swap privmsg swap drop ] each
                          drop
                      ]
                  }
                  
                  ! Unknown command
                  [ 
                      ":|" head? 
                      [ dup "Unknown command" swap privmsg ]
                      [ ] 
                      if
                  ]
                  
              } case 
              
          
              drop drop ! Drop the split message and the message(Since we don't use it)
          ] 
        }
        
        [ drop drop ]
    } cond ;
    
: readlns ( -- ) 
    readln [ handle-line readlns ] when* ;

: startbot ( -- )
    "irc.freenode.net" 6667 <inet> utf8 
    [ 
        "NICK FactorBot\r\n" write
        "USER FactorBot FactorBot irc.freenode.net :Someone\r\n" write
        flush
        readlns 
    ]
    with-client ;

MAIN: startbot

Annotation: possible design for irc library

Author: erg
Mode: factor
Date: Mon, 28 Dec 2009 16:39:24
Plain Text |
SYMBOL: current-irc-client

! Built-in bot type in library
TUPLE: irc-client ;
TUPLE: log-bot < irc-client ;

! Parse messages into tuples with the raw string and a timestamp in each one
TUPLE: irc-message raw timestamp ;
TUPLE: ping < irc-message sender ;
TUPLE: privmsg < irc-message sender receiver string ;

! Hooks that the bot implementor can override for each kind of irc message
HOOK: raw current-irc-client ( irc-message -- )
HOOK: ping current-irc-client ( ping -- )
HOOK: privmsg current-irc-client ( privmsg -- )

! Default handler for ping, you won't have to override this unless you need special behavior
M: irc-client ping
    sender>> "PONG " prepend send-irc ;

! Log pings for some reason
M: log-bot ping
    [ timestamp>> timestamp>rfc822 "Ping received at " prepend log-it ]
    [ handle-next-method ] bi ;

M: log-bot privmsg
    ... ;

New Annotation

Summary:
Author:
Mode:
Body: