示例#1
0
def duckboot():
#{{{
    # Get bot token from the env file
    with open("../.env") as env_file:
        bot_token = env_file.readline().rstrip().split("=")[1]
    util.logger.log(DiagMessage("INI0010I", bot_token))

    # Create the slack client
    util.sc = SlackClient(bot_token)
    util.logger.log(DiagMessage("INI0020I"))

    # Get bot info
    bot_str, bot_channels = util.getBotInfo(bot_token)
    bot_id = util.matchUserId(bot_str)
    if not bot_id:
        util.logger.log(DiagMessage("INI0030E",bot_str))
        return util.EXIT_CODES["INVALID_BOT_ID"], None
    util.logger.log(DiagMessage("INI0030I",bot_id))

    # Connect to rtm and create bot if successful
    return_code = connect()
    if return_code:
        return return_code, None
    else:
        return return_code, Duckbot(bot_id, bot_channels)
示例#2
0
def connect():
#{{{
    # Connect to the rtm
    if util.sc.rtm_connect(with_team_state=False):
    #{{{
        event_list = []
        # Wait for the connection event
        while not event_list:
            event_list = util.sc.rtm_read()
        event = event_list.pop(0)
        if event["type"] == "hello":
            # Connection was good
            util.logger.log(DiagMessage("INI0040I"))
            return 0
        else:
            # Error in connection
            error = event["error"]
            util.logger.log(DiagMessage("INI0040E",error["msg"]))
            util.logger.log(DiagMessage("INI0041E",str(error["code"])))
            return util.EXIT_CODES["RTM_BAD_CONNECTION"]
    #}}}
    # RTM connect failed
    else:
        util.logger.log(DiagMessage("INI0042E"))
        return util.EXIT_CODES["RTM_CONNECT_FAILED"]
示例#3
0
def run(duckbot):
#{{{
    if util.debug:
        util.logger.log(DiagMessage("INI0050D"))
    else:
        util.logger.log(DiagMessage("INI0050I"))

    running = True
    return_code = 0
    # Keep going until bot signals to stop
    while running:
    # {{{
        # Pause between reads to reduce the cycles spent spinning
        # Delay may need to be adjusted if bot feels sluggish to respond
        time.sleep(util.RTM_READ_DELAY)

        return_code, event_list = doRead()
        if event_list and not return_code:
            # Process all the events returned
            for event in event_list:
                return_code = duckbot.handleEvent(event)
        # Tick bot internal counter
        duckbot.tick()
        if return_code:
            running = False
    # }}}
    # Bot signalled to stop, return to mainline
    return return_code
示例#4
0
def doRead():
#{{{
    # Attempt to do rtm read, except errors
    # When new errors are experienced, they will be added specifically
    try:
        event_list = util.sc.rtm_read()
        return 0, event_list
    except TimeoutError:
        util.logger.log(DiagMessage("BOT0031E"))
        return util.EXIT_CODES["RTM_TIMEOUT_ERROR"], None
    except Exception as err:
        print("Error: RTM read failed")
        print(err,file=sys.stderr)
        util.logger.log(DiagMessage("BOT0030E"))
        return util.EXIT_CODES["RTM_GENERIC_ERROR"], None
示例#5
0
 def __init__(self, fn = DEFAULT_FN, log = True):
 #{{{
     self.keep_log = log
     self.fn = fn
     self.log_buffer = []
     if self.keep_log:
         self.log(DiagMessage("LOG0000I"))
示例#6
0
 def tick(self):
     #{{{
     # Tick function is called roughly every second, so the tick count rolls
     # over about every hour. Roll over point can be changed if time needs to
     # be tracked longer than an hour at a time.
     self.ticks = (self.ticks + 1) % self.TICK_ROLLOVER
     # Flush the buffer every hour or so if there aren't enough messages
     if self.ticks % util.LOG_TIME == 0:
         self.logger.log(DiagMessage("LOG0010I"), flush=True)
     # Save bank data timer
     if util.bank_file and self.ticks % util.SAVE_STATE_TIME == 0:
         self.gamble_handler.saveState()
     # Tick down the global cooldown
     if self.cooldown_g:
         self.cooldown_g -= 1
     # Regen some bux for the poor people
     if self.ticks % util.REGEN_TIME == 0:
         self.gamble_handler.regenBux()
     # Refresh the free pulls
     if self.gamble_handler.pull_timer:
         self.gamble_handler.pull_timer -= 1
     else:
         self.gamble_handler.refreshPulls()
     # Wonderful day wish
     if self.wish_timer:
         self.wish_timer -= 1
     else:
         util.sendMessage(self.WISH_CHANNEL, "Go, have a wonderful day.")
         self._getWishTime()
示例#7
0
def main():
#{{{
    initProgram()
    return_code, duckbot = duckboot()
    if not return_code:
        return_code = run(duckbot)
    util.logger.log(DiagMessage("LOG0011I"), flush=True)
    return return_code
示例#8
0
    def handleEvent(self, event_p):
        #{{{
        #         print(event_p)
        # Create standardized event
        event = Event(event_p)

        # No event type, get out
        if event.type == None:
            return 0

        # Message event, pass to message handler
        elif event.type == "message":
            #{{{
            # Display user and their message
            if event.text:
                self.logger.log(DiagMessage("BOT0010U", event.user,
                                            event.text))
            response = self.msg_handler.act(event)

            # Send message if one was returned
            if response:
                util.sendMessage(event.channel, response, event.user)
                return 0
            # None response signals an update needed
            elif response == None:
                util.sendMessage(event.channel,
                                 "Shutting down for update. Kweh! :duckbot:")
                return 2
            # Otherwise do nothing
            else:
                return 0
        #}}}

        # Bot message event
        elif event.type == "bot_message":
            #{{{
            self.bot_handler.checkBotId(event.user)
            # Do something sassy with the bot
            if not self.cooldown_g:
                self.cooldown_g = 120
                self.bot_handler.act(event)
            return 0
        #}}}

        # Update event, respond based on the event subtype
        elif event.type == "update":
            #{{{
            # channel_purpose and channel_joined require channel list update
            if (event.subtype == "channel_purpose"
                    or event.subtype == "channel_joined"):
                self._channelListUpdate(event)
            return 0
        #}}}

        # Unhandled event type
        else:
            # Don't do anything right now
            return 0
示例#9
0
    def __init__(self, bot_id, bot_channels):
        #{{{
        # Param fields
        self.id = bot_id
        self.channels = bot_channels

        self.debug = util.debug
        self.logger = util.logger
        self.ticks = 0
        self.cooldown_g = 0

        self._getWishTime()

        self.logger.log(DiagMessage("BOT0000I"))
        # Create command handlers
        self.roll_handler = RollHandler()
        util.logger.log(DiagMessage("BOT0001D",
                                    "Roll")) if util.debug else None
        self.help_handler = HelpHandler(bot_id)
        util.logger.log(DiagMessage("BOT0001D",
                                    "Help")) if util.debug else None
        self.gamble_handler = GambleHandler(bot_channels)
        util.logger.log(DiagMessage("BOT0001D",
                                    "Gamble")) if util.debug else None
        # Create event handlers
        self.msg_handler = MessageHandler(bot_id,
                                          gamble_handler=self.gamble_handler,
                                          help_handler=self.help_handler,
                                          roll_handler=self.roll_handler)
        self.logger.log(DiagMessage("BOT0001D",
                                    "Message")) if self.debug else None
        self.bot_handler = BotHandler()
        self.logger.log(DiagMessage("BOT0001D", "Bot")) if self.debug else None
        self.logger.log(DiagMessage("BOT0002I"))
示例#10
0
def initProgram():
#{{{
    # Change context directory to the running one
    os.chdir(os.path.dirname(os.path.realpath(__file__)))

    # Construct command line parser and get arguements
    cl_parser = argparse.ArgumentParser(description='Start up Duckbot')
    cl_parser.add_argument('--debug', action='store_true')
    cl_parser.add_argument('--nolog', dest='log', action='store_false', default=True)
    cl_parser.add_argument('--nobnk', dest='bnk', action='store_false', default=True)
    args = cl_parser.parse_args()
    util.debug = args.debug
    util.bank_file = args.bnk

    # Start the logger with logging mode
    util.logger = Logger(log=args.log)
    util.logger.log(DiagMessage("INI0000I"))
示例#11
0
    def act(self, event):
        #{{{
        u_parms = ""
        # Split text into command word and params
        command, o_parms = self._getCommand(event.text)
        # Save old params for nicer messages if needed
        if o_parms:
            u_parms = [str.upper(val) for val in o_parms]

        # Log command being processed
        if util.debug and command:
            util.logger.log(
                DiagMessage("BOT0020D", util.COMMANDS.inverse[command][0]))

        # HI command
        if command == util.COMMANDS["HI"]:
            return self.DEFAULT_RESPONSE

        # UPDATE command
        elif command == util.COMMANDS["UPDATE"]:
            return None

        # HELP command
        elif command == util.COMMANDS["HELP"]:
            return self.help_handler.act(u_parms)

        # ROLL command
        elif command == util.COMMANDS["ROLL"]:
            #{{{
            return_code, rolls = self.roll_handler.roll(u_parms)
            # Regular dice roll
            if return_code == 0:
                #{{{
                # Grab what will be added to the end of the message
                tail = rolls.pop()
                output = "You rolled: "
                # Join all the values if there's more than one
                if len(rolls) > 1:
                    output += ", ".join(map(
                        str, rolls)) + "\nYour total: " + str(tail)
                # Otherwise grab the one and slap the tail on
                else:
                    output += str(rolls[0]) + " " + tail
                return output
            # }}}
            # Character roll
            elif return_code == 1:
                #{{{
                output = ""
                stats = []
                # Go through each set of rolls, drop the lowest and total
                for group in rolls:
                    output += "\n\nYou rolled: " + ", ".join(map(str, group))
                    output += "\nDropping " + str(min(group)) + ", "
                    group.remove(min(group))
                    stat = sum(group)
                    stats.append(stat)
                    output += "Total: " + str(stat)
                output += "\n\nYour stats are: " + ", ".join(map(str, stats))
                return output
            #}}}
            elif return_code == -1:
                return o_parms[0] + " is not a valid roll."
            else:
                return "Can't roll without parameters, kweh! :duck:"
        #}}}

        # COIN command
        elif command == util.COMMANDS["COIN"]:
            return "You got: " + self.roll_handler.coinRoll()

        # 8BALL command
        elif command == util.COMMANDS["EIGHTBALL"]:
            return self.roll_handler.eightballRoll()

        # FACTOID command
        elif command == util.COMMANDS["FACTOID"]:
            return self.roll_handler.factoidRoll()

        # PICKIT command
        elif command == util.COMMANDS["PICKIT"]:
            #{{{
            return_code, response = self.roll_handler.pickitRoll(o_parms)
            # Number of choices out of range
            if return_code == 1:
                return ("Must pick between " + str(min(response)) + " "
                        "and " + str(max(response)) + " things")
            # Parsing error
            elif return_code == 2:
                return "Unmatched quotes! Kweh :duck:"
            else:
                return "I choose: " + response
        #}}}

        # JOIN command
        elif command == util.COMMANDS["JOIN"]:
            return self.gamble_handler.join(event.user, event.channel)

        # CHECKBUX command
        elif command == util.COMMANDS["CHECKBUX"]:
            target = u_parms[0] if u_parms else None
            return self.gamble_handler.checkbux(event.user, target)

        # BET command
        elif command == util.COMMANDS["BET"]:
            return self.gamble_handler.bet(event.user, event.channel, o_parms)

        # PULL command
        elif command == util.COMMANDS["PULL"]:
            amount = u_parms[0] if u_parms else None
            return self.gamble_handler.pull(event.user, event.channel, amount)

        # CHECKPOOL command
        elif command == util.COMMANDS["CHECKPOOL"]:
            target = u_parms[0] if u_parms else None
            return self.gamble_handler.checkPool(event.user, target)

        # No command or unrecognized, either way I don't care
        else:
            return ""