Beispiel #1
0
class Waiter():
    def __init__(self, event_loop, timeout_msec=-1):
        self._timeout_msec = timeout_msec
        self._event = Subject()
        self._wait_exit = False
        self.result_ob = None
        self._event_loop = event_loop
        self._timer = None

        self.scheduler = AsyncIOScheduler(loop=event_loop)
        self.done = asyncio.Future()

        print('done init')

    def set_timeout(self, timeout_msec):
        self._timeout_msec = timeout_msec

    def _timeout_callback(self):
        print('called _timeout_callback')
        self._event.on_next('timeout')

    async def wait(self):
        if self._timeout_msec > 0:
            self._timer = threading.Timer(self._timeout_msec / 1000,
                                          self._timeout_callback)
            self._timer.start()

        self._wait_exit = False

        def cb_next(data):
            print('received data : {}'.format(data))

            if self._timer:
                self._timer.cancel()

            self._wait_exit = True
            self.done.set_result(data)

        def cb_completed():
            print('received completed')
            self.done.set_result('done')

        #self._event.subscribe(on_next=cb_next, on_completed=cb_completed, scheduler=self.scheduler)
        self._event.subscribe(on_next=cb_next, scheduler=self.scheduler)
        result = await self.done

        print('done wait')
        return result

    def end(self, msg):
        self._event.on_next(msg or 'success')
        self._event.on_completed()
        #self.result_ob.dispose()

    def set_next(self, msg):
        self._event.on_next(msg)
Beispiel #2
0
 def test_base_on_completed(self):
     source = Subject()
     source.pipe(
         trace_observable(prefix='foo',
                          date=datetime.datetime(year=2018, month=8,
                                                 day=3))).subscribe()
     source.on_completed()
     self.assertEqual(
         '2018-08-03 00:00:00:foo - on_subscribe\n'
         '2018-08-03 00:00:00:foo - on_completed\n'
         '2018-08-03 00:00:00:foo - dispose',
         self.out.getvalue().strip())
Beispiel #3
0
                def action(scheduler, state=None):
                    s = None

                    if is_shift:
                        s = Subject()
                        q.append(s)
                        observer.on_next(add_ref(s, ref_count_disposable))

                    if is_span:
                        s = q.pop(0)
                        s.on_completed()

                    create_timer()
Beispiel #4
0
class PlotSaveHandler(rx.core.Observer):

    def __init__(self, cfg: CfgNode, cfg_dir="."):
        super(PlotSaveHandler, self).__init__()
        self.base_path = utils.abs_or_offset_from(cfg.output.base_path, cfg_dir)

        os.makedirs(self.base_path, exist_ok=True)
        os.makedirs(os.path.join(self.base_path, "weights"), exist_ok=True)

        self.e = []
        self.train_loss = []
        self.val_loss = []
        self.plot_sub = Subject()

    def on_next(self, value) -> None:
        e = value["epoch"]
        train_time = value["train_time"]
        val_time = value["valid_time"]
        train_loss = value["train_loss"]
        val_loss = value["valid_loss"]
        net: RamanAINetwork = value["net"]

        print(f"Epoch:{e}, train_loss={train_loss}, val_loss={val_loss}, train_time={train_time}, val_time={val_time}")
        self.e.append(e)
        self.train_loss.append(train_loss)
        self.val_loss.append(val_loss)

        # save
        torch.save(net, os.path.join(self.base_path, "weights", f"weights_{e}.pkl"))

        self.plot_sub.on_next({
            "epoch": self.e,
            "train": self.train_loss,
            "valid": self.val_loss,
            "test_output": value["test_output"],
        })

    def on_error(self, error: Exception) -> None:
        raise error

    def on_completed(self) -> None:
        print("Completed")
        with open(os.path.join(self.base_path, f"loss.csv"), "w", newline='') as f:
            writer = csv.writer(f)
            writer.writerow(["Epoch", "Train", "Valid"])
            for e, t, v, in zip(self.e, self.train_loss, self.val_loss):
                writer.writerow([e, t, v])

        self.plot_sub.on_completed()
Beispiel #5
0
def main():
    key="z"
    subject_test = Subject()
    initKeyMonitoring(subject_test)
    subject_test.on_next(key)
    print("here")
    time.sleep(2)

    subject_test.on_next(key)
    print("here")
    time.sleep(2)
    
    subject_test.on_next(key)
    print("here")
    time.sleep(2)
    subject_test.on_completed()
Beispiel #6
0
def main():
    key = "space"
    keyTwo = "a"
    subject_test = Subject()
    initKeyMonitoring(subject_test)
    subject_test.on_next(keyTwo)
    print("here")
    time.sleep(1)

    subject_test.on_next(key)
    print("here")
    time.sleep(1)

    subject_test.on_next(keyTwo)
    print("here")
    time.sleep(1)
    subject_test.on_completed()
Beispiel #7
0
class MidiReceiver(threading.Thread):
    def __init__(self, port):
        super().__init__(daemon=True)
        self.stop_flag = False
        self.message = Subject()
        self.clock_found = Subject()
        self.clock = Subject()
        self.clock_lost = Subject()
        self.clock_set = Subject()
        self.clocks_received = None
        self.last_clock_time = None
        self.port_name = port
        self.port = mido.open_input(port)

    def run(self):
        for message in self.port:
            if message.type == 'songpos':
                self.clock_set.on_next(message.pos * 24)
                print('{}: MIDI clock set: {}'.format(self.port_name, message.pos))
            elif message.type == 'clock':
                if not self.last_clock_time:
                    self.clock_found.on_next(None)
                    self.clocks_received = 0
                    print('{}: MIDI clock found'.format(self.port_name))
                self.clocks_received += 1
                self.clock.on_next(None)
                self.last_clock_time = time.time()
            else:
                self.message.on_next(message)
                print('{} -> {}'.format(self.port_name, message))

            if self.stop_flag:
                break

            if self.last_clock_time and time.time() - self.last_clock_time > 1:
                self.last_clock_time = None
                self.clock_lost.on_next(None)
                self.clocks_received = None
                print('{}: MIDI clock lost'.format(self.port_name))

    def stop(self):
        self.stop_flag = True
        self.message.on_completed()
        if self.last_clock_time:
            self.clock_lost.on_next(None)
Beispiel #8
0
class BackPressurePublisher(DefaultPublisherSubscription):
    def __init__(self, wrapped_observable: Observable):
        self._wrapped_observable = wrapped_observable
        self._feedback = None

    def subscribe(self, subscriber: Subscriber):
        super().subscribe(subscriber)
        self._feedback = Subject()
        async_iterator = observable_to_async_event_generator(
            self._wrapped_observable).__aiter__()
        from_aiter(async_iterator,
                   self._feedback).subscribe(SubscriberAdapter(subscriber))

    def request(self, n: int):
        for i in range(n):
            self._feedback.on_next(True)

    def cancel(self):
        self._feedback.on_completed()
class DeviceSniffer:
    def __init__(self, user_querier: UserQuerier, interface="mon0"):
        self.async_sniffer = AsyncSniffer(prn=self.handle_packet,
                                          store=False,
                                          iface=interface,
                                          monitor=True)
        self.device_dectect_stream = Subject()
        self.user_querier = user_querier

    def __del__(self):
        self.device_dectect_stream.on_completed()

    @staticmethod
    def is_probe_request(packet: Packet):
        return packet.type == 0 and packet.subtype == 4

    def handle_packet(self, packet: Packet):
        if not DeviceSniffer.is_probe_request(packet):
            return

        try:
            target_ssid = packet.getlayer(Dot11Elt).getfieldval("info").decode(
                "utf-8")
            if len(target_ssid) == 0:
                return

            source_mac_addr = packet.addr2.upper()
            userid = self.user_querier.get_userid(target_ssid, source_mac_addr)
            if userid is not None:
                self.device_dectect_stream.on_next(userid)

        except Exception as err:
            self.device_dectect_stream.on_error(err)

    def get_observable(self) -> Subject:
        return self.device_dectect_stream

    def start(self):
        self.async_sniffer.start()

    def stop(self):
        self.async_sniffer.stop()
Beispiel #10
0
class Lines:
    def __init__(self, chat_config):
        self.lines = []
        self.added = Subject()
        self.removed = Subject()
        self._config = chat_config

    @property
    def _max_lines(self):
        return self._config["max_messages_in_channel"]

    @property
    def _remove_batch(self):
        return self._config["message_trim_batch_size"]

    def __getitem__(self, n):
        return self.lines[n]

    def __iter__(self):
        return iter(self.lines)

    def __len__(self):
        return len(self.lines)

    def add(self, line):
        self.lines.append(line)
        self.added.on_next(line)
        self._check_trim()

    def clear(self):
        ll = len(self)
        self.lines.clear()
        self.removed.on_next(ll)

    def _check_trim(self):
        if len(self) > self._max_lines:
            self.lines = self.lines[self._remove_batch:]
            self.removed.on_next(self._remove_batch)

    def complete(self):
        self.added.on_completed()
        self.removed.on_completed()
Beispiel #11
0
class ModelSet(Mapping):
    def __init__(self):
        Mapping.__init__(self)
        self._items = {}
        self.added = Subject()
        self.removed = Subject()
        self.cleared = Subject()

    def __getitem__(self, item):
        return self._items[item]

    def __len__(self):
        return len(self._items)

    def __iter__(self):
        return iter(self._items)

    def add(self, item):
        self._items[item.id_key] = item

    def remove(self, item):
        del self._items[item.id_key]

    def clear(self):
        self._items.clear()

    def complete(self):
        self.added.on_completed()
        self.removed.on_completed()
        self.cleared.on_completed()
Beispiel #12
0
class Inquiry:

    def __init__(self, target: InstanceReference, timeout = 10):
        self.id = uuid.uuid4().bytes
        self.target = target
        self.time = time.time()
        self.complete = Subject()

        self.timer = Timer(timeout, self.__timeout)
        self.timer.start()

    def response_received(self) -> float:
        self.timer.cancel()
        delay = time.time() - self.time

        self.complete.on_next(delay)
        self.complete.on_completed()

        return delay

    def __timeout(self):
        Log.warn("Inquiry timed out")
        self.complete.on_error(TimeoutError("The inquiry timed out."))
Beispiel #13
0
class Player(ModelItem):
    def __init__(self, current_player_game, login):
        ModelItem.__init__(self)
        self._current_player_game = current_player_game

        self.login = login
        self._add_obs("id", 0)
        self._add_obs("global_rating", (1500, 500))
        self._add_obs("ladder_rating", (1500, 500))
        self._add_obs("number_of_games", 0)
        self._add_obs("avatar")
        self._add_obs("country")
        self._add_obs("clan")
        self._add_obs("league")

        self.obs_game = Subject()

    # The game this player is currently playing.
    @property
    def game(self):
        return self._current_player_game.get(self.id_key)

    def complete(self):
        ModelItem.complete(self)
        self.obs_game.on_completed()

    @property
    def rating_estimate(self):
        "Conservative estimate of the players global trueskill rating."
        return max(0, (self.global_rating[0] - 3 * self.global_rating[1]))

    # Unfortunately, games refer to players by login.
    # I have no idea how this plays with renaming, hopefully the server doesn't
    # change player names mid-session
    @property
    def id_key(self):
        return self.login
Beispiel #14
0
# 操作数据流
print('求所有偶数')
some_data = rx.of(1, 2, 3, 4, 5, 6, 7, 8)
some_data2 = rx.from_iterable(range(10, 20))
some_data.pipe(
    op.merge(some_data2),
    op.filter(lambda i: i % 2 == 0),
    # op.map(lambda i: i * 2)
).subscribe(lambda i: print(i))

# debounce操作符,仅在时间间隔之外的可以发射
print('防止重复发送')
ob = Subject()
ob.pipe(
    op.throttle_first(3)
    # op.debounce(3)
).subscribe(
    on_next=lambda i: print(i),
    on_completed=lambda: print('Completed')
)

print('press enter to print, press other key to exit')
while True:
    s = input()
    if s == '':
        ob.on_next(datetime.datetime.now().time())
    else:
        ob.on_completed()
        break
Beispiel #15
0
import rx
import rx.operators as ops
from rx.subject import Subject

first = Subject()
second = Subject()

first.pipe(ops.amb(second)).subscribe(
    on_next=lambda i: print("on_next {}".format(i)),
    on_error=lambda e: print("on_error: {}".format(e)),
    on_completed=lambda: print("on_completed")
)

first.on_next(1)
second.on_next(2)
first.on_completed()
Beispiel #16
0
class WriteApi(AbstractClient):
    def __init__(
        self, influxdb_client,
        write_options: WriteOptions = WriteOptions()) -> None:
        self._influxdb_client = influxdb_client
        self._write_service = WriteService(influxdb_client.api_client)
        self._write_options = write_options
        if self._write_options.write_type is WriteType.batching:
            # Define Subject that listen incoming data and produces writes into InfluxDB
            self._subject = Subject()

            # Define a scheduler that is used for processing incoming data - default singleton
            observable = self._subject.pipe(
                ops.observe_on(self._write_options.write_scheduler))
            self._disposable = observable \
                .pipe(  # Split incoming data to windows by batch_size or flush_interval
                    ops.window_with_time_or_count(count=write_options.batch_size,
                                                  timespan=timedelta(milliseconds=write_options.flush_interval)),
                    # Map incoming batch window in groups defined by 'organization', 'bucket' and 'precision'
                    ops.flat_map(lambda v: _window_to_group(v)),
                    # Write data into InfluxDB (possibility to retry if its fail)
                    ops.map(mapper=lambda batch: self._retryable(data=batch, delay=self._jitter_delay())),  #
                    ops.merge_all()) \
                .subscribe(self._on_next, self._on_error, self._on_complete)
        else:
            self._subject = None
            self._disposable = None

    def write(
            self,
            bucket: str,
            org: str,
            record: Union[str, List['str'], Point, List['Point'], dict,
                          List['dict'], bytes, List['bytes'], Observable],
            write_precision: WritePrecision = DEFAULT_WRITE_PRECISION) -> None:
        """
        Writes time-series data into influxdb.

        :param str org: specifies the destination organization for writes; take either the ID or Name interchangeably; if both orgID and org are specified, org takes precedence. (required)
        :param str bucket: specifies the destination bucket for writes (required)
        :param WritePrecision write_precision: specifies the precision for the unix timestamps within the body line-protocol
        :param record: Points, line protocol, RxPY Observable to write

        """

        if self._write_options.write_type is WriteType.batching:
            return self._write_batching(bucket, org, record, write_precision)

        final_string = self._serialize(record, write_precision)

        _async_req = True if self._write_options.write_type == WriteType.asynchronous else False

        return self._post_write(_async_req, bucket, org, final_string,
                                write_precision)

    def flush(self):
        # TODO
        pass

    def __del__(self):
        if self._subject:
            self._subject.on_completed()
            self._subject.dispose()
            self._subject = None

            # Wait for finish writing
            while not self._disposable.is_disposed:
                sleep(0.1)

        if self._disposable:
            self._disposable = None
        pass

    def _serialize(self, record, write_precision) -> bytes:
        _result = b''
        if isinstance(record, bytes):
            _result = record

        elif isinstance(record, str):
            _result = record.encode("utf-8")

        elif isinstance(record, Point):
            _result = self._serialize(record.to_line_protocol(),
                                      write_precision=write_precision)

        elif isinstance(record, dict):
            _result = self._serialize(Point.from_dict(
                record, write_precision=write_precision),
                                      write_precision=write_precision)
        elif isinstance(record, list):
            _result = b'\n'.join([
                self._serialize(item, write_precision=write_precision)
                for item in record
            ])

        return _result

    def _write_batching(self,
                        bucket,
                        org,
                        data,
                        precision=DEFAULT_WRITE_PRECISION):
        _key = _BatchItemKey(bucket, org, precision)
        if isinstance(data, bytes):
            self._subject.on_next(_BatchItem(key=_key, data=data))

        elif isinstance(data, str):
            self._write_batching(bucket, org, data.encode("utf-8"), precision)

        elif isinstance(data, Point):
            self._write_batching(bucket, org, data.to_line_protocol(),
                                 precision)

        elif isinstance(data, dict):
            self._write_batching(
                bucket, org, Point.from_dict(data, write_precision=precision),
                precision)

        elif isinstance(data, list):
            for item in data:
                self._write_batching(bucket, org, item, precision)

        elif isinstance(data, Observable):
            data.subscribe(
                lambda it: self._write_batching(bucket, org, it, precision))
            pass

        return None

    def _http(self, batch_item: _BatchItem):

        logger.debug("http post to: %s", batch_item)

        self._post_write(False, batch_item.key.bucket, batch_item.key.org,
                         batch_item.data, batch_item.key.precision)

        return _BatchResponse(data=batch_item)

    def _post_write(self, _async_req, bucket, org, body, precision):
        return self._write_service.post_write(
            org=org,
            bucket=bucket,
            body=body,
            precision=precision,
            async_req=_async_req,
            content_encoding="identity",
            content_type="text/plain; charset=utf-8")

    def _retryable(self, data: str, delay: timedelta):

        return rx.of(data).pipe(
            # use delay if its specified
            ops.delay(duetime=delay,
                      scheduler=self._write_options.write_scheduler),
            # invoke http call
            ops.map(lambda x: self._http(x)),
            # if there is an error than retry
            ops.catch(handler=lambda exception, source: self._retry_handler(
                exception, source, data)),
        )

    def _retry_handler(self, exception, source, data):

        if isinstance(exception, ApiException):

            if exception.status == 429 or exception.status == 503:
                _delay = self._jitter_delay() + timedelta(
                    milliseconds=self._write_options.retry_interval)
                return self._retryable(data, delay=_delay)

        return rx.just(_BatchResponse(exception=exception, data=data))

    def _jitter_delay(self):
        return timedelta(milliseconds=random() *
                         self._write_options.jitter_interval)

    @staticmethod
    def _on_next(response: _BatchResponse):
        if response.exception:
            logger.error(
                "The batch item wasn't processed successfully because: %s",
                response.exception)
        else:
            logger.debug("The batch item: %s was processed successfully.",
                         response)

    @staticmethod
    def _on_error(ex):
        logger.error("unexpected error during batching: %s", ex)

    def _on_complete(self):
        self._disposable.dispose()
        logger.info("the batching processor was disposed")
Beispiel #17
0
class Context:
    def __init__(self, config_path: str):
        deepkit.globals.last_context = self
        self.log_lock = Lock()
        self.defined_metrics = {}
        self.log_subject = Subject()
        self.metric_subject = Subject()
        self.speed_report_subject = Subject()

        self.client = deepkit.client.Client(config_path)
        self.wait_for_connect()
        atexit.register(self.shutdown)

        self.last_iteration_time = 0
        self.last_batch_time = 0
        self.job_iteration = 0
        self.job_iterations = 0
        self.seconds_per_iteration = 0
        self.seconds_per_iterations = []
        self.debugger_controller = None

        if deepkit.utils.in_self_execution():
            self.job_controller = JobController()

        self.debugger_controller = JobDebuggerController()

        def on_connect(connected):
            if connected:
                if deepkit.utils.in_self_execution():
                    asyncio.run_coroutine_threadsafe(
                        self.client.register_controller(
                            'job/' + self.client.job_id, self.job_controller),
                        self.client.loop)

                asyncio.run_coroutine_threadsafe(
                    self.client.register_controller(
                        'job/' + self.client.job_id + '/debugger',
                        self.debugger_controller), self.client.loop)

        self.client.connected.subscribe(on_connect)

        def on_log(data: List):
            if len(data) == 0: return
            packed = ''
            for d in data:
                packed += d

            self.client.job_action('log', ['main_0', packed])

        self.log_subject.pipe(buffer(interval(1))).subscribe(on_log)

        if len(deepkit.globals.last_logs.getvalue()) > 0:
            self.log_subject.on_next(deepkit.globals.last_logs.getvalue())

        def on_metric(data: List):
            if len(data) == 0: return
            packed = {}

            for d in data:
                if d['id'] not in packed:
                    packed[d['id']] = []

                packed[d['id']].append(d['row'])

            for i, v in packed.items():
                self.client.job_action('channelData', [i, v])

        self.metric_subject.pipe(buffer(interval(1))).subscribe(on_metric)

        def on_speed_report(rows):
            # only save latest value, each second
            if len(rows) == 0: return
            self.client.job_action('streamJsonFile',
                                   ['.deepkit/speed.csv', [rows[-1]]])

        self.speed_report_subject.pipe(buffer(
            interval(1))).subscribe(on_speed_report)

        p = psutil.Process()
        self.client.job_action('streamJsonFile', [
            '.deepkit/hardware/main_0.csv',
            [[
                'time', 'cpu', 'memory', 'network_rx', 'network_tx',
                'block_write', 'block_read'
            ]]
        ])

        def on_hardware_metrics(dummy):
            net = psutil.net_io_counters()
            disk = psutil.disk_io_counters()
            data = [
                time.time(),
                (p.cpu_percent(interval=None) / 100) / psutil.cpu_count(),
                p.memory_percent() / 100,
                net.bytes_recv,
                net.bytes_sent,
                disk.write_bytes,
                disk.read_bytes,
            ]
            self.client.job_action('streamJsonFile',
                                   ['.deepkit/hardware/main_0.csv', [data]])

        interval(1).subscribe(on_hardware_metrics)

    def wait_for_connect(self):
        async def wait():
            await self.client.connecting

        asyncio.run_coroutine_threadsafe(wait(), self.client.loop).result()

    def shutdown(self):
        self.metric_subject.on_completed()
        self.log_subject.on_completed()

        self.client.shutdown()

    def epoch(self, current: int, total: Optional[int]):
        self.iteration(current, total)

    def iteration(self, current: int, total: Optional[int]):
        self.job_iteration = current
        if total:
            self.job_iterations = total

        now = time.time()
        if self.last_iteration_time:
            self.seconds_per_iterations.append({
                'diff': now - self.last_iteration_time,
                'when': now,
            })

        self.last_iteration_time = now
        self.last_batch_time = now

        # remove all older than twenty seconds
        self.seconds_per_iterations = [
            x for x in self.seconds_per_iterations if (now - x['when']) < 20
        ]
        self.seconds_per_iterations = self.seconds_per_iterations[-30:]

        if len(self.seconds_per_iterations) > 0:
            diffs = [x['diff'] for x in self.seconds_per_iterations]
            self.seconds_per_iteration = sum(diffs) / len(diffs)

        if self.seconds_per_iteration:
            self.client.patch('secondsPerIteration',
                              self.seconds_per_iteration)

        self.client.patch('iteration', self.job_iteration)
        if total:
            self.client.patch('iterations', self.job_iterations)

        iterations_left = self.job_iterations - self.job_iteration
        if iterations_left > 0:
            self.client.patch('eta',
                              self.seconds_per_iteration * iterations_left)
        else:
            self.client.patch('eta', 0)

    def step(self, current: int, total: int = None, size: int = None):
        self.client.patch('step', current)
        now = time.time()

        x = self.job_iteration + (current / total)
        speed_per_second = size / (
            now - self.last_batch_time) if self.last_batch_time else size

        if self.last_batch_time:
            self.seconds_per_iterations.append({
                'diff': (now - self.last_batch_time) * total,
                'when':
                now
            })

        # remove all older than twenty seconds
        self.seconds_per_iterations = [
            x for x in self.seconds_per_iterations if (now - x['when']) < 20
        ]
        self.seconds_per_iterations = self.seconds_per_iterations[-30:]

        if len(self.seconds_per_iterations) > 0:
            diffs = [x['diff'] for x in self.seconds_per_iterations]
            self.seconds_per_iteration = sum(diffs) / len(diffs)

            iterations_left = self.job_iterations - self.job_iteration
            self.client.patch('eta',
                              self.seconds_per_iteration * iterations_left)

        self.last_batch_time = now

        if self.seconds_per_iteration:
            self.client.patch('secondsPerIteration',
                              self.seconds_per_iteration)

        self.client.patch('speed', speed_per_second)
        self.speed_report_subject.on_next([x, now, speed_per_second])

        if total:
            self.client.patch('steps', total)

    def set_title(self, s: str):
        self.client.patch('title', s)

    def set_info(self, name: str, value: any):
        self.client.patch('infos.' + name, value)

    def set_description(self, description: any):
        self.client.patch('description', description)

    def add_tag(self, tag: str):
        self.client.job_action('addTag', [tag])

    def rm_tag(self, tag: str):
        self.client.job_action('rmTag', [tag])

    def set_parameter(self, name: str, value: any):
        self.client.patch('config.parameters.' + name, value)

    def define_metric(self, name: str, options: dict):
        self.defined_metrics[name] = {}
        self.client.job_action('defineMetric', [name, options])

    def debug_snapshot(self, graph: dict):
        self.client.job_action('debugSnapshot', [graph])

    def add_file(self, path: str):
        self.client.job_action(
            'uploadFile',
            [path,
             base64.b64encode(open(path, 'rb').read()).decode('utf8')])

    def add_file_content(self, path: str, content: bytes):
        self.client.job_action(
            'uploadFile',
            [path, base64.b64encode(content).decode('utf8')])

    def set_model_graph(self, graph: dict):
        self.client.job_action('setModelGraph', [graph])

    def metric(self, name: str, x, y):
        if name not in self.defined_metrics:
            self.define_metric(name, {})

        if not isinstance(y, list):
            y = [y]

        self.metric_subject.on_next({'id': name, 'row': [x, time.time()] + y})
        self.client.patch('channels.' + name + '.lastValue', y)

    def log(self, s: str):
        self.log_subject.on_next(s)
Beispiel #18
0
import rx
from rx.subject import Subject, AsyncSubject, BehaviorSubject, ReplaySubject

# Subject同时是Observer和Observable

print('--------Subject---------')
subject = Subject()
subject.on_next(1)
subject.subscribe(lambda i: print(i))
subject.on_next(2)
subject.on_next(3)
subject.on_next(4)
subject.on_completed()

# ReplaySubject会缓存所有值,如果指定参数的话只会缓存最近的几个值
print('--------ReplaySubject---------')
subject = ReplaySubject()
subject.on_next(1)
subject.subscribe(lambda i: print(i))
subject.on_next(2)
subject.on_next(3)
subject.on_next(4)
subject.on_completed()

# BehaviorSubject会缓存上次发射的值,除非Observable已经关闭
print('--------BehaviorSubject---------')
subject = BehaviorSubject(0)
subject.on_next(1)
subject.on_next(2)
subject.subscribe(lambda i: print(i))
subject.on_next(3)
import rx
import rx.operators as ops
from rx.subject import Subject

numbers = Subject()
trigger = Subject()

numbers.pipe(ops.skip_until(trigger)).subscribe(
    on_next=lambda i: print("on_next {}".format(i)),
    on_error=lambda e: print("on_error: {}".format(e)),
    on_completed=lambda: print("on_completed")
)

numbers.on_next(1)
numbers.on_next(2)
trigger.on_next(True)
numbers.on_next(3)
numbers.on_next(4)
numbers.on_completed()
class _RxWriter(object):
    success_count = 0
    failed_count = 0
    raise_retry_exception = 0

    def __init__(self) -> None:
        self._subject = Subject()
        self._scheduler = ThreadPoolScheduler(max_workers=1)
        obs = self._subject.pipe(ops.observe_on(self._scheduler))
        self._disposable = obs \
            .pipe(ops.window_with_time_or_count(count=5, timespan=datetime.timedelta(milliseconds=10_000)),
                  ops.flat_map(lambda x: self._window_to_group(x)),
                  ops.map(mapper=lambda x: self._retryable(data=x, delay=self._jitter_delay(jitter_interval=1000))),
                  ops.merge_all()) \
            .subscribe(self._result, self._error, self._on_complete)
        pass

    def __del__(self):
        if self._subject:
            self._subject.on_completed()
            self._subject.dispose()
            self._subject = None

            while not self._disposable.is_disposed:
                time.sleep(0.1)

        if self._disposable:
            self._disposable = None
        pass

    def _window_to_group(self, value):
        return value.pipe(
            ops.to_iterable(),
            ops.map(lambda x: rx.from_iterable(x).pipe(
                ops.group_by(_group_by), ops.map(_group_to_batch), ops.merge_all())),
            ops.merge_all())

    def _retryable(self, data: str, delay: datetime.timedelta):

        return rx.of(data).pipe(
            ops.delay(duetime=delay, scheduler=self._scheduler),
            ops.map(lambda x: self._http(x)),
            ops.catch(handler=lambda exception, source: self._retry_handler(exception, source, data)),
        )

    def _http(self, data: str):
        if "gamma" in data:
            print('bad request[{}]: {}'.format(current_thread().name, data))
            raise Exception('unexpected token: {}'.format(data))
            pass

        if "alpha" in data:
            if self.raise_retry_exception < 2:
                self.raise_retry_exception += 1
                print('server is temporarily unavailable to accept writes[{}]: {}'.format(current_thread().name, data))
                raise Exception('server is temporarily unavailable to accept writes: {}'.format(data))
            else:
                print("server is OK: {}".format(datetime.datetime.now()))
            pass

        print("http[" + current_thread().name + "]: " + data)
        return _Notification(data=data)

    def write(self, data: str):
        print("write[" + current_thread().name + "]")
        self._subject.on_next(data)
        pass

    def _result(self, data: _Notification):
        print("result[" + current_thread().name + "]: " + str(data))
        if data.exception:
            self.failed_count += 1
        else:
            self.success_count += 1
        pass

    def _error(self, error):
        print(error)

    def _on_complete(self):
        self._disposable.dispose()
        print("on complete")

    def _jitter_delay(self, jitter_interval=0):
        _jitter = datetime.timedelta(milliseconds=random() * jitter_interval)
        print('jitter: {}'.format(_jitter))
        return _jitter

    def _retry_handler(self, exception, source, data):
        print('retry_handler: {}, source: {}'.format(exception, source))

        if "server is temporarily" in str(exception):
            print("RETRY!!!: {}".format(datetime.datetime.now()))
            return self._retryable(data, delay=datetime.timedelta(seconds=2))

        notification = _Notification(exception=exception, data=data)

        return rx.just(notification)
Beispiel #21
0
class TimeCertificateBuilder:
    def __init__(self,
                 trust_set: TrustSet,
                 trust_set_key: VerifyKey,
                 digest: bytes,
                 timeout: int = -1):
        # Save the paramaters
        self.trust_set = trust_set
        self.trust_set_key = trust_set_key
        self.timeout = timeout
        self.signatures: Set[TimeSignature] = set()
        self.result = Subject()
        self.digest = digest

        if (self.timeout == -1):
            self.timeout = trust_set.maximum_deviation

        self.__timer = None
        self.__complete = False

    def add_signature(self, signature: TimeSignature):
        # Do we have a timer?
        if (self.__timer == None):
            # No, create it
            self.__timer = Timer(self.timeout, self.__finalise)
            self.__timer.start()

        # Have we timed out?
        if (self.__complete):
            # Don't do anything
            return

        # Is the signature valid for this trust set?
        if (signature.public_key.encode()
                not in self.trust_set.valid_key_data):
            # Drop it
            return

        # Add to the signature set
        self.signatures.add(signature)

        # Have we got all the signatures?
        if (len(self.signatures) == len(self.trust_set.valid_keys)):
            # Yes, cancel timer and finalise
            self.__timer.cancel()
            self.__finalise()

    def __finalise(self):
        # We are complete
        self.__complete = True

        # Do we have enough signatures?
        if (len(self.signatures) < self.trust_set.required_signatures):
            # No, return error
            self.result.on_error(
                Exception(
                    "Could not get required number of signatures in time"))
            return

        # We have enough signatures for a certificate, build it
        certificate = TimeCertificate(self.trust_set, self.trust_set_key,
                                      self.signatures)

        # Verify the certificate
        try:
            certificate.validate(self.digest)
        except Exception as e:
            self.result.on_error(e)
            return

        # Send to the observer
        self.result.on_next(certificate)
        self.result.on_completed()
Beispiel #22
0
class Context:
    def __init__(self, options: ContextOptions = None):
        if options is None:
            options = ContextOptions()

        self.client = deepkit.client.Client(options)
        deepkit.globals.last_context = self
        self.log_lock = Lock()
        self.defined_metrics = {}
        self.log_subject = Subject()
        self.metric_subject = Subject()
        self.speed_report_subject = Subject()
        self.shutting_down = False

        atexit.register(self.shutdown)
        self.wait_for_connect()

        self.last_iteration_time = 0
        self.last_batch_time = 0
        self.job_iteration = 0
        self.job_iterations = 0
        self.seconds_per_iteration = 0
        self.seconds_per_iterations = []
        self.debugger_controller = None

        if deepkit.utils.in_self_execution():
            self.job_controller = JobController()

        self.debugger_controller = JobDebuggerController()

        def on_connect(connected):
            if connected:
                if deepkit.utils.in_self_execution():
                    asyncio.run_coroutine_threadsafe(
                        self.client.register_controller(
                            'job/' + self.client.job_id, self.job_controller),
                        self.client.loop)

                asyncio.run_coroutine_threadsafe(
                    self.client.register_controller(
                        'job/' + self.client.job_id + '/debugger',
                        self.debugger_controller), self.client.loop)

        self.client.connected.subscribe(on_connect)

        def on_metric(data: List):
            if len(data) == 0: return

            packed = {}
            for d in data:
                if d['id'] not in packed:
                    packed[d['id']] = b''

                packed[d['id']] += d['row']

            for i, v in packed.items():
                self.client.job_action(
                    'channelData', [i, base64.b64encode(v).decode('utf8')])

        self.metric_subject.pipe(buffer(interval(1))).subscribe(on_metric)

        def on_speed_report(rows):
            # only save latest value, each second
            if len(rows) == 0: return
            self.client.job_action('streamFile', [
                '.deepkit/speed.metric',
                base64.b64encode(rows[-1]).decode('utf8')
            ])

        self.speed_report_subject.pipe(buffer(
            interval(1))).subscribe(on_speed_report)

        if deepkit.utils.in_self_execution:
            # the CLI handled output logging otherwise
            def on_log(data: List):
                if len(data) == 0: return
                packed = ''
                for d in data:
                    packed += d

                self.client.job_action('log', ['main_0', packed])

            self.log_subject.pipe(buffer(interval(1))).subscribe(on_log)

            if len(deepkit.globals.last_logs.getvalue()) > 0:
                self.log_subject.on_next(deepkit.globals.last_logs.getvalue())

        if deepkit.utils.in_self_execution:
            # the CLI handled output logging otherwise
            p = psutil.Process()

            def on_hardware_metrics(dummy):
                net = psutil.net_io_counters()
                disk = psutil.disk_io_counters()
                data = struct.pack(
                    '<BHdHHffff',
                    1,
                    0,
                    time.time(),
                    int(((p.cpu_percent(interval=None) / 100) /
                         psutil.cpu_count()) *
                        65535),  # stretch to max precision of uint16
                    int((p.memory_percent() / 100) *
                        65535),  # stretch to max precision of uint16
                    float(net.bytes_recv),
                    float(net.bytes_sent),
                    float(disk.write_bytes),
                    float(disk.read_bytes),
                )

                self.client.job_action('streamFile', [
                    '.deepkit/hardware/main_0.hardware',
                    base64.b64encode(data).decode('utf8')
                ])

            interval(1).subscribe(on_hardware_metrics)

    def wait_for_connect(self):
        async def wait():
            await self.client.connecting

        asyncio.run_coroutine_threadsafe(wait(), self.client.loop).result()

    def shutdown(self):
        if self.shutting_down: return
        self.shutting_down = True
        self.metric_subject.on_completed()
        self.log_subject.on_completed()

        self.client.shutdown()

    def epoch(self, current: int, total: Optional[int]):
        self.iteration(current, total)

    def iteration(self, current: int, total: Optional[int]):
        self.job_iteration = current
        if total:
            self.job_iterations = total

        now = time.time()
        if self.last_iteration_time:
            self.seconds_per_iterations.append({
                'diff': now - self.last_iteration_time,
                'when': now,
            })

        self.last_iteration_time = now
        self.last_batch_time = now

        # remove all older than twenty seconds
        self.seconds_per_iterations = [
            x for x in self.seconds_per_iterations if (now - x['when']) < 20
        ]
        self.seconds_per_iterations = self.seconds_per_iterations[-30:]

        if len(self.seconds_per_iterations) > 0:
            diffs = [x['diff'] for x in self.seconds_per_iterations]
            self.seconds_per_iteration = sum(diffs) / len(diffs)

        if self.seconds_per_iteration:
            self.client.patch('secondsPerIteration',
                              self.seconds_per_iteration)

        self.client.patch('iteration', self.job_iteration)
        if total:
            self.client.patch('iterations', self.job_iterations)

        iterations_left = self.job_iterations - self.job_iteration
        if iterations_left > 0:
            self.client.patch('eta',
                              self.seconds_per_iteration * iterations_left)
        else:
            self.client.patch('eta', 0)

    def step(self, current: int, total: int = None, size: int = None):
        self.client.patch('step', current)
        now = time.time()

        x = self.job_iteration + (current / total)
        speed_per_second = size / (
            now - self.last_batch_time) if self.last_batch_time else size

        if self.last_batch_time:
            self.seconds_per_iterations.append({
                'diff': (now - self.last_batch_time) * total,
                'when':
                now
            })

        # remove all older than twenty seconds
        self.seconds_per_iterations = [
            x for x in self.seconds_per_iterations if (now - x['when']) < 20
        ]
        self.seconds_per_iterations = self.seconds_per_iterations[-30:]

        if len(self.seconds_per_iterations) > 0:
            diffs = [x['diff'] for x in self.seconds_per_iterations]
            self.seconds_per_iteration = sum(diffs) / len(diffs)

            iterations_left = self.job_iterations - self.job_iteration
            self.client.patch('eta',
                              self.seconds_per_iteration * iterations_left)

        self.last_batch_time = now

        if self.seconds_per_iteration:
            self.client.patch('secondsPerIteration',
                              self.seconds_per_iteration)

        self.client.patch('speed', speed_per_second)

        speed = struct.pack('<Bddd', 1, float(x), now, float(speed_per_second))
        self.speed_report_subject.on_next(speed)

        if total:
            self.client.patch('steps', total)

    def set_title(self, s: str):
        self.client.patch('title', s)

    def set_info(self, name: str, value: any):
        self.client.patch('infos.' + str(name), value)

    def set_description(self, description: any):
        self.client.patch('description', description)

    def add_tag(self, tag: str):
        self.client.job_action('addTag', [tag])

    def rm_tag(self, tag: str):
        self.client.job_action('rmTag', [tag])

    def set_parameter(self, name: str, value: any):
        self.client.patch('config.parameters.' + name, value)

    def define_metric(self, name: str, options: dict):
        self.defined_metrics[name] = {}
        self.client.job_action('defineMetric', [name, options])

    def debug_snapshot(self, graph: dict):
        self.client.job_action('debugSnapshot', [graph])

    def add_file(self, path: str):
        self.client.job_action(
            'uploadFile',
            [path,
             base64.b64encode(open(path, 'rb').read()).decode('utf8')])

    def add_file_content(self, path: str, content: bytes):
        self.client.job_action(
            'uploadFile',
            [path, base64.b64encode(content).decode('utf8')])

    def set_model_graph(self, graph: dict):
        self.client.job_action('setModelGraph', [graph])

    def metric(self, name: str, x, y):
        if name not in self.defined_metrics:
            self.define_metric(name, {})

        if not isinstance(y, list):
            y = [y]

        row_binary = struct.pack('<BHdd', 1, len(y), float(x), time.time())
        for y1 in y:
            row_binary += struct.pack('<d',
                                      float(y1) if y1 is not None else 0.0)

        self.metric_subject.on_next({'id': name, 'row': row_binary})
        self.client.patch('channels.' + name + '.lastValue', y)

    def log(self, s: str):
        self.log_subject.on_next(s)
Beispiel #23
0
class RPP:

    def __init__(self, muxer: MX2, discoverer: AIP, is_repeater: bool = False):
        self.__muxer = muxer
        self.__discoverer = discoverer

        self.is_repeater = is_repeater
        self.instance_info: Dict[InstanceReference, PeerInfo] = {}
        self.instance_network: Dict[InstanceReference, Network] = {}
        self.__announced_instances: Set[InstanceReference] = set()

        # Create instance 
        self.__instance = self.__muxer.create_instance(RPP_NAMESPACE)

        # Create transport
        self.__transport = STP(self.__muxer, self.__instance)

        # Create application information
        self.__info = ApplicationInformation.from_instance(self.__instance)

        # Subscribe to muxer and discoverer events
        # self.__discoverer.ready.subscribe(self.__aip_ready)
        self.__instance.incoming_greeting.subscribe(self.__received_greeting)
        self.__transport.incoming_stream.subscribe(self.__new_stream)

        self.__ready = False
        self.ready = Subject()

        # Are we a repeater?
        if(self.is_repeater):
            # Yes, tag ourself with that resource
            self.__info.resources.add(REPEATER_RESOURCE)

        # Add the application to the discoverer
        self.__discoverer.add_application(self.__info).subscribe(self.__new_aip_app_peer)

        # Keep a set of reachable RPP repeater peers
        self.__repeaters: Set[InstanceReference] = set()

        self._ready = False
        self.ready = Subject()


    @property
    def instance_reference(self):
        return self.__instance.reference


    def add_instance(self, instance: InstanceReference):
        # Add to our set
        self.__announced_instances.add(instance)

        # Announce to connected repeaters
        self.__send_command(COMMAND_ANNOUNCE, Announcement([instance]).serialise().read())


    def find_path(self, instance: InstanceReference):
        # Construct a query
        query = PathQuery(instance, 15, [])

        # Create a Path Info from a stream
        def read_response(stream: IngressStream):
            response = PathResponse.deserialise(stream)
            stream.close()

            # Prepend hop to respondant repeater
            # TODO these flags may need to be looked at some more or the 
            # PathNode object redesigned
            # HACK we should probably just get some sort of full representation
            # from the RPP repeater we ask the path from, but can't at the moment as we require peer info
            response.nodes.insert(0, PathNode.PathNode(stream.origin, PathNode.FLAGS_NONE, self.__muxer.get_peer_info(stream.origin)))

            # TODO generate many possible strategies
            return [PathStrategy(PathInfo([x.instance for x in response.nodes]), response.nodes[0].peer_info),]

        # Send the query and map reply to PathResponse
        return self.__send_command(COMMAND_FIND_PATH, query.serialise().read(), True).pipe(operators.take(1), operators.map(read_response))


    def __new_aip_app_peer(self, instance):
        # Query for RPP repeater instances
        self.__discoverer.find_application_resource(self.__info, REPEATER_RESOURCE).answer.subscribe(self.__found_instance)


    def __found_instance(self, instance_info: InstanceInformation):
        # Is this peer already reachable?
        if(instance_info.instance_reference in self.__repeaters):
            # Don't harras it
            return

        # Inquire about the peer
        self.__muxer.inquire(self.__instance, instance_info.instance_reference, instance_info.connection_methods)
    

    def __received_greeting(self, instance: InstanceReference):
        # Do we already know about this peer?
        if(instance in self.__repeaters):
            # Nothing to do
            return

        # No, announce our instances
        self.__send_command_to(COMMAND_ANNOUNCE, Announcement(self.__announced_instances).serialise().read(), instance).subscribe(on_completed=self.__set_ready)

        # Save as repeater
        self.__repeaters.add(instance)

        # Are we a repeater?
        if(self.is_repeater):
            # Send join (empty)
            self.__send_command_to(COMMAND_JOIN, b"", instance)

            # Save instance info for flag lookups
            self.instance_info[instance] = self.__muxer.get_peer_info(instance)
            self.instance_network[instance] = self.__muxer.get_peer_network(instance)

    
    def __set_ready(self):
        if(self._ready):
            return

        self.ready.on_completed()

    
    def __send_command(self, command_type: bytes, data: bytes, expect_reply: bool = False, blacklist: Set[InstanceReference] = set()) -> Subject:
        # If we expect replies to this command, create a subject
        reply_subject = None
        if(expect_reply):
            reply_subject = Subject()

        count = 0

        # Loop over each repeater
        for repeater in self.__repeaters:
            # Is this a blacklisted repeater?
            if(repeater in blacklist):
                # Yes, skip
                continue

            # Send command
            subject = self.__send_command_to(command_type, data, repeater, expect_reply)

            count += 1

            # Do we expect a reply?
            if(expect_reply):
                # Yes, connect to subject
                subject.subscribe(reply_subject.on_next)

        Log.debug("Broadcasted a command to {} repeater/s".format(count))

        # Return reply subject
        return reply_subject


    def __send_command_to(self, command_type: bytes, data: bytes, instance: InstanceReference, expect_reply: bool = False) -> Subject:
        # Returns when the command has been sent, or with the reply if expctant
        subject = Subject()
            
        # Handler for eventual opening of stream
        def on_connected(stream: EgressStream):
            # Do we expect a reply?
            if(expect_reply):
                # Subscribe to reply
                stream.reply.subscribe(subject.on_next)

            # Send command type and command
            stream.write(command_type + data)

            # Close the stream
            stream.close()

            # Do we expect a reply?
            if(not expect_reply):
                # No, let caller know we are done
                subject.on_completed()

        # Open stream with the peer
        self.__transport.initialise_stream(instance).subscribe(on_connected)

        # Return the subject
        return subject
        

    def __new_stream(self, stream: IngressStream):
        # New command, what is it?
        command_type = stream.read(1)

        # Announce
        if(command_type == COMMAND_ANNOUNCE):
            # Read announcement
            announcement = Announcement.deserialise(stream)

            # Get peer info and network
            info = self.__muxer.get_peer_info(stream.origin)
            network = self.__muxer.get_peer_network(stream.origin)

            Log.debug("Peer announced itself with {} attached instance/s".format(len(announcement.instances)))

            # Update records
            for instance in announcement.instances:
                self.instance_info[instance] = info
                self.instance_network[instance] = network

            # Also add info for the RPP peer
            self.instance_info[stream.origin] = info
            self.instance_network[stream.origin] = network

        # Join
        elif(command_type == COMMAND_JOIN):
            Log.debug("Repeater peer joined")
            # Add as repeater peer
            self.__repeaters.add(stream.origin)

            # Save instance info for flag lookups
            self.instance_info[stream.origin] = self.__muxer.get_peer_info(stream.origin)
            self.instance_network[stream.origin] = self.__muxer.get_peer_network(stream.origin)

        # Find path
        elif(command_type == COMMAND_FIND_PATH):
            # Read the query
            query = PathQuery.deserialise(stream)

            # Is it an instance directly connected to us?
            if(query.target in self.instance_info):
                # Yes, get the flags
                flags = self.__get_instance_flags(stream.origin, query.target)

                Log.debug("Servicing query for path to an instance that is currently connected")

                self.__query_respond(stream.origin, stream.id, PathResponse([]))

            elif(query.ttl > 0):
                Log.debug("Forwarding query for path to instance")
                # Instance is not directly connected, forward query if still alive
                self.__forward_query(stream.origin, stream.id, query)


    def __forward_query(self, instance: InstanceReference, reply_to, query: PathQuery):
        # Add out own instance reference to the blacklist so it can't route through us again
        query.blacklist.append(self.__instance.reference)

        # Handle responses
        def on_responded(stream: IngressStream):
            # Read response
            response = PathResponse.deserialise(stream)

            # TODO: Save PeerInfo of other repeaters we may be able to communicate with
            # as the client asking for this path will try combinations

            # Get flags for respondant repeater
            flags = self.__get_instance_flags(instance, stream.origin)

            # Prepend hop to respondant repeater
            response.nodes.insert(0, PathNode.PathNode(stream.origin, flags, self.__muxer.get_peer_info(stream.origin)))

        # Forward the query to all my repeater friends
        self.__send_command(COMMAND_FIND_PATH, query.serialise().read(), True, set(query.blacklist)).pipe(operators.take(1)).subscribe(on_responded)


    def __get_instance_flags(self, origin: InstanceReference, target: InstanceReference):
        #set up flags
        flags = PathNode.FLAGS_NONE

        # Is it on the same network as the caller?
        # TODO this may need to use self.instance_network instead of the muxer lookup
        if(self.instance_network[origin] != self.instance_network[target]):
            # No, add bridge flag
            flags = flags | PathNode.FLAGS_BRIDGE

        return flags


    def __query_respond(self, instance: InstanceReference, reply_to, response: PathResponse):
        # Handler for stream setup
        def on_stream(stream: EgressStream):
            # Send the response
            stream.write(response.serialise().read())

            # Close
            stream.close()

        # Set up connection with instance
        self.__transport.initialise_stream(instance, in_reply_to=reply_to).subscribe(on_stream)