예제 #1
0
 def monitor(self):
     log.info("[CallMonitor] Started monitor")
     BrowserWrapper.b.open_menu("Status")
     waiting_from = None
     while True:
         if pbot.has_request():
             skip_processing = False
             request = pbot.request
             log.info("[CallMonitor] Has personal bot request: %s" %
                      request)
             # reboot and reset/restore are still possible while in the call
             # as we have a confirmation message before running each of them
             if self.call_or_dialing_started():
                 if isinstance(request, BalanceRequest)\
                         or isinstance(request, SendSmsRequest)\
                         or isinstance(request, SendUssdRequest):
                     log.info(
                         "[CallMonitor] Could not process the request while in a call. Waiting..."
                     )
                     skip_processing = True
             if isinstance(request, RebootRequest) or isinstance(
                     request, ResetRestoreRequest):
                 waiting_from = None
             if not skip_processing:
                 log.info("[CallMonitor] Processing personal bot request")
                 pbot.process_request(self.goip)
                 log.info("[CallMonitor] Processed personal bot request")
                 BrowserWrapper.b.open_menu("Status")
         # send daily status every day once at 23:XX when no-one is using GoIP caller
         if current_time().hour == 23 and not self.call_or_dialing_started() and\
                 (not self.daily_status_sent_at or self.daily_status_sent_at.date() != current_date().date()):
             self.daily_status_sent_at = current_time(
             )  # using in-memory var to decrease amt of calls to DB
             vs.set_daily_status_sent(self.daily_status_sent_at)
             bot.send(daily_status())
         # this should be checked every time, so no var defined above
         sleep_for_sec = 2 if self.call_or_dialing_started(
         ) else LAST_CALL_SLEEP_SECONDS
         # if not authorised for < 5 minutes - just wait for this issue to get fixed (with reset/restore?)
         if not BrowserWrapper.b.is_authorized(
         ) and not passed_more_that_sec(waiting_from, 5 * 60):
             log.warning(
                 "[CallMonitor] Browser is not ok - session is not authorised"
             )
             if waiting_from is None:
                 waiting_from = current_time()
             sleep(sleep_for_sec)
             continue
         waiting_from = None
         # this is the way to get up-to-day info from the page
         BrowserWrapper.b.driver.refresh()
         if self.goip.goip_monitor():  # if all is fine with GoIP
             self.call_monitor()  # run call monitor logic
         else:
             log.info("[CallMonitor] GoIP monitor is not ok")
         sleep(sleep_for_sec, print_log=False)
예제 #2
0
    def goip_monitor(self):
        # we couldn't afford sleep(600) because we are working with browser in the single thread
        # instead - just skip method' body till the sleep time is elapsed
        if self.goip_slept_at and not passed_more_that_sec(
                self.goip_slept_at, GOIP_MONITOR_SLEEP_SECONDS):
            return True

        cdr_started = BrowserWrapper.b.by_id("l1_cdrt").text.strip()
        if cdr_started.startswith("1970-01"):
            log.error(
                "[GoipMonitor] Have internal GoIP issue (1970 year at clock).")
            if vs.last_date_cdr_restart() == current_time().date(
            ):  # if we had the same problem today
                bot.send(
                    "Переналаштовую дзвонилку бо вона ґеґнула (1970 рік надворі)!"
                )
                self.reset_and_restore()
            else:
                vs.set_last_date_cdr_restart(current_time().date(
                ))  # if this is the first problem occurrence
                bot.send(
                    "Перезавантажую дзвонилку бо вона знову ні-гугу (1970 рік надворі)!"
                )
                self.reboot()
            # open the 'Status' tab again to support the logic in rest of the cycle
            BrowserWrapper.b.open_menu("Status")
            # just waiting for the fix to be applied. Nothing could be done now
            return False
        # reason for the status check is doing fix only if GoIP problem persists for >1 cycle
        goip_is_working = self.statuses_ok()
        if not goip_is_working and vs.last_reg_status(
        ) == self.voip_connection_status:
            self.reset_and_restore()
            # open the 'Status' tab again to support the logic in rest of the cycle
            BrowserWrapper.b.open_menu("Status")
        self.voip_connection_status = vs.last_reg_status()
        self.goip_slept_at = current_time(
        )  # we have this in-memory var to decrease amt of calls to the DB
        vs.set_monitor_slept_at(
            self.goip_slept_at
        )  # we are using this value as heartbeat for the whole GoIP monitor
        log.info("[GoipMonitor] Sleeping for %d sec..." %
                 GOIP_MONITOR_SLEEP_SECONDS)
        if not goip_is_working:  # just waiting for the fix to be applied. Nothing could be done now
            log.error(
                "[GoipMonitor] Patient is not ok. Will check again soon.")
            return False
        return True
예제 #3
0
def monthly_status():
    has_status, minutes_left, valid_till = parse_ussd(USSD_MONTHLY_STATUS,
                                                      MONTHLY_STATUS_REGEX,
                                                      [False, None, None])
    valid_days = 0
    if has_status:
        log.info(
            "[Monthly status] Found information: minutes left '%s', valid till '%s'"
            % (minutes_left, valid_till))
        valid_till_date = datetime.strptime(valid_till, "%d.%m.%y")
        valid_days = (valid_till_date - current_time()).days
    return has_status, minutes_left, valid_days
예제 #4
0
 def start_call(self):
     # this could happen when previous call ended and new started in-between check cycles
     if self.call_started and self.call_number != self.last_called_number:
         self.finish_call()
     # if we missed dialing statuses because of slow cycles
     if not self.dialing_started:
         self.start_dialing()
     # start actual call
     if not self.call_started:
         log.info("[Process call] Started call to %s" % self.call_number)
         self.last_msg = self.bot_message("Говоримо з %s" %
                                          self.call_number)
         self.call_started = current_time()
         self.last_called_number = self.call_number
예제 #5
0
 def start_dialing(self):
     self.dialing_started = current_time()
     try:
         log_msg, self.msg_call_status = self.STATUS_LOG_MSG.get(
             self.status)
     except TypeError as e:  # if call already started
         log.warning(
             "[Start call] Exception getting message from call status: %s" %
             e)
         log_msg, self.msg_call_status = self.STATUS_LOG_MSG.get(
             self.DIALING)
     log.info("[Start call] %s" % log_msg)
     if self.status_changed:
         self.last_msg = self.bot_message(self.msg_call_status)
예제 #6
0
 def statuses_ok(self):
     log.info("[Statuses ok] Checking")
     b = BrowserWrapper.b
     sim = b.by_id("l1_gsm_sim").text.strip()
     gsm = b.by_id("l1_gsm_status").text.strip()
     voip = b.by_id("l1_status_line").text.strip()
     vs.set_last_reg_status(None)  # reset value
     if voip == "401":
         log.error(
             "[Statuses ok] Incorrect SIP username/password specified.")
         # try to fix fix-able issue only once per day as more attempts are often useless
         if vs.last_date_error_notified() and vs.last_date_error_notified(
         ).date() == current_time().date():
             return True  # do not fix
         vs.set_last_date_error_notified(current_time())
         vs.set_last_reg_status(
             "Помилка реєстрації VoIP. Невірний логін/пароль (код %s)" %
             voip)
         return False  # try to fix
     if voip == "403":
         log.error("[Statuses ok] Error 403. No easy remedy for this")
         vs.set_last_reg_status("Невідома помилка (код %s)" % voip)
     if voip != "Y":
         log.error(
             "[Statuses ok] VoIP registration failed (status = '%s')." %
             voip)
         vs.set_last_reg_status("Помилка реєстрації VoIP (код %s)" % voip)
         return False  # try to fix
     if sim != "Y":
         log.error("[Statuses ok] SIM not found. No easy remedy for this")
         vs.set_last_reg_status("SIM не знайдено")
     if gsm != "Y":
         log.error("[Statuses ok] No GSM network. No easy remedy for this")
         vs.set_last_reg_status("Помилка реєстрації GSM")
     vs.set_last_date_error_notified(None)
     return True  # do not try to fix
예제 #7
0
 def finish_call(self):
     number = self.any_call_number()
     log.info("[Finish call] Processing call end for '%s'" % number)
     started_when = self.call_or_dialing_started()
     log.info("[Finish call] Call started at %s" % started_when)
     seconds = (current_time() - started_when).seconds
     log.info("[Finish call] Overall call duration is %s seconds" % seconds)
     duration_str = seconds_to_time_str(seconds,
                                        no_seconds=(seconds > 3600))
     log.info("[Finish call] Call to %s ended (%s)" %
              (number, duration_str))
     if self.call_started:
         text = "Дзвоник до %s - %s" % (number, duration_str)
         vs.increase_daily_call_duration(seconds)
         vs.increase_daily_ok_calls_amount(1)
     else:
         if self.msg_call_status:
             text = self.msg_call_status + random_list_item(
                 self.ERROR_PHRASES)
         else:
             text = "Ймовірно невдалий дзвоник до {number}"
         vs.increase_daily_failed_calls_amount(1)
     self.bot_message(text)
     self.dialing_started = self.call_started = self.last_called_number = self.msg_call_status = self.last_msg = None
예제 #8
0
def daily_status(scheduled_run=True):
    has_balance_info, money, tariff, number_valid_till = balance()
    has_monthly_info, monthly_minutes_left, monthly_valid_days = monthly_status(
    )
    has_yearly_info, yearly_valid_till = yearly_status()
    string = ""
    ok_calls_amt = vs.daily_ok_calls_amount()
    failed_calls_amt = vs.daily_failed_calls_amount()
    all_calls_amt = ok_calls_amt + failed_calls_amt
    calls_duration = vs.daily_calls_duration()
    fixed_times = vs.daily_fixed_times()
    today_is_sunday = current_date().strftime("%w") == "0"
    # daily calls status
    if all_calls_amt > 0:
        calls_stats = " (%d%%)" % (100 * ok_calls_amt / all_calls_amt)
    else:
        calls_stats = ""
    if calls_duration:
        duration_str = seconds_to_time_str(
            calls_duration, no_seconds=True)  # omit the seconds part
        duration_str = "%s%s" % (duration_str, calls_stats)
        if scheduled_run:
            vs.increase_weekly_call_duration(calls_duration)
    else:
        duration_str = "не було"
    string += "Розмов %s\n" % duration_str
    # weekly calls status
    weekly_calls_duration = vs.weekly_calls_duration()
    if not scheduled_run:  # as we do not increment weekly calls duration if it's a not scheduled_run
        weekly_calls_duration += calls_duration
    if today_is_sunday or not scheduled_run:  # if it's Sunday or on-demand info request
        duration_str = seconds_to_time_str(
            weekly_calls_duration, no_seconds=True)  # omit the seconds part
        string += "За тиждень %s\n" % duration_str
    if has_balance_info:
        string += "На рахунку %s грн" % money
        has_money_diff, money_diff = daily_balance_diff(money=money)
        if has_money_diff:
            string += " (%s грн)" % money_diff
        string += "\n"
    if has_monthly_info:
        days_add = "на %s дні(в)" % monthly_valid_days if monthly_valid_days > 0 else "до сьогодні"
        string += "%s хв %s\n" % (monthly_minutes_left, days_add)
    if fixed_times:
        string += "<b>Полагоджено %s раз(и)</b>\n" % fixed_times
    if tariff:
        string += "Тариф %s\n" % tariff
    if number_valid_till or yearly_valid_till:
        if yearly_valid_till and yearly_valid_till < number_valid_till:
            valid_till = yearly_valid_till
        else:
            valid_till = number_valid_till or yearly_valid_till  # as 1 might be None
        days_left = (valid_till - current_time()).days
        if days_left < 10:
            string += "<b>Поповни! Лишилось %s дні(в)</b>\n" % days_left
        string += "Рік/номер до %s\n" % valid_till.strftime(DATE_FORMAT)
    if scheduled_run:
        reset_daily_values(money=money)
        if today_is_sunday:
            vs.set_weekly_calls_duration(0)
    return string