async def _api_device_claim(self, client_ctx, msg): replied_ok = False # Must start listening events before calling `claim_device_invitation` # given this function will send the `device.claimed` event the creator # is waiting for. send_channel, recv_channel = trio.open_memory_channel(1000) def _on_organization_events(event, organization_id, device_id, device_certificate=None, encrypted_answer=None): if organization_id == client_ctx.organization_id: send_channel.send_nowait( (event, device_id, device_certificate, encrypted_answer)) with self._event_bus.connect_in_context( (BackendEvent.DEVICE_CREATED, _on_organization_events), (BackendEvent.DEVICE_INVITATION_CANCELLED, _on_organization_events), ): try: invitation = await self.claim_device_invitation( client_ctx.organization_id, msg["invited_device_id"], msg["encrypted_claim"]) if not invitation.is_valid(): return {"status": "not_found"} except UserAlreadyExistsError: return {"status": "not_found"} except UserNotFoundError: return {"status": "not_found"} # Wait for creator device to accept (or refuse) our claim async for event, device_id, device_certificate, encrypted_answer in recv_channel: if device_id == invitation.device_id: replied_ok = event == BackendEvent.DEVICE_CREATED break if not replied_ok: return { "status": "denied", "reason": ("Invitation creator rejected us.") } else: return apiv1_device_claim_serializer.rep_dump({ "status": "ok", "device_certificate": device_certificate, "encrypted_answer": encrypted_answer, })
async def api_device_claim(self, client_ctx, msg): msg = apiv1_device_claim_serializer.req_load(msg) # Setting the cancel scope here instead of just were we are waiting # for the event make testing easier. with trio.move_on_after(PEER_EVENT_MAX_WAIT) as cancel_scope: rep = await self._api_device_claim(client_ctx, msg) if cancel_scope.cancelled_caught: rep = { "status": "timeout", "reason": "Timeout while waiting for invitation creator to answer.", } return apiv1_device_claim_serializer.rep_dump(rep)