Exemple #1
0
class TorrentPeerProcessor(TorrentManager):

    def __init__(self, torrent):
        TorrentManager.__init__(self, torrent, "Peer processor")

        self.running = False
        self.process_thread = CustomThread(self.process, "Peer processor")

    def start(self):
        self.running = True
        self.process_thread.start()

    def stop(self):
        self.running = False
        self.process_thread.join()
        super().stop()

    def process(self):
        while self.running:
            start_time = current_time()
            peers_to_process = self.torrent.peer_manager.connected_peers

            Timing().start_timing("peer_processing")
            for peer in peers_to_process:
                peer.metadata_manager.update()
                peer.download_manager.update_timeout()
            Timing().stop_timing("peer_processing")

            spend_time = current_time() - start_time
            time.sleep(0.1 - (spend_time / 1000))
Exemple #2
0
class PresenceManager(metaclass=Singleton):
    def __init__(self):
        self.check_thread = CustomThread(self.check_presence,
                                         "Presence checker")
        self.running = False
        self.check_interval = 5
        self.device_gone_interval = 240
        self.on_coming_home = None
        self.on_leaving_home = None
        self.anyone_home = True
        self.pi = sys.platform == "linux" or sys.platform == "linux2"

        self.device_states = [
            DeviceState("Mobiel Jan", "192.168.2.51",
                        self.device_gone_interval),
            DeviceState("Mobiel Melissa", "192.168.2.50",
                        self.device_gone_interval),
        ]

    def start(self):
        self.running = True
        self.check_thread.start()

    def stop(self):
        self.running = False
        self.check_thread.join()

    def check_presence(self):
        if not self.pi:
            return

        while self.running:
            for device in self.device_states:
                result = subprocess.call('sudo arping -q -c1 -W 1 ' +
                                         device.ip + ' > /dev/null',
                                         shell=True)
                device.set_device_state(result == 0)

            if self.anyone_home and len(
                [x for x in self.device_states if x.home_state]) == 0:
                # left
                self.anyone_home = False
                Logger().write(LogVerbosity.Info, "Everybody left home")
                if self.on_leaving_home is not None:
                    self.on_leaving_home()
            elif not self.anyone_home and len(
                [x for x in self.device_states if x.home_state]) > 0:
                # returned
                self.anyone_home = True
                Logger().write(LogVerbosity.Info, "Someone came home")
                if self.on_coming_home is not None:
                    self.on_coming_home()

            time.sleep(self.check_interval)
Exemple #3
0
class TorrentNetworkManager(TorrentManager):

    def __init__(self, torrent):
        super().__init__(torrent, "network")

        self.running = True
        self.torrent = torrent

        self.speed_log = 0

        self.average_download_counter = AverageCounter(self, 3)

        self.thread = None
        self._event_id_stopped = EventManager.register_event(EventType.TorrentStopped, self.unregister)

    def unregister(self):
        EventManager.deregister_event(self._event_id_stopped)

    def start(self):
        Logger().write(LogVerbosity.Info, "Starting network manager")
        self.thread = CustomThread(self.execute, "Network IO")
        self.thread.start()

    def execute(self):
        while self.running:
            Timing().start_timing("IO")
            # Select in/outputs
            input_peers = self.torrent.peer_manager.get_peers_for_reading()
            received_messages = []
            for peer in input_peers:
                messages_size, messages = peer.connection_manager.handle_read()
                if messages_size > 0:
                    self.average_download_counter.add_value(messages_size)
                    time = current_time()
                    received_messages += [(peer, x, time) for x in messages]

            if len(received_messages) != 0:
                self.torrent.message_processor.process_messages(received_messages)

            for peer in self.torrent.peer_manager.connected_peers:
                peer.download_manager.update_requests()

            output_peers = self.torrent.peer_manager.get_peers_for_writing()
            for peer in output_peers:
                peer.connection_manager.handle_write()

            Timing().stop_timing("IO")
            sleep(0.005)

    def stop(self):
        self.running = False
        self.thread.join()
        super().stop()
Exemple #4
0
class Engine(LogObject):

    def __init__(self, name, tick_time=1000, parent=None):
        super().__init__(parent, "Engine:" + name)

        self.name = name
        self.tick_time = tick_time
        self.last_tick = 0
        self.running = False
        self.thread = None
        self.work_items = []

        self.current_item = None
        self.start_time = 0

        self.timing = dict()
        self.own_time = TimingObject(self.name)

        # Log props
        self.current_item_log = ""

    def runner(self):
        while self.running:
            sleep(0.01)
            if not self.running:
                break

            self.last_tick = current_time()
            self.tick()

    def start(self):
        self.running = True
        self.thread = CustomThread(self.runner, self.name)
        self.thread.start()

    def add_work_item(self, name, interval, work_item, initial_invoke=True):
        self.work_items.append(EngineWorkItem(self, name, interval, work_item, initial_invoke))

    def stop(self):
        self.running = False
        self.thread.join()

    def tick(self):
        tick_time = current_time()
        cur_list = list(self.work_items)
        for i in range(len(cur_list)):
            work_item = cur_list[i]

            if work_item.last_run_time + work_item.interval < tick_time:
                Timing().start_timing("Engine item " + work_item.name)
                self.current_item = work_item
                self.current_item_log = work_item.name
                self.start_time = current_time()
                if not self.running:
                    return

                result = work_item.action()
                self.current_item = None
                self.current_item_log = ""
                test_time = current_time()
                work_item.last_run_time = test_time
                work_item.last_run_duration = test_time - self.start_time

                if work_item.interval == -1:
                    self.work_items.remove(work_item)

                elif not result:
                    self.work_items.remove(work_item)

                if work_item.name not in self.timing:
                    self.timing[work_item.name] = TimingObject(work_item.name)
                self.timing[work_item.name].add_time(current_time() - self.start_time)
                Timing().stop_timing("Engine item " + work_item.name)
                sleep(0)

        self.own_time.add_time(current_time() - tick_time)
Exemple #5
0
class Peer(TorrentManager):
    @property
    def bitfield(self):
        # Only create a new bitfield when we actually have metadata for it
        if self.__bitfield is None and not self.torrent.is_preparing:
            self.__bitfield = Bitfield(self,
                                       self.torrent.data_manager.total_pieces)
        return self.__bitfield

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, value):
        if self._state != value:
            old = self._state
            self._state = value
            if self.torrent.peer_manager is not None:
                self.torrent.peer_manager.update_peer(self, old, value)

            if value == PeerState.Started:
                self.peer_state_task = CustomThread(
                    self.check_peer_state, "Check peer state " + str(self.id))
                self.peer_state_task.start()

    def __init__(self, id, torrent, uri, source):
        super().__init__(torrent, "Peer " + str(id))
        self.id = id
        self.torrent = torrent
        self.uri = uri
        self._state = PeerState.Initial
        self.source = source

        self.connection_manager = None
        self.download_manager = None
        self.metadata_manager = None
        self.extension_manager = None

        self.__bitfield = None
        self.communication_state = PeerCommunicationState(self)
        self.counter = None
        self.peer_speed = PeerSpeed.Low

        self.allowed_fast_pieces = []

        self.round_trips = 0
        self.round_trip_total = 0
        self.round_trip_average = 0
        self.max_blocks_log = 0
        self.speed_log = 0

        self.peer_start_task = None
        self.peer_state_task = None
        self.peer_stop_task = None

        self.stop_reason = "Torrent stopping"
        self.protocol_logger = ProtocolLogger(self)

    def adjust_round_trip_time(self, time):
        self.round_trips += 1
        self.round_trip_total += time
        self.round_trip_average = self.round_trip_total / self.round_trips

    def start(self):
        Logger().write(LogVerbosity.All, str(self.id) + ' Starting peer')
        self.state = PeerState.Starting

        self.connection_manager = PeerConnectionManager(self, self.uri)
        self.download_manager = PeerDownloadManager(self)
        self.metadata_manager = PeerMetaDataManager(self)
        self.extension_manager = PeerExtensionManager(self)
        self.counter = AverageCounter(self, 3)

        self.peer_start_task = CustomThread(self.connection_manager.start,
                                            "Start peer " + str(self.id))
        self.peer_start_task.start()

        Logger().write(LogVerbosity.Debug, str(self.id) + ' Peer started')

    def update(self):
        self.metadata_manager.update()
        self.download_manager.update()

    def check_peer_state(self):
        zero_speed_checks = 0
        while self.state == PeerState.Started:
            if current_time() - self.connection_manager.connected_on < 20000:
                time.sleep(1)
                continue

            if not self.torrent.peer_manager.should_stop_peers():
                time.sleep(1)
                continue

            if self.counter.total == 0:
                Logger().write(LogVerbosity.Info,
                               str(self.id) + " stopping not downloading peer")
                self.stop_async(
                    "Not downloading"
                )  # Stop since we haven't downloaded anything since connecting
                return

            if self.counter.value == 0:
                zero_speed_checks += 1
                if zero_speed_checks >= 10:
                    Logger().write(
                        LogVerbosity.Info,
                        str(self.id) +
                        " stopping currently not downloading peer")
                    self.stop_async(
                        "Not recently downloading"
                    )  # Stop since we haven't downloaded anything in the last 10 seconds
                    return
            else:
                zero_speed_checks = 0

            time.sleep(1)

    @staticmethod
    def add_connected_peer_stat(source):
        if source == PeerSource.DHT:
            Stats().add('peers_source_dht_connected', 1)
        elif source == PeerSource.HttpTracker:
            Stats().add('peers_source_http_tracker_connected', 1)
        elif source == PeerSource.UdpTracker:
            Stats().add('peers_source_udp_tracker_connected', 1)
        elif source == PeerSource.PeerExchange:
            Stats().add('peers_source_exchange_connected', 1)

    def stop_async(self, reason):
        if self.state != PeerState.Started and self.state != PeerState.Starting:
            return

        self.stop_reason = reason
        self.state = PeerState.Stopping
        self.peer_stop_task = CustomThread(self.stop,
                                           "Peer stopper " + str(self.id), [])
        self.peer_stop_task.start()

    def stop(self):
        if self.state == PeerState.Stopped:
            return

        self.state = PeerState.Stopping
        Logger().write(LogVerbosity.All, str(self.id) + ' Peer stopping')
        if self.peer_state_task is not None:
            self.peer_state_task.join()

        if self.state == PeerState.Stopped:
            return

        self.connection_manager.disconnect()
        self.download_manager.stop()
        self.extension_manager.stop()
        self.metadata_manager.stop()

        self.state = PeerState.Stopped
        self.peer_start_task.join()

        self.protocol_logger = None
        super().stop()
        self.finish()
        Logger().write(LogVerbosity.Debug,
                       str(self.id) + ' Peer stopped: ' + self.stop_reason)
Exemple #6
0
class RuleManager(metaclass=Singleton):
    conditions = {
        1: IsBetweenTimeCondition,
        2: IsPassingTimeCondition,
        3: IsHomeCondition,
        4: OnLeavingHomeCondition,
        5: OnComingHomeCondition
    }
    actions = {
        1: ToggleTradfriGroupAction,
        2: SetTemperatureAction,
        3: ToggleTvAction,
        4: PlayRadioAction
    }

    def __init__(self):
        self.running = False
        self.current_rules = []
        self.check_thread = CustomThread(self.check_rules, "Rule checker")
        self.load_rules()
        enabled = Database().get_stat("rules_enabled")
        self.enabled = bool(enabled)

    def start(self):
        if Settings.get_bool("slave"):
            return

        self.running = True
        self.check_thread.start()

    def stop(self):
        self.running = False
        self.check_thread.join()

    def set_enabled(self, enabled):
        self.enabled = enabled
        Database().update_stat("rules_enabled", enabled)

    def check_rules(self):
        while self.running:
            Logger().write(LogVerbosity.All, "Checking rules")
            for rule in self.current_rules:
                if rule.check():
                    Logger().write(
                        LogVerbosity.Info, "Executing rule " + rule.name +
                        ": " + rule.description)
                    if self.enabled:
                        try:
                            rule.execute()
                        except Exception as e:
                            Logger().write_error(e, "Rule error")
                    Database().update_rule(rule)

            time.sleep(10)

    def update_rule(self, rule_id, active, name, actions, conditions):
        if rule_id == -1:
            rule = Rule(-1, name, current_time(), True, 0)
            self.current_rules.append(rule)
        else:
            rule = [x for x in self.current_rules if x.id == rule_id][0]
        rule.name = name
        rule.active = active
        rule.actions = []
        for action in actions:
            rule.add_action(-1, action[0],
                            [x for x in action[1:] if x is not None])

        rule.conditions = []
        for condition in conditions:
            rule.add_condition(-1, condition[0],
                               [x for x in condition[1:] if x is not None])

        rule.last_execution = 0
        Database().save_rule(rule)

    def remove_rule(self, rule_id):
        self.current_rules = [x for x in self.current_rules if x.id != rule_id]
        Database().remove_rule(rule_id)

    def get_rule(self, rule_id):
        return [x for x in self.current_rules if x.id == rule_id][0]

    def get_rules(self):
        return self.enabled, self.current_rules

    def get_actions_and_conditions(self):
        actions = [
            ActionModel(id, action.name, action.description,
                        action.parameter_descriptions)
            for id, action in self.actions.items()
        ]
        conditions = [
            ActionModel(id, condition.name, condition.description,
                        condition.parameter_descriptions)
            for id, condition in self.conditions.items()
        ]
        return actions, conditions

    def load_rules(self):
        db_rules = Database().get_rules()
        self.current_rules = self.parse_rules(db_rules)

    def parse_rules(self, rules):
        result = []
        for r in rules:
            rule = Rule(r.id, r.name, r.created, r.active, r.last_execution)
            for link in r.links:
                if link.rule_link_type == "Condition":
                    rule.add_condition(link.id, link.link_type,
                                       link.parameters)
                else:
                    rule.add_action(link.id, link.link_type, link.parameters)
            result.append(rule)
        return result

    @staticmethod
    def update_check_time(hour, minute):
        result = datetime.now()
        if result.hour > hour or (result.hour == hour
                                  and result.minute >= minute):
            result += timedelta(days=1)
        result = result.replace(hour=hour,
                                minute=minute,
                                second=0,
                                microsecond=0)
        return result
class PeerConnectionManager(LogObject):

    @property
    def ready_for_sending(self):
        return len(self.to_send_bytes) > 0 and current_time() - self.last_send > 10

    @property
    def ready_for_reading(self):
        return len(self.buffer) >= self._next_message_length

    def __init__(self, peer, uri):
        super().__init__(peer, "connection")

        self.peer = peer
        self.uri = uri
        self.to_send_bytes = bytearray()
        self.last_send = 0
        self.connected_on = 0
        self._last_communication = 0
        self._peer_timeout = Settings.get_int("peer_timeout")
        self._connection_timeout = Settings.get_int("connection_timeout") / 1000

        self.connection = TcpClient(uri.hostname, uri.port, self._connection_timeout)
        self.buffer = bytearray()

        self.buffer_in_size = 0
        self.buffer_out_size = 0

        self._next_message_length = 1
        self._buffer_position = 0
        self._receive_state = ReceiveState.ReceiveLength
        self._receive_buffer_size = 32768

        self.in_thread = None
        self.reading_handshake = True

    def start(self):
        self.connected_on = 0
        Logger().write(LogVerbosity.All, str(self.peer.id) + ' connecting to ' + str(self.uri.netloc))
        Stats().add('peers_connect_try', 1)

        if not self.connection.connect():
            Stats().add('peers_connect_failed', 1)
            if self.peer is not None:
                Logger().write(LogVerbosity.All, str(self.peer.id) + ' could not connect to ' + str(self.uri.netloc))
                self.peer.stop_async("Can't connect")
            return

        if self.peer.state is not PeerState.Starting:
            return

        self.connected_on = current_time()
        self.peer.add_connected_peer_stat(self.peer.source)
        Stats().add('peers_connect_success', 1)
        Logger().write(LogVerbosity.Debug, str(self.peer.id) + ' connected to ' + str(self.uri.netloc))
        self.peer.state = PeerState.Started

        self.in_thread = CustomThread(self.socket_reader, "Peer " + str(self.peer.id) + " input")
        self.in_thread.start()

    def socket_reader(self):
        while self.peer.state == PeerState.Started:
            if len(self.buffer) > 1000000:
                time.sleep(0.01)
                continue

            data = self.connection.receive_available(self._receive_buffer_size)
            if data is None or len(data) == 0:
                self.peer.stop_async("Reading error")
                break

            self._last_communication = current_time()
            self.buffer += data
            self.buffer_in_size = len(self.buffer)
            time.sleep(0.001)

    def handle_read(self):
        received_messages = []
        messages_size = 0

        while True:
            buffer_size = len(self.buffer)
            if buffer_size - self._buffer_position < self._next_message_length:
                # cant read another complete message
                break

            # form messages from the buffer:
            if self._receive_state == ReceiveState.ReceiveLength:
                if self.reading_handshake:
                    offset, id_length = read_byte_as_int(self.buffer, 0)
                    msg_length = id_length + 49  # Handshake sends the length of the id, the rest of the handshake takes 49 bytes
                    if msg_length > len(self.buffer):
                        break
                    self.reading_handshake = False
                else:
                    offset, msg_length = read_integer(self.buffer, self._buffer_position)
                    self._buffer_position += 4

                self._next_message_length = msg_length
                self._receive_state = ReceiveState.ReceiveMessage

                if self._next_message_length < 0 or self._next_message_length > 17000:
                    Logger().write(LogVerbosity.Info, "Invalid next message length: " + str(self._next_message_length))
                    self.peer.stop_async("Invalid next msg length")
                    break
            else:
                total_data = self._buffer_position + self._next_message_length
                message = bytes(self.buffer[self._buffer_position: total_data])
                self._buffer_position = total_data
                self._next_message_length = 4
                self._receive_state = ReceiveState.ReceiveLength
                messages_size += len(message)
                received_messages.append(message)

        self.buffer = self.buffer[self._buffer_position:]
        self._buffer_position = 0
        self.buffer_in_size = len(self.buffer)
        return messages_size, received_messages

    def handle_write(self):
        success = self.connection.send(self.to_send_bytes)
        self.to_send_bytes.clear()
        self.buffer_out_size = 0
        self.last_send = current_time()
        self._last_communication = current_time()

        if not success:
            self.peer.stop_async("Write error")

    def send(self, data):
        self.to_send_bytes.extend(data)
        self.buffer_out_size = len(self.to_send_bytes)

    def disconnect(self):
        if self.connected_on != 0:
            Logger().write(LogVerbosity.Debug, str(self.peer.id) + ' disconnected')

        self.connection.disconnect()
        self.to_send_bytes.clear()

        if self.in_thread is not None:
            self.in_thread.join()
        self.buffer.clear()
        self.peer = None