def async_run(self): while True: try: event = self.internal_queue.get(block=True, timeout=1) event() except Empty: pass except Exception: L.error("Exception:\n" + traceback.format_exc())
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 add_fake_request(self,msg): if msg['response'] == 'ping': request=Ping() elif msg['response'] == 'query': request=Refresh() elif msg['response'] == 'modify': request=Modify() else: L.error("Respuesta desconocida %s" % msg['response']) request.id=msg['id'] self.pending[request.id] = request
def run(self): while True: try: osc.readQueue(self.oscid) if not self.notified: self.update_notification("Intento: " + self.last_time.strftime('%Y-%m-%d %H:%M')) self.notified = True if self.check_pattern(): self.add_pattern() # Pending operations if self.check_interval(): # Update last_time here to avoid repeated requests self.last_time = datetime.datetime.now(tz=self.met) self.internal_queue.put(lambda: self.modify(-1)) except: L.error("Exception:\n" + traceback.format_exc()) sleep(.1)
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_info(self, state, pending, status=None): self.status_bar.text = "" if not state: L.error("state is None") self.querying.dismiss() if status is not None: self.error.text = status else: self.error.text = "Error desconocido" self.error.open() return self.unrequest_month(self.current_month) self.unrequest_month(self.next_month) self.current_month.update(state, pending) self.next_month.update(state, pending) L.debug("Update ends") self.querying.dismiss()
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 query(self): L.debug("Starting query") if self.session is None: # # No session, start a login session # the result is fine as a query result # state = self.login() return state # # Reuse session # try: r = self.session.get("http://" + self.host + "/perfil.php") if r.status_code != requests.codes.ok: status = "Error consultando al " + self.host + ", respuesta:" + r raise ServerException(status) # # Parse the web page we have read # L.debug("Parsing query result") state = self.parse_months(self.get_response_text(r)) if state is None: L.debug("parsing failed, login might have failed") self.session = None return self.query() except (KeyboardInterrupt, requests.ConnectionError, ServerException): L.error(traceback.format_exc()) # try to login again self.session = None return self.query() return state
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 check_timeout(self): now = datetime.datetime.now() timedout_id = [_id for _id in self.pending if self.pending[_id].endtime < now] timedout = [self.get_id(_id) for _id in timedout_id] map(lambda (x): L.error("Time out on %d" % x.id), timedout) map(lambda (x): x.timedout(), timedout)