def __init__(self): # NOTE: the rx type hints don't actually work https://github.com/ReactiveX/RxPY/issues/514 self.door_states = Subject() # Subject[DoorState] self.current_door_states: Dict[str, DoorState] = {} self._save_event( self.door_states, self.current_door_states, lambda x: x.door_name, ) self.door_health = Subject() # Subject[DoorHealth] self.current_door_health: Dict[str, ttm.DoorHealth] = {} self._save_event( self.door_health, self.current_door_health, lambda x: x.id_, ) self.lift_states = Subject() # Subject[LiftState] self.current_lift_states: Dict[str, LiftState] = {} self._save_event( self.lift_states, self.current_lift_states, lambda x: x.lift_name, ) self.lift_health = Subject() # Subject[LiftHealth] self.current_lift_health: Dict[str, ttm.LiftHealth] = {} self._save_event( self.lift_health, self.current_lift_health, lambda x: x.id_, ) self.dispenser_states = Subject() # Subject[DispenserState] self.current_dispenser_states: Dict[str, DispenserState] = {} self._save_event( self.dispenser_states, self.current_dispenser_states, lambda x: x.guid, ) self.dispenser_health = Subject() # Subject[DispenserHealth] self.current_dispenser_health: Dict[str, ttm.DispenserHealth] = {} self._save_event( self.dispenser_health, self.current_dispenser_health, lambda x: x.id_, ) self.ingestor_states = Subject() # Subject[IngestorState] self.current_ingestor_states: Dict[str, IngestorState] = {} self._save_event( self.ingestor_states, self.current_ingestor_states, lambda x: x.guid, ) self.ingestor_health = Subject() # Subject[IngestorHealth] self.current_ingestor_health: Dict[str, ttm.IngestorHealth] = {} self._save_event( self.ingestor_health, self.current_ingestor_health, lambda x: x.id_, ) self.fleet_states = Subject() # Subject[FleetState] self.current_fleet_states: Dict[str, FleetState] = {} self._save_event( self.fleet_states, self.current_fleet_states, lambda x: x.name, ) self.robot_health = Subject() # Subject[RobotHealth] self.current_robot_health: Dict[str, ttm.RobotHealth] = {} self._save_event( self.robot_health, self.current_robot_health, lambda x: x.id_, ) self.task_summaries = Subject() # Subject[TaskSummary] self.current_task_summaries: Dict[str, TaskSummary] = {} self._init_task_summaries() # BehaviorSubject[Optional[RmfBuildingMap]] self.rmf_building_map = BehaviorSubject(None) # BehaviorSubject[Optional[Dict]], a dict containing fields same as RmfBuildingMap, # but with the image data changed to an url. self.building_map = BehaviorSubject(None)
class Client(threading.Thread): connection: websockets.WebSocketClientProtocol def __init__(self, project: Optional[str] = None, account: Optional[str] = None, try_pick_up=False, parent_experiment=None, silent=False): self.connected = BehaviorSubject(False) self.project = project self.account = account self.parent_experiment = parent_experiment self.silent = silent self.host = os.environ.get('DEEPKIT_HOST', '127.0.0.1') self.socket_path = os.environ.get('DEEPKIT_SOCKET', None) self.ssl = os.environ.get('DEEPKIT_SSL', '0') is '1' self.port = int(os.environ.get('DEEPKIT_PORT', '8960')) self.job_token = None self.job_id = None if try_pick_up: # is set by Deepkit cli self.job_token = os.environ.get('DEEPKIT_JOB_ACCESSTOKEN', None) self.job_id = os.environ.get('DEEPKIT_JOB_ID', None) # is set by deepkit.login() self.token = os.environ.get('DEEPKIT_ACCESSTOKEN', None) self.result_status = None self.message_id = 0 self.callbacks: Dict[int, asyncio.Future] = {} self.subscriber: Dict[int, any] = {} self.stopping = False self.queue = [] self.controllers = {} self.patches = {} self.offline = False self.connections = 0 self.lock = threading.Lock() threading.Thread.__init__(self) self.daemon = True self.loop = asyncio.new_event_loop() self.start() def is_connected(self): return self.connected.value def run(self): self.connecting = self.loop.create_future() self.loop.run_forever() def connect(self): asyncio.run_coroutine_threadsafe(self._connect(), self.loop) def connect_anon(self): asyncio.run_coroutine_threadsafe(self._connect_anon(), self.loop).result() def shutdown(self): if self.offline: return promise = asyncio.run_coroutine_threadsafe(self.stop_and_sync(), self.loop) promise.result() if not self.connection.closed: raise Exception('Connection still active') self.loop.stop() async def stop_and_sync(self): self.stopping = True if deepkit.utils.in_self_execution() or self.result_status: # only when we are in self execution do we set status, time stamps etc # otherwise the CLI is doing that and the server. Or when # the experiment set result_state explicitly. # done = 150, //when all tasks are done # aborted = 200, //when at least one task aborted # failed = 250, //when at least one task failed # crashed = 300, //when at least one task crashed self.patches['status'] = 150 self.patches['ended'] = datetime.datetime.utcnow() self.patches['tasks.main.ended'] = datetime.datetime.utcnow() # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.status'] = 500 self.patches[ 'tasks.main.instances.0.ended'] = datetime.datetime.utcnow() # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.instances.0.status'] = 500 if hasattr(sys, 'last_value'): if isinstance(sys.last_value, KeyboardInterrupt): self.patches['status'] = 200 self.patches['tasks.main.status'] = 550 self.patches['tasks.main.instances.0.status'] = 550 else: self.patches['status'] = 300 self.patches['tasks.main.status'] = 650 self.patches['tasks.main.instances.0.status'] = 650 if self.result_status: self.patches['status'] = self.result_status.value while len(self.patches) > 0 or len(self.queue) > 0: await asyncio.sleep(0.15) await self.connection.close() def register_controller(self, name: str, controller): return asyncio.run_coroutine_threadsafe( self._register_controller(name, controller), self.loop) async def _register_controller(self, name: str, controller): self.controllers[name] = controller async def handle_peer_message(message, done): if message['type'] == 'error': done() del self.controllers[name] raise Exception('Register controller error: ' + message['error']) if message['type'] == 'ack': pass if message['type'] == 'peerController/message': data = message['data'] if not hasattr(controller, data['action']): error = f"Requested action {message['action']} not available in {name}" print(error, file=sys.stderr) await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'error', 'id': data['id'], 'stack': None, 'entityName': '@error:default', 'error': error } }, no_response=True) if data['name'] == 'actionTypes': parameters = [] i = 0 for arg in inspect.getfullargspec( getattr(controller, data['action'])).args: parameters.append({ 'type': 'any', 'name': '#' + str(i) }) i += 1 await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'actionTypes/result', 'id': data['id'], 'parameters': parameters, 'returnType': { 'type': 'any', 'name': 'result' } } }, no_response=True) if data['name'] == 'action': try: res = await getattr(controller, data['action'])(*data['args']) await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'next/json', 'id': data['id'], 'encoding': { 'name': 'r', 'type': 'any' }, 'next': res, } }, no_response=True) except Exception as e: await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'error', 'id': data['id'], 'stack': None, 'entityName': '@error:default', 'error': str(e) } }, no_response=True) def subscriber(message, on_done): self.loop.create_task(handle_peer_message(message, on_done)) await self._subscribe( { 'name': 'peerController/register', 'controllerName': name, }, subscriber) class Controller: def __init__(self, client): self.client = client def stop(self): self.client._message( { 'name': 'peerController/unregister', 'controllerName': name, }, no_response=True) return Controller(self) async def _action(self, controller: str, action: str, args=None, lock=True, allow_in_shutdown=False): if args is None: args = [] if lock: await self.connecting if self.offline: return if self.stopping and not allow_in_shutdown: raise Exception('In shutdown: actions disallowed') if not controller: raise Exception('No controller given') if not action: raise Exception('No action given') # print('> action', action, threading.current_thread().name) res = await self._message( { 'name': 'action', 'controller': controller, 'action': action, 'args': args, 'timeout': 60 }, lock=lock) # print('< action', action) if res['type'] == 'next/json': return res['next'] if 'next' in res else None if res['type'] == 'error': print(res, file=sys.stderr) raise ApiError('API Error: ' + str(res['error'])) raise ApiError(f"Invalid action type '{res['type']}'. Not implemented") def app_action_threadsafe(self, action: str, args=None) -> Future: if args is None: args = [] return asyncio.run_coroutine_threadsafe( self._action('app', action, args), self.loop) async def job_action(self, action: str, args=None): return await self._action('job', action, args) def job_action_threadsafe(self, action: str, args=None) -> Future: """ This method is non-blocking and every try to block-wait for an answers means script execution stops when connection is broken (offline training entirely impossible). So, we just schedule the call and return a Future, which the user can subscribe to. """ if args is None: args = [] return asyncio.run_coroutine_threadsafe( self._action('job', action, args), self.loop) async def _subscribe(self, message, subscriber): await self.connecting self.message_id += 1 message['id'] = self.message_id message_id = self.message_id def on_done(): del self.subscriber[message_id] def on_incoming_message(incoming_message): subscriber(incoming_message, on_done) self.subscriber[self.message_id] = on_incoming_message self.queue.append(message) def _create_message(self, message: dict, lock=True, no_response=False) -> dict: self.message_id += 1 message['id'] = self.message_id if not no_response: self.callbacks[self.message_id] = self.loop.create_future() return message async def _message(self, message, lock=True, no_response=False): if lock: await self.connecting message = self._create_message(message, no_response=no_response) self.queue.append(message) if no_response: return return await self.callbacks[self.message_id] def patch(self, path: str, value: any): if self.offline: return if self.stopping: return self.patches[path] = value async def send_messages(self, connection): while not connection.closed: try: q = self.queue[:] for m in q: try: j = json.dumps(m, default=json_converter) except TypeError as e: print('Could not send message since JSON error', e, m, file=sys.stderr) continue await connection.send(j) self.queue.remove(m) except Exception as e: print("Failed sending, exit send_messages", file=sys.stderr) raise e if len(self.patches) > 0: # we have to send first all messages/actions out # before sending patches, as most of the time # patches are based on previously created entities, # so we need to make sure those entities are created # first before sending any patches. # print('patches', self.patches) try: send = self.patches.copy() await connection.send( json.dumps( { 'name': 'action', 'controller': 'job', 'action': 'patchJob', 'args': [send], 'timeout': 60 }, default=json_converter)) for i in send.keys(): if self.patches[i] == send[i]: del self.patches[i] except websockets.exceptions.ConnectionClosed: return except ApiError: print("Patching failed. Syncing job data disabled.", file=sys.stderr) return await asyncio.sleep(0.5) async def handle_messages(self, connection): while not connection.closed: try: res = json.loads(await connection.recv()) except websockets.exceptions.ConnectionClosedError: # we need reconnect break except websockets.exceptions.ConnectionClosedOK: # we closed on purpose, so no reconnect necessary return if res and 'id' in res: if res['id'] in self.subscriber: self.subscriber[res['id']](res) if res['id'] in self.callbacks: self.callbacks[res['id']].set_result(res) del self.callbacks[res['id']] if not self.stopping: self.log("Deepkit: lost connection. reconnect ...") self.connecting = self.loop.create_future() self.connected.on_next(False) self.loop.create_task(self._connect()) async def _connected(self, id: str, token: str): try: if self.socket_path: self.connection = await websockets.unix_connect( self.socket_path) else: ws = 'wss' if self.ssl else 'ws' url = f"{ws}://{self.host}:{self.port}" self.connection = await websockets.connect(url) except Exception as e: # try again later self.log('Unable to connect', e) await asyncio.sleep(1) self.loop.create_task(self._connect()) return self.loop.create_task(self.handle_messages(self.connection)) # we don't use send_messages() since this would send all queue/patches # which would lead to permission issues when we're not first authenticated if token: message = self._create_message( { 'name': 'authenticate', 'token': { 'id': 'job', 'token': token, 'job': id } }, lock=False) await self.connection.send( json.dumps(message, default=json_converter)) res = await self.callbacks[message['id']] if not res['result'] or res['result'] is not True: raise Exception('Job token invalid') self.loop.create_task(self.send_messages(self.connection)) self.connecting.set_result(True) if self.connections > 0: self.log("Deepkit: Reconnected.") self.connected.on_next(True) self.connections += 1 async def _connect_anon(self): ws = 'wss' if self.ssl else 'ws' url = f"{ws}://{self.host}:{self.port}" self.connection = await websockets.connect(url) self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) self.connecting.set_result(True) self.connected.on_next(True) self.connections += 1 async def _connect(self): # we want to restart with a empty queue, so authentication happens always first queue_copy = self.queue[:] self.queue = [] if self.job_token: await self._connected(self.job_id, self.job_token) return try: link: Optional[FolderLink] = None user_token = self.token account_name = 'none' if not user_token: config = get_home_config() # when no user_token is given (via deepkit.login() for example) # we need to find the host, port, token from the user config in ~/.deepkit/config if not self.account and not self.project: # find both, start with link = config.get_folder_link_of_directory(sys.path[0]) account_config = config.get_account_for_id(link.accountId) elif self.account and not self.project: account_config = config.get_account_for_name(self.account) else: # default to first account configured account_config = config.get_first_account() account_name = account_config.name self.host = account_config.host self.port = account_config.port self.ssl = account_config.ssl user_token = account_config.token ws = 'wss' if self.ssl else 'ws' try: url = f"{ws}://{self.host}:{self.port}" self.connection = await websockets.connect(url) except Exception as e: self.offline = True print( f"Deepkit: App not started or server not reachable. Monitoring disabled. {e}", file=sys.stderr) self.connecting.set_result(False) return self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) res = await self._message( { 'name': 'authenticate', 'token': { 'id': 'user', 'token': user_token } }, lock=False) if not res['result']: raise Exception('Login invalid') project_name = '' if link: project_name = link.name projectId = link.projectId else: if not self.project: raise Exception( 'No project defined. Please use project="project-name" ' 'to specify which project to use.') project = await self._action('app', 'getProjectForPublicName', [self.project], lock=False) if not project: raise Exception( f'No project found for name {self.project}. Make sure it exists before using it. ' f'Do you use the correct account? (used {account_name})' ) project_name = project['name'] projectId = project['id'] job = await self._action('app', 'createJob', [projectId, self.parent_experiment], lock=False) prefix = "Sub experiment" if self.parent_experiment else "Experiment" self.log( f"{prefix} #{job['number']} created in project {project_name} using account {account_name}" ) deepkit.globals.loaded_job_config = job['config']['config'] self.job_token = await self._action('app', 'getJobAccessToken', [job['id']], lock=False) self.job_id = job['id'] # todo, implement re-authentication, so we don't have to drop the active connection await self.connection.close() await self._connected(self.job_id, self.job_token) except Exception as e: self.connecting.set_exception(e) self.queue = queue_copy + self.queue def log(self, *message: str): if not self.silent: print(*message)
lambda state, value: state.money < value, 'else': lambda state, value: True, } @dataclass class State: case: int = 0 customer: int = 0 employer: int = 0 money: int = 0 store = BehaviorSubject( State(settings['initial_case_index'], settings['initial_customer'], settings['initial_employer'], settings['initial_money'])) def store_on_next(state): print(settings['money_template'].format(state.money)) check_state(state) case = cases[state.case] show_case_description(case) next_state = get_next_state(case, state) if next_state is None or next_state.case == -1: print(settings['customer_template'].format(next_state.customer)) print(settings['employer_template'].format(next_state.employer)) print(settings['money_template'].format(next_state.money)) store.on_completed()
def __init__(self): self.rx_sensor_data_subject = Subject() self.rx_sensor_settings_subject = BehaviorSubject(SensorSettings())
class Client(threading.Thread): connection: websockets.WebSocketClientProtocol def __init__(self, config_path: str): self.connected = BehaviorSubject(False) self.config_path = config_path self.loop = asyncio.new_event_loop() self.host = os.environ.get('DEEPKIT_HOST', '127.0.0.1') self.port = int(os.environ.get('DEEPKIT_PORT', '8960')) self.token = os.environ.get('DEEPKIT_JOB_ACCESSTOKEN', None) self.job_id = os.environ.get('DEEPKIT_JOB_ID', None) self.message_id = 0 self.account = 'localhost' self.callbacks: Dict[int, asyncio.Future] = {} self.subscriber: Dict[int, any] = {} self.stopping = False self.queue = [] self.controllers = {} self.patches = {} self.offline = False self.connections = 0 self.lock = threading.Lock() threading.Thread.__init__(self) self.daemon = True self.loop = asyncio.new_event_loop() self.start() def run(self): self.connecting = self.loop.create_future() self.loop.create_task(self._connect()) self.loop.run_forever() def shutdown(self): if self.offline: return promise = asyncio.run_coroutine_threadsafe(self.stop_and_sync(), self.loop) promise.result() if not self.connection.closed: raise Exception('Connection still active') self.loop.stop() async def stop_and_sync(self): self.stopping = True # todo, assign correct status depending on python exit code # done = 150, //when all tasks are done # aborted = 200, //when at least one task aborted # failed = 250, //when at least one task failed # crashed = 300, //when at least one task crashed self.patches['status'] = 150 self.patches['ended'] = time.time() * 1000 self.patches['tasks.main.ended'] = time.time() * 1000 # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.status'] = 500 self.patches['tasks.main.instances.0.ended'] = time.time() * 1000 # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.instances.0.status'] = 500 while len(self.patches) > 0 or len(self.queue) > 0: await asyncio.sleep(0.15) await self.connection.close() async def register_controller(self, name: str, controller): self.controllers[name] = controller async def subscriber(message, done): if message['type'] == 'error': done() del self.controllers[name] raise Exception('Register controller error: ' + message['error']) if message['type'] == 'ack': pass if message['type'] == 'peerController/message': data = message['data'] if not hasattr(controller, data['action']): error = f"Requested action {message['action']} not available in {name}" print(error, file=sys.stderr) await self._message({ 'name': 'peerController/message', 'controllerName': name, 'replyId': message['replyId'], 'data': {'type': 'error', 'id': 0, 'stack': None, 'entityName': '@error:default', 'error': error} }, no_response=True) if data['name'] == 'actionTypes': parameters = [] for arg in inspect.getfullargspec(getattr(controller, data['action'])).args: parameters.append({ 'type': 'Any', 'array': False, 'partial': False }) await self._message({ 'name': 'peerController/message', 'controllerName': name, 'replyId': message['replyId'], 'data': { 'type': 'actionTypes/result', 'id': 0, 'parameters': parameters, 'returnType': {'partial': False, 'type': 'Any', 'array': False} } }, no_response=True) if data['name'] == 'action': try: res = getattr(controller, data['action'])(*data['args']) await self._message({ 'name': 'peerController/message', 'controllerName': name, 'replyId': message['replyId'], 'data': { 'type': 'next/json', 'id': message['id'], 'next': res, } }, no_response=True) except Exception as e: await self._message({ 'name': 'peerController/message', 'controllerName': name, 'replyId': message['replyId'], 'data': {'type': 'error', 'id': 0, 'stack': None, 'entityName': '@error:default', 'error': str(e)} }, no_response=True) await self._subscribe({ 'name': 'peerController/register', 'controllerName': name, }, subscriber) class Controller: def __init__(self, client): self.client = client def stop(self): self.client._message({ 'name': 'peerController/unregister', 'controllerName': name, }) return Controller(self) async def _action(self, controller: str, action: str, args: List, lock=True): if lock: await self.connecting if self.offline: return if self.stopping: raise Exception('In shutdown: actions disallowed') res = await self._message({ 'name': 'action', 'controller': controller, 'action': action, 'args': args, 'timeout': 60 }, lock=lock) if res['type'] == 'next/json': return res['next'] if res['type'] == 'error': print(res, file=sys.stderr) raise Exception('API Error: ' + res['error']) raise Exception(f"Invalid action type '{res['type']}'. Not implemented") def job_action(self, action: str, args: List): return asyncio.run_coroutine_threadsafe(self._action('job', action, args), self.loop) async def _subscribe(self, message, subscriber): await self.connecting self.message_id += 1 message['id'] = self.message_id message_id = self.message_id def on_done(): del self.subscriber[message_id] async def on_incoming_message(incoming_message): await subscriber(incoming_message, on_done) self.subscriber[self.message_id] = on_incoming_message self.queue.append(message) async def _message(self, message, lock=True, no_response=False): if lock: await self.connecting self.message_id += 1 message['id'] = self.message_id if not no_response: self.callbacks[self.message_id] = self.loop.create_future() self.queue.append(message) if no_response: return return await self.callbacks[self.message_id] def patch(self, path: str, value: any): if self.offline: return if self.stopping: raise Exception('In shutdown: patches disallowed') self.patches[path] = value async def send_messages(self, connection): while not connection.closed: try: q = self.queue[:] for m in q: await connection.send(json.dumps(m)) self.queue.remove(m) except Exception: return if len(self.patches) > 0: try: send = self.patches.copy() await connection.send(json.dumps({ 'name': 'action', 'controller': 'job', 'action': 'patchJob', 'args': [ send ], 'timeout': 60 })) for i in send.keys(): if self.patches[i] == send[i]: del self.patches[i] except websockets.exceptions.ConnectionClosed: return await asyncio.sleep(0.25) async def handle_messages(self, connection): while not connection.closed: try: res = json.loads(await connection.recv()) except websockets.exceptions.ConnectionClosedError: # we need reconnect break except websockets.exceptions.ConnectionClosedOK: # we closed on purpose, so no reconnect necessary return if res and 'id' in res: if res['id'] in self.subscriber: await self.subscriber[res['id']](res) if res['id'] in self.callbacks: self.callbacks[res['id']].set_result(res) del self.callbacks[res['id']] if not self.stopping: print("Deepkit: lost connection. reconnect ...") self.connecting = self.loop.create_future() self.connected.on_next(False) self.loop.create_task(self._connect()) async def _connect_job(self, host: str, port: int, id: str, token: str): try: self.connection = await websockets.connect(f"ws://{host}:{port}") except Exception: # try again later await asyncio.sleep(1) self.loop.create_task(self._connect()) return self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) res = await self._message({ 'name': 'authenticate', 'token': { 'id': 'job', 'token': token, 'job': id } }, lock=False) if not res['result'] or res['result'] is not True: raise Exception('Job token invalid') # load job controller await self._message({ 'name': 'action', 'controller': 'job', 'action': '' }, lock=False) self.connecting.set_result(True) if self.connections > 0: print("Deepkit: Reconnected.") self.connected.on_next(True) self.connections += 1 async def _connect(self): # we want to restart with a empty queue, so authentication happens always first queue_copy = self.queue[:] self.queue = [] if self.token: await self._connect_job(self.host, self.port, self.job_id, self.token) else: account_config = self.get_account_config(self.account) self.host = account_config['host'] self.port = account_config['port'] try: self.connection = await websockets.connect(f"ws://{self.host}:{self.port}") except Exception as e: self.offline = True print(f"Deepkit: App not started or server not reachable. Monitoring disabled. {e}") self.connecting.set_result(False) return self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) res = await self._message({ 'name': 'authenticate', 'token': { 'id': 'user', 'token': account_config['token'] } }, lock=False) if not res['result']: raise Exception('Login invalid') link = self.get_folder_link() deepkit_config_yaml = None if self.config_path and os.path.exists(self.config_path): deepkit_config_yaml = open(self.config_path, 'r', encoding='utf-8').read() job = await self._action('app', 'createJob', [link['projectId'], self.config_path, deepkit_config_yaml], lock=False) deepkit.globals.loaded_job = job self.token = await self._action('app', 'getJobAccessToken', [job['id']], lock=False) self.job_id = job['id'] await self.connection.close() await self._connect_job(self.host, self.port, self.job_id, self.token) self.queue = queue_copy + self.queue def get_account_config(self, name: str) -> Dict: with open(os.path.expanduser('~') + '/.deepkit/config', 'r') as h: config = json.load(h) for account in config['accounts']: if account['name'] == name: return account raise Exception(f"No account for {name} found.") def get_folder_link(self) -> Dict: with open(os.path.expanduser('~') + '/.deepkit/config', 'r') as h: config = json.load(h) for link in config['folderLinks']: if is_in_directory(sys.path[0], link['path']): return link raise Exception(f"No project link for {sys.path[0]} found.")
def __init__(self, *args, **kwargs): super().__init__(*args) self.subject = BehaviorSubject(self.checkState()) self.stateChanged.connect(self.subject.on_next) self.subject.subscribe(self.update_ui)
class LobbyConnection: """ GUARANTEES: - After calling connect, connection will leave disconnected state. """ def __init__(self, host, port): self.socket = QtNetwork.QTcpSocket() self.socket.stateChanged.connect(self._on_socket_state_change) self.socket.readyRead.connect(self.read) self.socket.error.connect(self._on_error) self.socket.setSocketOption(QtNetwork.QTcpSocket.KeepAliveOption, 1) self._host = host self._port = port self.block_size = 0 self._obs_state = BehaviorSubject(ConnectionState.DISCONNECTED) self.obs_state = self._obs_state.pipe(ops.distinct_until_changed()) self.message_stream = Subject() def _socket_state(self, s): qas = QtNetwork.QAbstractSocket if s in [qas.ConnectedState, qas.ClosingState]: return ConnectionState.CONNECTED elif s in [qas.BoundState, qas.HostLookupState, qas.ConnectingState]: return ConnectionState.CONNECTING else: return ConnectionState.DISCONNECTED @property def state(self): return self._obs_state.value def _on_socket_state_change(self, state): s = self._socket_state(state) if s is ConnectionState.DISCONNECTED: self.block_size = 0 self._obs_state.on_next(s) # Conflict with PySide2 signals! # Idempotent def connect_(self): if self.state is not ConnectionState.DISCONNECTED: return self.socket.connectToHost(self._host, self._port) def disconnect_(self): self.socket.disconnectFromHost() def read(self): ins = QtCore.QDataStream(self.socket) ins.setVersion(QtCore.QDataStream.Qt_4_2) while not ins.atEnd(): if self.block_size == 0: if self.socket.bytesAvailable() < 4: return self.block_size = ins.readUInt32() if self.socket.bytesAvailable() < self.block_size: return data = ins.readQString() self.block_size = 0 self.message_stream.on_next(data) def write(self, data): block = QtCore.QByteArray() out = QtCore.QDataStream(block, QtCore.QIODevice.ReadWrite) out.setVersion(QtCore.QDataStream.Qt_4_2) out.writeUInt32(2 * len(data) + 4) out.writeQString(data) if self.socket.state() == QtNetwork.QAbstractSocket.ConnectedState: self.socket.write(block) def _on_error(self): self.disconnect_()
class GenericRantList(urwid.WidgetWrap): def __init__(self, rants_subscriptable): self.widget = None self.rants_subscriptable = rants_subscriptable self.rants = [] self.update = BehaviorSubject(self) self._subscriptions = [] self.create() super().__init__(self.widget) def __del__(self): self.update.dispose() for subscription in self._subscritpions: subscription.unsubscribe() def create_list_box(self): elements = [] for i, rant in enumerate(self.rants): if i > 0: elements.append(urwid.Divider(u'\u2500')) element = RantListElementWidget(rant) elements.append(element) list_box = urwid.ListBox(urwid.SimpleListWalker(elements)) return list_box def create(self): self.widget = urwid.Frame(self.create_list_box()) self._subscribe_rant_list() def _subscribe_rant_list(self): def action(new_value): self.rants = new_value simple_list_walker = self.widget.contents['body'][0].body i = 0 j = 0 # update existent while i < len(simple_list_walker) and j < len(new_value): element = simple_list_walker[i] rant = new_value[j] if type(element) is not RantListElementWidget: i += 1 else: element.update_rant(rant) i += 1 j += 1 # append new ones while j < len(new_value): rant = new_value[j] if i > 0: simple_list_walker.append(urwid.Divider(u'\u2500')) i += 1 simple_list_walker.contents.append(RantListElementWidget(rant)) i += 1 j += 1 # delete excedent simple_list_walker.contents[:i] self.update.on_next(self) self._subscriptions.append(self.rants_subscriptable.subscribe(action))
def __init__(self): self.game_msg = MockMessage() self.player_msg = MockMessage() self.login_msg = MockLoginMessage() self.obs_connection_state = BehaviorSubject( ConnectionState.DISCONNECTED)
class DevRantService(): def __init__(self, *args, **kwargs): self.base_url = "https://devrant.com/api" self.base_params = { 'app': 3, } self.rants = BehaviorSubject([]) self.error = Subject() self.me = BehaviorSubject(None) self.auth_token = BehaviorSubject(None) self.is_logged = BehaviorSubject(False) self._subscribe_to_auth_token() self._load_cache() def __del__(self): self.rants.dispose() self.error.dispose() self.me.dispose() self.auth_token.dispose() self.is_logged.dispose() def _get_params(self, **kwargs): params = dict(self.base_params, **kwargs) return urllib.parse.urlencode(params) def _load_cache(self, filename='.cache.json'): try: fh = open(filename, 'r') except FileNotFoundError: self._write_cache(filename) self._load_cache(filename) else: try: cache_data = json.load(fh) except json.decoder.JSONDecodeError: pass else: cached_auth_token = cache_data.get('auth_token') if cached_auth_token is not None: cached_auth_token = AuthToken(**cached_auth_token) self.auth_token.on_next(cached_auth_token) fh.close() def _write_cache(self, filename='.cache.json'): cache_data = {} try: fh = open(filename, 'r') cache_data = json.load(fh) except FileNotFoundError: pass except json.JSONDecodeError: pass else: fh.close() fh = open(filename, 'w') if self.auth_token.value is not None: cache_data['auth_token'] = self.auth_token.value.__dict__() json.dump(cache_data, fh) fh.close() def _delete_cache(self, filename='.cache.json'): fh = open(filename, 'w') json.dump({}, fh) fh.close() def _subscribe_to_auth_token(self): def action(value): # change is_logged value if self.is_logged.value and value.user_id is None: self.is_logged.on_next(False) elif not self.is_logged.value and value and value.user_id: self.is_logged.on_next(True) # save new auth_token self._write_cache() self._auth_token_subscription = self.auth_token.subscribe(action) return self async def get_rants(self, limit=10): param_url = self._get_params(sort='recent', limit=limit, skip=len(self.rants.value)) response = requests.get(self.base_url + '/devrant/rants' + '?' + param_url) if response.status_code == 200: new_rants = json.loads(response.text)['rants'] new_rants = [Rant(rant) for rant in new_rants] all_rants = list( merge(self.rants.value, new_rants, key=lambda x: x.id, reverse=True)) self.rants.on_next(all_rants) else: self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': response }) return self async def get_new_rants(self, skip=0, limit=10): if len(self.rants.value) == 0: return await self.get_rants() newest_actual_rant = self.rants.value[0] param_url = self._get_params(sort='recent', limit=limit, skip=skip) response = requests.get(self.base_url + '/devrant/rants' + '?' + param_url) if response.status_code == 200: new_rants = json.loads(response.text)['rants'] new_rants = [Rant(rant) for rant in new_rants] new_rants.sort(key=lambda x: x.id, reverse=True) if new_rants[-1].id > newest_actual_rant.id: await self.get_new_rants(skip + limit, limit) newest_actual_rant = self.rants.value[0] new_rants = [ rant for rant in new_rants if rant.id > newest_actual_rant.id ] all_rants = list( merge(new_rants, self.rants.value, key=lambda x: x.id, reverse=True)) self.rants.on_next(all_rants) else: self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': response }) return self async def post_rant(self, draft_rant): headers = { "Host": "devrant.com", "Connection": "keep-alive", "Accept": "application/json", "Origin": "https://devrant.com", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "https://devrant.com/feed", } form_data = { **self.base_params, 'rant': draft_rant.text, 'token_id': self.auth_token.value.id, 'token_key': self.auth_token.value.key, 'user_id': self.auth_token.value.user_id, 'tags': ', '.join(draft_rant.tags), 'type': 1 } draft_rant.response = requests.post(self.base_url + '/devrant/rants', headers=headers, data=form_data) draft_rant.state.on_next(DraftState.Sent) if draft_rant.response.status_code == 200: success = json.loads(draft_rant.response.text).get('success') if success: await self.get_new_rants() draft_rant.state.on_next(DraftState.Published) else: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 2, 'message': 'Posted rant error', 'response': draft_rant.response }) elif draft_rant.response.status_code == 400: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 2, 'message': 'Posted rant error', 'response': draft_rant.response }) else: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': draft_rant.response }) async def login(self, username, password): headers = { "Host": "devrant.com", "Connection": "keep-alive", "Accept": "application/json", "Origin": "https://devrant.com", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "https://devrant.com/", } response = requests.post(self.base_url + '/users/auth-token', headers=headers, data={ **self.base_params, "username": username, "password": password, }) if response.status_code == 200: data = response.json() if data.get('success'): auth_token = AuthToken(**data.get('auth_token')) self.auth_token.on_next(auth_token) # await self.get_about_me() else: self.error.on_next({'message': data.get('error')}) def logout(self): self._delete_cache() self.auth_token.on_next(AuthToken()) async def get_about_me(self): param_url = self._get_params(token_id=self.auth_token.value.id, token_key=self.auth_token.value.key) response = requests.get( self.base_url + '/users/{}'.format(self.auth_token.value.user_id) + '?' + param_url) return response
def create_store(initial_state: Optional[ReduxRootState] = None) -> ReduxRootStore: # pylint: disable=too-many-locals """ Constructs a new store that can handle feature modules. Args: initial_state: optional initial state of the store, will typically be the empty dict Returns: An implementation of the store """ # current reducer reducer: Reducer = identity_reducer def replace_reducer(new_reducer: Reducer) -> None: """ Callback that replaces the current reducer Args: new_reducer: the new reducer """ nonlocal reducer reducer = new_reducer # subject used to dispatch actions actions = Subject() # the shared action observable actions_ = actions.pipe(op.share()) _dispatch = actions.on_next # our current state state = BehaviorSubject(initial_state if initial_state else {}) # shutdown trigger done_ = Subject() # The set of known modules, to avoid cycles and duplicate registration modules: MutableMapping[str, ReduxFeatureModule] = {} # Sequence of added modules module_subject = Subject() # Subscribe to the resolved modules module_ = module_subject.pipe(op.distinct(select_id), op.share()) # Build the reducers reducer_ = module_.pipe( op.filter(has_reducer), op.scan(reduce_reducers, {}), op.map(combine_reducers), op.map(replace_reducer), ) # Build the epic epic_ = module_.pipe( op.map(select_epic), op.filter(bool), op.map(normalize_epic) ) # Root epic that combines all of the incoming epics def root_epic( action_: Observable, state_: Observable ) -> Observable: """ Implementation of the root epic. If listens for new epics to come in and automatically subscribes. Args: action_: the action observable state_: the state observable Returns The observable of resulting actions """ return epic_.pipe( op.flat_map(run_epic(action_, state_)), op.map(_dispatch) ) # notifications about new feature states new_module_ = module_.pipe( op.map(select_id), op.map(create_action(INIT_ACTION)), op.map(_dispatch), ) def _add_feature_module(module: ReduxFeatureModule): """ Registers a new feature module Args: module: the new feature module """ module_id = select_id(module) if not module_id in modules: modules[module_id] = module for dep in select_dependencies(module): _add_feature_module(dep) module_subject.on_next(module) # all state internal_ = merge(root_epic(actions_, state), reducer_, new_module_).pipe( op.ignore_elements() ) def _as_observable() -> Observable: """ Returns the state as an observable Returns: the observable """ return state def _on_completed() -> None: """ Triggers the done event """ done_.on_next(None) merge(actions_, internal_).pipe( op.map(lambda action: reducer(state.value, action)), op.take_until(done_), ).subscribe(state, logger.error) return ReduxRootStore( _as_observable, _dispatch, _add_feature_module, _dispatch, _on_completed )
def subject_factory(scheduler): return BehaviorSubject(initial_value)
def action1(scheduler, state=None): subject[0] = BehaviorSubject(100)
class BlenderContext(Context): window_size: RV[Dimension] = rv.new_view() batch: RV[GPUBatch] = window_size.map(lambda c, s: c.create_batch(s)) buffer: RV[GPUBatch] = window_size.map(lambda c, s: c.create_batch(s)) def __init__(self, toolkit: BlenderToolkit, look_and_feel: Optional[LookAndFeel] = None, font_options: Optional[FontOptions] = None, window_manager: Optional[WindowManager] = None, error_handler: Optional[ErrorHandler] = None) -> None: super().__init__(toolkit, look_and_feel, font_options, window_manager, error_handler) resolution = Dimension(bge.render.getWindowWidth(), bge.render.getWindowHeight()) self._resolution = BehaviorSubject(resolution) # noinspection PyTypeChecker self.window_size = self._resolution.pipe(ops.distinct_until_changed()) self._shader = cast(GPUShader, gpu.shader.from_builtin("2D_IMAGE")) if use_viewport_render: # noinspection PyArgumentList self._draw_handler = SpaceView3D.draw_handler_add( self.process, (), "WINDOW", "POST_PIXEL") else: self._draw_handler = None bge.logic.getCurrentScene().post_draw.append(self.process) # noinspection PyTypeChecker self._texture = Buffer(bgl.GL_INT, 1) bgl.glGenTextures(1, self.texture) @property def shader(self) -> GPUShader: return self._shader @property def texture(self) -> Buffer: return self._texture def create_batch(self, size: Dimension) -> GPUBatch: if size is None: raise ValueError("Argument 'size' is required.") points = Bounds(0, 0, size.width, size.height).points vertices = tuple(map(lambda p: p.tuple, map(self.translate, points))) coords = ((0, 0), (1, 0), (1, 1), (0, 1)) indices = {"pos": vertices, "texCoord": coords} return batch_for_shader(self.shader, "TRI_FAN", indices) def translate(self, point: Point) -> Point: if point is None: raise ValueError("Argument 'point' is required.") return point.copy(y=self.window_size.height - point.y) # noinspection PyTypeChecker def process_draw(self) -> None: width = bge.render.getWindowWidth() height = bge.render.getWindowHeight() self._resolution.on_next(Dimension(width, height)) super().process_draw() data = self.surface.get_data() source = bgl.Buffer(bgl.GL_BYTE, width * height * 4, data) bgl.glEnable(bgl.GL_BLEND) bgl.glActiveTexture(bgl.GL_TEXTURE0) # noinspection PyUnresolvedReferences bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture[0]) bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_SRGB_ALPHA, width, height, 0, bgl.GL_BGRA, bgl.GL_UNSIGNED_BYTE, source) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_NEAREST) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_NEAREST) self.shader.bind() self.shader.uniform_int("image", 0) self.batch.draw(self.shader) bgl.glDeleteBuffers(1, source) def dispose(self) -> None: if self._draw_handler: # noinspection PyArgumentList SpaceView3D.draw_handler_remove(self._draw_handler, "WINDOW") else: bge.logic.getCurrentScene().post_draw.remove(self.process) bgl.glDeleteTextures(1, self.texture) # noinspection PyTypeChecker bgl.glDeleteBuffers(1, self.texture) super().dispose()
def __init__(self): self.note_repository = NoteRepository() # Create notes field as a behavior subject with note from the business logic as an initial value # Your code here self.note_behavior_subject = BehaviorSubject( self.note_repository.get_all_notes())
class TabViewModel: """Informação global da tab""" def __init__(self, share_x, max_plots, name): self.sharexBehavior = BehaviorSubject(share_x) self.maxPlotsBehavior = BehaviorSubject(max_plots) self.nameBehavior = BehaviorSubject(name) def dispose(self): self.sharexBehavior.dispose() self.maxPlotsBehavior.dispose() self.nameBehavior.dispose() def _get_sharex_(self): return self.sharexBehavior.value def _set_sharex_(self, s): self.sharexBehavior.on_next(s) sharex = property(_get_sharex_, _set_sharex_) def _get_maxPlots_(self): return self.maxPlotsBehavior.value def _set_maxPlots_(self, m): self.maxPlotsBehavior.on_next(m) maxPlots = property(_get_maxPlots_, _set_maxPlots_) def _get_name_(self): return self.nameBehavior.value def _set_name_(self, value): self.nameBehavior.on_next(value) name = property(_get_name_, _set_name_)
class Client(threading.Thread): connection: websockets.WebSocketClientProtocol def __init__(self, options: ContextOptions): self.connected = BehaviorSubject(False) self.options: ContextOptions = options self.loop = asyncio.new_event_loop() self.host = os.environ.get('DEEPKIT_HOST', '127.0.0.1') self.port = int(os.environ.get('DEEPKIT_PORT', '8960')) self.token = os.environ.get('DEEPKIT_JOB_ACCESSTOKEN', None) self.job_id = os.environ.get('DEEPKIT_JOB_ID', None) self.message_id = 0 self.account = 'localhost' self.callbacks: Dict[int, asyncio.Future] = {} self.subscriber: Dict[int, any] = {} self.stopping = False self.queue = [] self.controllers = {} self.patches = {} self.offline = False self.connections = 0 self.lock = threading.Lock() threading.Thread.__init__(self) self.daemon = True self.loop = asyncio.new_event_loop() self.start() def run(self): self.connecting = self.loop.create_future() self.loop.create_task(self._connect()) self.loop.run_forever() def shutdown(self): if self.offline: return promise = asyncio.run_coroutine_threadsafe(self.stop_and_sync(), self.loop) promise.result() if not self.connection.closed: raise Exception('Connection still active') self.loop.stop() async def stop_and_sync(self): self.stopping = True # done = 150, //when all tasks are done # aborted = 200, //when at least one task aborted # failed = 250, //when at least one task failed # crashed = 300, //when at least one task crashed self.patches['status'] = 150 self.patches['ended'] = datetime.utcnow().isoformat() self.patches['tasks.main.ended'] = datetime.utcnow().isoformat() # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.status'] = 500 self.patches['tasks.main.instances.0.ended'] = datetime.utcnow( ).isoformat() # done = 500, # aborted = 550, # failed = 600, # crashed = 650, self.patches['tasks.main.instances.0.status'] = 500 if hasattr(sys, 'last_value'): if isinstance(sys.last_value, KeyboardInterrupt): self.patches['status'] = 200 self.patches['tasks.main.status'] = 550 self.patches['tasks.main.instances.0.status'] = 550 else: self.patches['status'] = 300 self.patches['tasks.main.status'] = 650 self.patches['tasks.main.instances.0.status'] = 650 while len(self.patches) > 0 or len(self.queue) > 0: await asyncio.sleep(0.15) await self.connection.close() async def register_controller(self, name: str, controller): self.controllers[name] = controller async def subscriber(message, done): if message['type'] == 'error': done() del self.controllers[name] raise Exception('Register controller error: ' + message['error']) if message['type'] == 'ack': pass if message['type'] == 'peerController/message': data = message['data'] if not hasattr(controller, data['action']): error = f"Requested action {message['action']} not available in {name}" print(error, file=sys.stderr) await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'error', 'id': data['id'], 'stack': None, 'entityName': '@error:default', 'error': error } }, no_response=True) if data['name'] == 'actionTypes': parameters = [] i = 0 for arg in inspect.getfullargspec( getattr(controller, data['action'])).args: parameters.append({ 'type': 'any', 'name': '#' + str(i) }) i += 1 await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'actionTypes/result', 'id': data['id'], 'parameters': parameters, 'returnType': { 'type': 'any', 'name': 'result' } } }, no_response=True) if data['name'] == 'action': try: res = getattr(controller, data['action'])(*data['args']) await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'next/json', 'id': data['id'], 'encoding': { 'name': 'r', 'type': 'any' }, 'next': res, } }, no_response=True) except Exception as e: await self._message( { 'name': 'peerController/message', 'controllerName': name, 'clientId': message['clientId'], 'data': { 'type': 'error', 'id': data['id'], 'stack': None, 'entityName': '@error:default', 'error': str(e) } }, no_response=True) await self._subscribe( { 'name': 'peerController/register', 'controllerName': name, }, subscriber) class Controller: def __init__(self, client): self.client = client def stop(self): self.client._message({ 'name': 'peerController/unregister', 'controllerName': name, }) return Controller(self) async def _action(self, controller: str, action: str, args: List, lock=True, allow_in_shutdown=False): if lock: await self.connecting if self.offline: return if self.stopping and not allow_in_shutdown: raise Exception('In shutdown: actions disallowed') if not controller: raise Exception('No controller given') if not action: raise Exception('No action given') res = await self._message( { 'name': 'action', 'controller': controller, 'action': action, 'args': args, 'timeout': 60 }, lock=lock) if res['type'] == 'next/json': return res['next'] if 'next' in res else None if res['type'] == 'error': print(res, file=sys.stderr) raise ApiError('API Error: ' + str(res['error'])) raise ApiError(f"Invalid action type '{res['type']}'. Not implemented") def job_action(self, action: str, args: List): return asyncio.run_coroutine_threadsafe( self._action('job', action, args), self.loop) async def _subscribe(self, message, subscriber): await self.connecting self.message_id += 1 message['id'] = self.message_id message_id = self.message_id def on_done(): del self.subscriber[message_id] async def on_incoming_message(incoming_message): await subscriber(incoming_message, on_done) self.subscriber[self.message_id] = on_incoming_message self.queue.append(message) async def _message(self, message, lock=True, no_response=False): if lock: await self.connecting self.message_id += 1 message['id'] = self.message_id if not no_response: self.callbacks[self.message_id] = self.loop.create_future() self.queue.append(message) if no_response: return return await self.callbacks[self.message_id] def patch(self, path: str, value: any): if self.offline: return if self.stopping: return self.patches[path] = value async def send_messages(self, connection): while not connection.closed: try: q = self.queue[:] for m in q: await connection.send(json.dumps(m)) self.queue.remove(m) except Exception as e: print("Failed sending, exit send_messages") raise e if len(self.patches) > 0: # we have to send first all messages/actions out # before sending patches, as most of the time # patches are based on previously created entities, # so we need to make sure those entities are created # first before sending any patches. try: send = self.patches.copy() await connection.send( json.dumps({ 'name': 'action', 'controller': 'job', 'action': 'patchJob', 'args': [send], 'timeout': 60 })) for i in send.keys(): if self.patches[i] == send[i]: del self.patches[i] except websockets.exceptions.ConnectionClosed: return except ApiError: print("Patching failed. Syncing job data disabled.", file=sys.stderr) return await asyncio.sleep(0.2) async def handle_messages(self, connection): while not connection.closed: try: res = json.loads(await connection.recv()) except websockets.exceptions.ConnectionClosedError: # we need reconnect break except websockets.exceptions.ConnectionClosedOK: # we closed on purpose, so no reconnect necessary return if res and 'id' in res: if res['id'] in self.subscriber: await self.subscriber[res['id']](res) if res['id'] in self.callbacks: self.callbacks[res['id']].set_result(res) del self.callbacks[res['id']] if not self.stopping: print("Deepkit: lost connection. reconnect ...") self.connecting = self.loop.create_future() self.connected.on_next(False) self.loop.create_task(self._connect()) async def _connect_job(self, host: str, port: int, id: str, token: str): try: self.connection = await websockets.connect(f"ws://{host}:{port}") except Exception: # try again later await asyncio.sleep(1) self.loop.create_task(self._connect()) return self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) res = await self._message( { 'name': 'authenticate', 'token': { 'id': 'job', 'token': token, 'job': id } }, lock=False) if not res['result'] or res['result'] is not True: raise Exception('Job token invalid') self.connecting.set_result(True) if self.connections > 0: print("Deepkit: Reconnected.") self.connected.on_next(True) self.connections += 1 async def _connect(self): # we want to restart with a empty queue, so authentication happens always first queue_copy = self.queue[:] self.queue = [] if self.token: await self._connect_job(self.host, self.port, self.job_id, self.token) else: config = get_home_config() link: Optional[FolderLink] = None if self.options.account: account_config = config.get_account_for_name( self.options.account) else: link = config.get_folder_link_of_directory(sys.path[0]) account_config = config.get_account_for_id(link.accountId) self.host = account_config.host self.port = account_config.port ws = 'wss' if account_config.ssl else 'ws' try: self.connection = await websockets.connect( f"{ws}://{self.host}:{self.port}") except Exception as e: self.offline = True print( f"Deepkit: App not started or server not reachable. Monitoring disabled. {e}" ) self.connecting.set_result(False) return self.loop.create_task(self.handle_messages(self.connection)) self.loop.create_task(self.send_messages(self.connection)) res = await self._message( { 'name': 'authenticate', 'token': { 'id': 'user', 'token': account_config.token } }, lock=False) if not res['result']: raise Exception('Login invalid') if link: projectId = link.projectId else: if not self.options.project: raise Exception( 'No project defined. Please use ContextOptions(project="project-name") ' 'to specify which project to use.') project = await self._action('app', 'getProjectForPublicName', [self.options.project], lock=False) if not project: raise Exception( f'No project found for name {self.options.project}. ' f'Do you use the correct account? (used {account_config.name})' ) projectId = project['id'] job = await self._action('app', 'createJob', [projectId], lock=False) deepkit.globals.loaded_job = job self.token = await self._action('app', 'getJobAccessToken', [job['id']], lock=False) self.job_id = job['id'] # todo, implement re-authentication, so we don't have to drop the active connection await self.connection.close() await self._connect_job(self.host, self.port, self.job_id, self.token) self.queue = queue_copy + self.queue
def __init__(self, share_x, max_plots, name): self.sharexBehavior = BehaviorSubject(share_x) self.maxPlotsBehavior = BehaviorSubject(max_plots) self.nameBehavior = BehaviorSubject(name)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.subject = BehaviorSubject(self.currentData()) self.currentIndexChanged.connect( lambda: self.subject.on_next(self.currentText()))
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) subject.on_next(4) subject.on_completed() # AsyncSubject会缓存上次发射的值,而且仅会在Observable关闭后开始发射 print('--------AsyncSubject---------') subject = AsyncSubject() subject.on_next(1) subject.on_next(2) subject.subscribe(lambda i: print(i)) subject.on_next(3) subject.on_next(4)