Ejemplo n.º 1
0
def getRatingChanges(contestId):
    with cfPredictorLock:
        if time.time() > cfPredictorLastRequest[contestId] + 20:
            logger.debug('request rating changes from cf-predictor')
            cfPredictorLastRequest[contestId] = time.time()
            try:
                startT = time.time()
                r = requests.get(cfPredictorUrl + str(contestId), timeout=10)
                perfLogger.info(
                    "cf predictor request {:.3f}s".format(time.time() -
                                                          startT))
            except requests.exceptions.Timeout as errt:
                logger.error("Timeout on CF-predictor.")
                return handleToRatingChanges[contestId]
            except Exception as e:
                logger.critical(
                    'Failed to request cf-predictor: \nexception: %s\n',
                    e,
                    exc_info=True)
                return handleToRatingChanges[contestId]
            if r.status_code != requests.codes.ok:
                logger.error("CF-Predictor request failed with code " +
                             str(r.status_code) + ", " + str(r.reason))
                return handleToRatingChanges[contestId]
            logger.debug('rating changes received')
            r = r.json()
            if r['status'] != 'OK':
                return handleToRatingChanges[contestId]
            r = r['result']
            handleToRatingChanges[contestId] = {}
            for row in r:
                handleToRatingChanges[contestId][row['handle']] = (
                    row['oldRating'], row['newRating'])
            cfPredictorLastRequest[contestId] = time.time()
        return handleToRatingChanges[contestId]
Ejemplo n.º 2
0
def handleSettingsCallback(chat: Chat, data, callback):
    if data != "":
        logger.critical("Invalid callback settings data: " + data)
    else:
        chat.editMessageText(callback['message']['message_id'],
                             "What do you want to change?",
                             getReplyMarkup(getSettingsButtons()))
Ejemplo n.º 3
0
def handleCFError(request, r, chat):
    if r['status'] == 'FAILED':
        #delete nonexisting friends
        startS = "handles: User with handle "
        endS = " not found"
        if r['comment'].startswith(startS) and r['comment'].endswith(endS):
            handle = r['comment'][len(startS):-len(endS)]
            db.deleteFriend(handle)
            return
        #remove wrong authentification
        if 'Incorrect API key' in r['comment'] or 'Incorrect signature' in r[
                'comment']:
            chat.apikey = None
            chat.secret = None
            chat.sendMessage(
                "Your API-key did not work 😢. Please add a valid key and secret in the settings."
            )
            return
        if "contestId: Contest with id" in r[
                'comment'] and "has not started" in r['comment']:
            return  # TODO fetch new contest start time
        if "contestId: Contest with id" in r['comment'] and "not found" in r[
                'comment']:
            logger.debug("codeforces error: " + r['comment'])
            return
    logger.critical("codeforces error: " + str(r['comment']) + "\n" +
                    "this request caused the error:\n" + (str(request)[:200]),
                    exc_info=True)
Ejemplo n.º 4
0
 def _run(self):
     while True:
         found = False
         with self._lock:
             for i in range(len(self._q)):
                 if self._q[i].qsize() > 0:
                     (timeStamp, callbackFun) = self._q[i].get()
                     found = True
                     break
             if not found:
                 self._lock.wait()
         if found:
             startT = time.time()
             try:
                 callbackFun()
                 timeInSpooler = startT - timeStamp
                 timeForFun = time.time() - startT
                 if timeInSpooler > 0.001 or timeForFun > 0.001:
                     perfLogger.info(
                         "time in spooler: {:.3f}s; time for fun: {:.3f}s".
                         format(timeInSpooler, timeForFun))
             except Exception as e:
                 logger.critical('%s spooler error %s',
                                 self._name,
                                 e,
                                 exc_info=True)
             sleepT = startT + self._timeInterval - time.time()
             if sleepT > 0:
                 time.sleep(sleepT)
Ejemplo n.º 5
0
def handleSetupCallback(chat, data, callback):
    if data == "":
        showSetupPage(chat, data, callback)
    else:
        funs = {
            'timezone': handleChangeTimezone,
            'handle': handleSetUserHandlePrompt,
            'apikey': handleSetAuthorization,
        }
        if data not in funs:
            logger.critical("wrong setup data: " + str(data))
        else:
            return funs[data](chat)
Ejemplo n.º 6
0
	def run(self):
		lastTime = -1
		while True:
			waitTime = lastTime + self._updateInterval - time.time()
			if waitTime > 0:
				time.sleep(waitTime)
			try:
				startT = time.time()
				self._doTask()
				if self._logPerf:
					perfLogger.info("service: {:.3f}s".format(time.time()-startT))
			except Exception as e:
				logger.critical('Run error %s', e, exc_info=True)
			lastTime = time.time()
Ejemplo n.º 7
0
def handleWidthChange(chat: Chat, data, callback):
    def getMsg(width):
        table = Table(
            ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"],
            [])
        text = (
            "Configure how many columns you want to display. Choose the maximum "
            "value which still displays the table correctly.\n"
            "Note: This setting is global for the chat, make sure it works on all of "
            "your devices.\n")
        text += table.formatTable(chat.width)
        buttons = [
            [{
                "text": "-",
                "callback_data": "width:-"
            }, {
                "text": "+",
                "callback_data": "width:+"
            }],
            [{
                "text": "👈 Back to General Settings",
                "callback_data": "general:"
            }],
        ]
        return text, buttons

    warningText = None
    if data == '':
        pass  # initial call, don't change
    elif data == '+':
        if chat.width == 12:
            warningText = "❗️You reached the maximum table width❗️"
        else:
            chat.width = chat.width + 1
    elif data == '-':
        if chat.width == 4:
            warningText = "❗️You reached the minimum table width❗️"
        else:
            chat.width = chat.width - 1
    else:
        logger.critical("unrecognized data at handle width: " + str(data))

    if warningText:
        return warningText
    else:
        text, buttons = getMsg(chat.width)
        chat.editMessageText(callback["message"]["message_id"], text,
                             settings.getReplyMarkup(buttons))
Ejemplo n.º 8
0
 def _analyseContest(self, contestId, friends, firstRead):
     ranking = cf.getStandings(contestId, friends, forceRequest=True)
     if ranking is False:
         if firstRead:
             logger.critical(
                 "------------ ranking not fetched during firstRead ----------------------------"
             )
             logger.critical(
                 "Aborting to avoid resending of solved notifications ...")
             os._exit(1)
         return
     results = ranking['rows']
     for row in results:
         self._analyseRow(contestId, row, ranking, firstRead)
     if ranking['contest']['phase'] != 'FINISHED' and not firstRead:
         self._updateStandings(contestId, db.getAllChatPartners())
def handleChatCallback(chat: Chat, data, callback):
    answerToast = None
    if data == "":
        buttons, title = getMenu(chat)
    elif data.startswith("config-page"):
        page = int(data[len("config-page"):])
        buttons, title = getButtonRows(chat, page)
    elif data.startswith("toggle-"):
        answerToast, buttons, title = toggleFriendsSettings(
            chat, data[len("toggle-"):])
    elif data == "handlepress":
        return
    elif data == "decNotifyLvl":
        if chat.notifyLevel == 0:
            return "You already disabled all friend notifications"
        else:
            db.updateToNotifyLevel(
                chat.chatId,
                chat.notifyLevel - 1,
                chat.notifyLevel,
            )
            chat.notifyLevel -= 1
        buttons, title = getMenu(chat)
    elif data == "incNotifyLvl":
        if chat.notifyLevel >= len(NOTIFY_LEVEL_DESC) - 1:
            return "You already enabled all friend notifications"
        else:
            db.updateToNotifyLevel(chat.chatId, chat.notifyLevel + 1,
                                   chat.notifyLevel)
            chat.notifyLevel += 1
        buttons, title = getMenu(chat)
    elif data == "hoverNotifyLvl":
        return
    elif data == "reset":
        db.updateToNotifyLevel(chat.chatId, chat.notifyLevel, reset=True)
        buttons, title = getMenu(chat)
    else:
        logger.critical("no valid bahaviour option for notify settings: " +
                        data)

    replyMarkup = settings.getReplyMarkup(buttons)
    msgId = callback['message']['message_id']
    chat.editMessageText(msgId, title, replyMarkup)
    return answerToast
Ejemplo n.º 10
0
def handleCallbackQuery(callback):
    chat = ChatFunctions.getChat(str(callback['message']['chat']['id']))
    data = callback['data']

    if not ":" in data:
        logger.critical("Invalid callback data: " + data)
        return

    pref, suff = data.split(":", 1)
    funs = {
        "settings": handleSettingsCallback,
        "general": general_settings.handleSetupCallback,
        "behavior": behavior_settings.handleChatCallback,
        "friend_notf": notify_settings.handleChatCallback,
        "width": widthSelector.handleWidthChange,
    }
    if pref not in funs:
        logger.critical("Invalid callback prefix: " + pref + ", data: " + suff)
    else:
        retMsg = funs[pref](chat, suff, callback)
        tg.requestSpooler.put(
            lambda: tg.sendAnswerCallback(chat.chatId, callback['id'], retMsg),
            priority=0)
Ejemplo n.º 11
0
def handleChatCallback(chat, data, callback):
	answerText = None
	with chatsLock:
		if data == "polite":
			chat.polite = not chat.polite
			if chat.polite:
				answerText = "👿 This is what I call weakness…"
			else:
				answerText = "😈 Welcome back to the dark side."
		elif data == "reply":
			chat.reply = not chat.reply
		elif data == "reminder2h":
			chat.reminder2h = not chat.reminder2h
		elif data == "reminder1d":
			chat.reminder1d = not chat.reminder1d
		elif data == "reminder3d":
			chat.reminder3d = not chat.reminder3d
		elif data != "":
			logger.critical("no valid bahaviour option: " + data)

		buttons = getChatSettingsButtons(chat)
	replyMarkup = settings.getReplyMarkup(buttons)
	chat.editMessageText(callback['message']['message_id'], "Change the behavior of the bot:", replyMarkup)
	return answerText
Ejemplo n.º 12
0
def sendRequest(method, params, authorized=False, chat=None):
    rnd = random.randint(0, 100000)
    rnd = str(rnd).zfill(6)
    tailPart = method + '?'

    if authorized:
        try:
            if chat == None or chat.apikey == None or chat.secret == None:
                # maybe we don't have apikey so we cannot request friends or smt
                return False
            params['apiKey'] = str(chat.apikey)
            params['time'] = str(int(time.time()))
        except Exception as e:
            logger.critical("%s", e, exc_info=True)
            return False

    for key, val in sorted(params.items()):
        tailPart += str(key) + "=" + urllib.parse.quote(str(val)) + "&"
    tailPart = tailPart[:-1]

    if authorized:
        hsh = util.sha512Hex(rnd + '/' + tailPart + '#' + chat.secret)
        tailPart += '&apiSig=' + rnd + hsh
    request = codeforcesUrl + tailPart
    startWait = time.time()
    waitTime = endTimes.get() + 1 - time.time()
    if waitTime > 0:
        time.sleep(waitTime)
    startT = time.time()
    try:
        r = requests.get(request, timeout=15)
    except requests.exceptions.Timeout as errt:
        logger.error("Timeout on Codeforces.")
        return False
    except requests.exceptions.ChunkedEncodingError as e:
        logger.error("ChunkedEncodingError on CF: %s", e)
        return False
    except Exception as e:
        logger.critical('Failed to request codeforces: \nexception: %s\n',
                        e,
                        exc_info=True)
        return False
    finally:
        perfLogger.info("cf request " + method +
                        ": {:.3f}s; waittime: {:.3f}".format(
                            time.time() - startT, startT - startWait))
        endTimes.put(time.time())
    if r.status_code != requests.codes.ok:
        if r.status_code == 429:
            logger.error("too many cf requests... trying again")
            return sendRequest(method, params, authorized, chat)
        elif r.status_code // 100 == 5:
            logger.error("Codeforces Http error " + str(r.reason) + " (" +
                         str(r.status_code) + ")")
        else:
            try:
                r = r.json()
                handleCFError(request, r, chat)
            except simplejson.errors.JSONDecodeError as jsonErr:
                logger.critical("no valid json; status code for cf request: " +
                                str(r.status_code) + "\n" +
                                "this request caused the error:\n" +
                                str(request),
                                exc_info=True)
        return False
    else:
        try:
            r = r.json()
            if r['status'] == 'OK':
                return r['result']
            else:
                logger.critical("Invalid Codeforces request: " + r['comment'])
                return False
        except Exception as e:  #TODO why does CF send an invalid json with http 200?
            logger.critical(
                "json decoding failed; status code for cf request: " +
                str(r.status_code) + "\n" +
                "this request caused the error:\n" + str(request) + "\n" +
                "text got back:\n" + str(r.text),
                exc_info=True)
            return False
Ejemplo n.º 13
0
	try:
		msgText = open(sys.argv[1]).read()[:-1] # discard trailing newline
		logger.info("sending broadcast message:\n" + msgText)
		for chatId in Chat.chats:
			msg = msgText
			chat = Chat.chats[chatId]
			while True:
				m = re.search("\[%t [0-9]*\]", msg)
				if m is None:
					break
				tInSec = int(m.group()[4: -1])
				timeLeft = int(tInSec - time.time())
				delta = datetime.timedelta(seconds=timeLeft)
				dTime = f"*{util.displayTime(tInSec, chat.timezone)}* (in {':'.join(str(delta).split(':')[:2])} hours)"
				msg = msg[:m.span()[0]] + dTime + msg[m.span()[1]:]
			#print(f"chat: {chatId}: {msg}")
			chat.sendMessage(msg)
		time.sleep(1)
		while tg.requestSpooler._q[0].qsize() > 0:
			try:
				print(f"waiting {tg.requestSpooler._q[0].qsize()}")
			except Exception as ex:
				print(ex)
			time.sleep(1)
		logger.info("sending broadcasts finished")
	except Exception as e:
		logger.critical(str(e))
else:
	logger.error("wrong command line options\nusage: python3 sendBroadcast.py <file with text>")
os._exit(0)