Ejemplo n.º 1
0
 def send_ping_result(self, _id):
     L.debug("Send ping result %d" % _id)
     pickle_msg = pickle.dumps({
         'response': 'ping',
         'id': _id,
         'config': self.config})
     osc.sendMsg('/android_park', [pickle_msg, ], port=3334)
Ejemplo n.º 2
0
 def send_modify_result(self, _id, status=None):
     L.debug("Send modify result %d" % _id)
     pickle_msg = pickle.dumps({
         'response': 'modify',
         'id': _id,
         'status': status})
     osc.sendMsg('/android_park', [pickle_msg, ], port=3334)
Ejemplo n.º 3
0
    def start_modify_request(self):
        if not self.service_running:
            self.error.text = "El Servicio en segundo plano no está corriendo"
            self.error.open()
            return

        L.debug("Send start")
        days = self.get_days_with_change()
        operations = {}
        for d in days:
            if d.day.status != DayStatus.RESERVED and d.day.status != DayStatus.REQUESTED:
                # request
                operations[d.day.date] = DayStatus.TO_REQUEST
            elif d.day.status == DayStatus.RESERVED:
                # free
                operations[d.day.date] = DayStatus.TO_FREE
            elif d.day.status == DayStatus.REQUESTED:
                # unrequest
                operations[d.day.date] = DayStatus.TO_UNREQUEST
        free_count = len([x for x in operations if operations[x] == DayStatus.TO_FREE])
        unrequest_count = len([x for x in operations if operations[x] == DayStatus.TO_UNREQUEST])
        request_count = len([x for x in operations if operations[x] == DayStatus.TO_REQUEST])

        # Now add to the operations those days that are already requested.
        requested_days = self.get_days_requested()
        for d in requested_days:
            operations[d.day.date] = DayStatus.TO_REQUEST
        total_request_count = len([x for x in operations if operations[x] == DayStatus.TO_REQUEST])

        self.confirm.text = "Se liberarán {0:d} plazas, se quitará la solicitud para {1:d} plazas y se solicitarán {2:d} nuevas plazas. {3:d} plazas están solicitadas" \
            .format(free_count, unrequest_count, request_count, total_request_count - request_count)
        self.confirm.on_accept = lambda: self.modify_request(operations)
        self.confirm.open()
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 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
Ejemplo n.º 6
0
 def send_query_result(self, _id, result, pending, status=None):
     L.debug("Send query result %d" % _id)
     pickle_msg = pickle.dumps({
         'response': 'query',
         'id': _id,
         'result': result,
         'pending': pending,
         'status': status})
     osc.sendMsg('/android_park', [pickle_msg, ], port=3334)
Ejemplo n.º 7
0
 def add_pattern(self):
     pattern = ""
     if self.config is not None:
         pattern = self.config.get("general", "pattern")
     dates_from_pattern = [t[1] for t in self.parse_spec(pattern) if t[0]]
     L.debug("Using pattern %s, adding %s" % (pattern, str(dates_from_pattern)))
     self.pending.update({t: DayStatus.TO_REQUEST for t in dates_from_pattern})
     if len(dates_from_pattern) > 0:
         self.last_time = None  # Force a modify.
Ejemplo n.º 8
0
 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())
Ejemplo n.º 9
0
 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
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    def refresh_request(self):
        if not self.is_config_ready():
            return

        if not self.service_running:
            self.error.text = "El Servicio en segundo plano no está corriendo"
            self.error.open()
            return

        L.debug("Query start")
        self.last_update = datetime.datetime.now()
        self.querying.open()
        self.status_bar.text = "Consultando al servidor del parking..."
        self.app.do_refresh()
Ejemplo n.º 14
0
 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)
Ejemplo n.º 15
0
 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())
Ejemplo n.º 16
0
    def handle_message(self, message, *args):
        pickle_msg = message[2]
        msg = pickle.loads(pickle_msg)

        if 'response' in msg:
            if msg['id'] == -1:
                self.add_fake_request(msg)
            keep = 'is_partial' in msg and msg['is_partial']
            req = self.get_id(msg['id'], keep)
            if req is not None:
                if keep:
                    req.callback_partial(msg)
                else:
                    req.callback(msg)
            else:
                L.debug("Ignoring unknown response %d" % msg['id'])
        else:
            L.debug("Got a request %s for %d" % (msg['response'], msg['id']))
Ejemplo n.º 17
0
    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()
Ejemplo n.º 18
0
    def handle_message(self, message, *args):
        pickle_msg = message[2]
        msg = pickle.loads(pickle_msg)
        L.debug("Received message %s" % msg['request'])

        self.config = msg['config']
        self.server.config(self.config)

        if msg['request'] == 'ping':
            # Reply immediatelly to pings.
            self.ping(msg['id'])
        if msg['request'] == 'query':
            self.internal_queue.put(lambda: self.query(msg['id']))
        if msg['request'] == 'modify':
            self.pending = msg['operations']
            self.internal_queue.put(lambda: self.modify(msg['id']))

        L.debug("End Received message %s" % msg['request'])
Ejemplo n.º 19
0
 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
Ejemplo n.º 20
0
    def login(self):
        L.debug("Starting login")
        #
        # Start a session so that we can reuse cookies
        #
        self.session = requests.Session()

        # self.session.proxies= {
        #    "http": "http://es.proxy.lucent.com:8000",
        #    "https": "http://es.proxy.lucent.com:8000",
        # }

        #
        # Prepare the login request
        #
        try:
            r = self.session.post(
                "http://" + self.host + "/index.php",
                data={"usuario": self.username, "contrasena": self.password, "aceptar": "ACEPTAR"},
            )

            if r.status_code != requests.codes.ok:
                status = "Fallo al hacer login " + self.host + ", respuesta:" + r
                raise ServerException(status)

        except (KeyboardInterrupt, requests.ConnectionError) as e:
            status = str(e)
            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:
            raise ServerException(
                "Problema consultando con el servidor, es probable que el usuario/contraseña sean incorrectos"
            )
        return state
Ejemplo n.º 21
0
 def __init__(self):
     L.debug("Service is running")
     # Initialize internal queue
     self.thread = threading.Thread(name='execution', target=self.async_run)
     self.internal_queue = Queue()
     self.thread.start()
     # Initialize OSC
     osc.init()
     self.oscid = osc.listen(ipAddr='127.0.0.1', port=3333)
     osc.bind(self.oscid, self.handle_message, '/android_park')
     self.server = ServerInterface()
     self.pending = {}
     self.last_time = None
     self.notified = True
     self.config = None
     # set to indicate that a month has been processed by the pattern
     self.pattern_processed=set()
     # Initialize timezones
     self.met = pytz.timezone('Europe/Madrid')
     self.t1 = datetime.time(hour=0, minute=0, second=0, tzinfo=self.met)  # 00:00
     self.t2 = datetime.time(hour=15, minute=0, second=0, tzinfo=self.met)  # 15:00
     self.t3 = datetime.time(hour=17, minute=30, second=0, tzinfo=self.met)  # 17:30
     self.t4 = datetime.time(hour=23, minute=59, second=59, tzinfo=self.met)  # 23:59
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
    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))
Ejemplo n.º 24
0
 def ping_callback(self, value, config):
     if self.service_running != value:
         L.debug("Service state change: " + str(value))
     self.service_running = value
Ejemplo n.º 25
0
 def modify_partial_callback(self, status):
     L.info(status)
     self.status_bar.text = status.decode('utf-8', 'replace').encode('utf-8')
Ejemplo n.º 26
0
    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
Ejemplo n.º 27
0
 def callback_partial(self, msg):
     if self.calendar is not None:
         L.debug("Got a partial response %s for %d" % (msg['response'], msg['id']))
         self.calendar.modify_partial_callback(msg['status'])
Ejemplo n.º 28
0
 def callback(self, msg):
     if self.calendar is not None:
         L.debug("Got a response %s for %d" % (msg['response'], msg['id']))
         self.calendar.modify_callback()
Ejemplo n.º 29
0
 def callback(self, msg):
     if self.calendar is not None:
         L.debug("Got a response %s for %d" % (msg['response'], msg['id']))
         self.calendar.refresh_callback(msg['result'], msg['pending'], msg['status'])
Ejemplo n.º 30
0
    def refresh_callback(self, state, pending, status=None):
        if status is not None:
            L.debug("Update status: " + str(status) + " pending operations: " + str(pending))

        Clock.schedule_once(lambda (dt): self.update_info(state, pending, status))