def query(self, _id): L.info("Calling query id: %s " % _id) try: result = self.server.query() self.update_pending(result) self.send_query_result(_id, result, self.pending) except ServerException as e: self.send_query_result(_id, None, self.pending, e.status)
def stop_service(self): if self.service is None: return L.info("Trying to stop service") if platform == 'android': from android import AndroidService self.service.stop() self.service = None
def start_service(self): if self.service is not None: return L.info("Trying to start service") if platform == 'android': from android import AndroidService service = AndroidService('AndroidPark(ing)', 'en ejecución...') service.start('service started') self.service = service
def modify(self, _id): L.info("Calling modify id:%s " % _id) try: result = self.server.modify(self.pending, lambda (s): self.send_modify_partial_result(_id, s)) self.last_time = datetime.datetime.now(tz=self.met) self.notified = False self.update_pending(result) self.send_modify_result(_id, "OK") except ServerException as e: self.send_modify_result(_id, e.status)
def modify(self, operations, partial): status = self.query() last_text = "" today = datetime.datetime.now(tz=self.met) for i in sorted(operations): if i.month == 1 and today.month == 12: mes = 1 else: mes = i.month - today.month if mes not in (0, 1): L.error(str(i) + " is neither current nor next month") partial(str(i) + " no es parte del mes actual o siguiente") continue if operations[i] == DayStatus.TO_REQUEST: if i not in status or status[i].status in ( DayStatus.RESERVED, DayStatus.NOT_AVAILABLE, DayStatus.REQUESTED, DayStatus.BUSY, ): partial(str(i) + " está ya solicitado") continue if operations[i] in (DayStatus.TO_FREE, DayStatus.TO_UNREQUEST): # Operation is to free/unrequest if i not in status or status[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE): partial(str(i) + " está ya liberado") continue try: L.debug("Requesting " + str(i) + ": " + self.map_operation(operations[i])) r = self.session.post( "http://" + self.host + "/perfil.php", data={"dia": i.day, "mes": mes, "libre": operations[i]} ) if r.status_code != requests.codes.ok: L.error("Failed request on " + self.host + ", response:" + r) partial(str(i) + "`: Failed request on server response:" + r) continue # Parse the web page to obtain the result message last_text = self.get_response_text(r) result = self.parse_result(last_text) if result == "": result = "La modificación de " + str(i) + " no fue aceptada" partial(result) L.info(str(i) + ": " + result) except (KeyboardInterrupt, requests.ConnectionError): L.debug("Petición fallida en " + self.host + ", con:\n" + traceback.format_exc()) if last_text != "": return self.parse_months(last_text) else: # We didn't send any operation, use the status retrieved # when we entered the method. return status
def update_notification(self, text): L.info("Notification: " + text) if platform == 'android': try: service = PythonService.mService builder = NotificationBuilder(service) builder.setSmallIcon(service.getApplicationInfo().icon) builder.setContentTitle("AndroidPark(ing)") builder.setContentText(text) context_intent = Intent(service, Class.forName('org.renpy.android.PythonActivity')) pending_intent = PendingIntent.getActivity(service, 0, context_intent, PendingIntent.FLAG_UPDATE_CURRENT) builder.setContentIntent(pending_intent) manager = service.getSystemService(Context.NOTIFICATION_SERVICE) manager.notify(1, builder.build()) except: L.error("Exception:\n" + traceback.format_exc())
def update_pending(self, result): """ Update the pending operations with the result retrieved from the web. :param result: :return: None """ self.check_next_month(result) to_delete = [] L.info("pending (before) " + str(self.pending)) for i in sorted(self.pending): today = datetime.datetime.now(tz=self.met) if(i.month==1 and today.month==12): mes = 1 else: mes = i.month - today.month if mes not in (0, 1): L.error(str(i) + " is neither current nor next month") to_delete.append(i) continue if self.pending[i] == DayStatus.TO_FREE: # Request was to Free... target should be Free. if i not in result or result[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE): to_delete.append(i) if self.pending[i] == DayStatus.TO_REQUEST: # Request was to Request.... target is Assigned. if i not in result or result[i].status in (DayStatus.RESERVED, DayStatus.NOT_AVAILABLE): to_delete.append(i) if self.pending[i] == DayStatus.TO_UNREQUEST: # Request was to Unrequest. if i not in result or result[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE): to_delete.append(i) for i in to_delete: del self.pending[i] for i in [i for i in result if result[i].status == DayStatus.REQUESTED]: self.pending[i] = DayStatus.TO_REQUEST L.info("pending (after) " + str(self.pending))
def check_interval(self): """ Check if it is time for a new attempt :return: True if it is time for a new attempt """ now = datetime.datetime.now(tz=self.met) tomorrow = now.date() + datetime.timedelta(days=1) f1 = 0 f2 = 0 if self.config is not None: f1 = int(self.config.get("timers", "frequency")) * 60 f2 = int(self.config.get("timers", "frequency2")) * 60 if len(self.pending) > 0 and \ ((self.t1 <= now.time() < self.t2) or (self.t3 <= now.time() < self.t4)): # Period 00:00 - 14:59: attempt every 30 min if self.last_time is None or (0 < f1 < (now - self.last_time).total_seconds()): L.info("modify on regular interval") return True if (self.t2 <= now.time() < self.t3) and tomorrow in self.pending: # Period 15:00 - 17:30: attempt 1 min (but only if there's something pending for tomorrow if self.last_time is None or (0 < f2 < (now - self.last_time).total_seconds()): L.info("modify on repesca interval") return True if len(self.pending) > 0 and \ now.hour == 14 and now.minute > 50 and \ now.second > random.randrange(0, 60) and \ ((self.last_time is None) or ((now - self.last_time).total_seconds() > (10 * 60))): # One final at 14:50 + random seconds # and only if we haven't requested more than 10 minutes ago. L.info("modify on Last call") return True return False
def parse_months(self, text): """ Parse the web page to obtain the list of the days and their status :param text: the text from the http response :return: a dictionary with the status of the days """ result = [] out = {} soup = bs4.BeautifulSoup(text, "html5lib") # get the cells... this is better reference I could get toptables = soup.select("body > table ") if len(toptables) != 6: L.error("Parsing: did not found 6 tables") return None tables = [toptables[4].tbody.tr.td.table, toptables[5].tbody.contents[1].td.table] # Now, for each table. for t in tables: month = [] # for each week (row) for w in t.select("tr"): # for each day (cell) for d in w.select("td"): # only pay attention to colored cells if "bgcolor" in d.attrs: # Try to parse the cell cell_list = d.select("div") if len(cell_list) == 0: # No divs... not interested in this continue elif len(cell_list) < 2: # only one div day = cell_list[0] slot = None else: # two divs. (day, slot) = cell_list # some days appear with two nested divs. if day.string is not None: mday = int(day.string.strip()) else: mday = int([x for x in day.stripped_strings][0]) rslot = None # parse the status based on the color if d.attrs["bgcolor"] == "#999999": status = DayStatus.NOT_AVAILABLE elif d.attrs["bgcolor"] == "#FF9900": status = DayStatus.RESERVED if slot is not None: rslot = [x for x in slot.stripped_strings][0] elif d.attrs["bgcolor"] == "#339900": status = DayStatus.AVAILABLE elif d.attrs["bgcolor"] == "#000000": status = DayStatus.REQUESTED else: status = DayStatus.BUSY month.append(DayStatus(mday, status, rslot)) result.append(month) if len(result) != 2: L.error("Parsing: did not found 2 months") return None # Now rebuild the date today = datetime.datetime.now(tz=self.met) today = datetime.date(today.year, today.month, 1) for d in [x.fix(today) for x in result[0]]: out[d.date] = d for d in [x.fix(today + datetime.timedelta(days=31)) for x in result[1]]: out[d.date] = d busy = len([x for x in out if out[x].status == DayStatus.BUSY]) requested = len([x for x in out if out[x].status == DayStatus.REQUESTED]) reserved = len([x for x in out if out[x].status == DayStatus.RESERVED]) available = len([x for x in out if out[x].status == DayStatus.AVAILABLE]) L.info("Parsed: %d busy,%d requested, %d reserved, %d available" % (busy, requested, reserved, available)) return out
def modify_partial_callback(self, status): L.info(status) self.status_bar.text = status.decode('utf-8', 'replace').encode('utf-8')