async def push(self, src_paths: List[str], container: FileContainer, dest_path: str) -> None: async with self.stub.push.open() as stream: await stream.send_message( PushRequest(inner=PushRequest.Inner( bundle_id=file_container_to_bundle_id_deprecated( container), dst_path=dest_path, container=file_container_to_grpc(container), ))) if self.is_local: for src_path in src_paths: await stream.send_message( PushRequest(payload=Payload(file_path=src_path))) await stream.end() await stream.recv_message() else: await drain_to_stream( stream=stream, generator=stream_map( generate_tar(paths=src_paths, verbose=self._is_verbose), lambda chunk: PushRequest(payload=Payload(data=chunk)), ), logger=self.logger, )
async def _install_to_destination( client: CompanionClient, bundle: Bundle, destination: Destination ) -> InstalledArtifact: if isinstance(bundle, str): # Treat as a file path / url url = urllib.parse.urlparse(bundle) if url.scheme: payload = Payload(url=bundle) else: payload = Payload(file_path=str(Path(bundle).resolve(strict=True))) async with client.stub.install.open() as stream: await stream.send_message(InstallRequest(destination=destination)) await stream.send_message(InstallRequest(payload=payload)) await stream.end() response = await stream.recv_message() return InstalledArtifact(name=response.name, uuid=response.uuid) else: # Treat as a binary object (tar of .app or .ipa) async with client.stub.install.open() as stream: await stream.send_message(InstallRequest(destination=destination)) response = await drain_to_stream( stream=stream, generator=_generate_io_chunks(io=bundle, logger=client.logger), logger=client.logger, ) return InstalledArtifact(name=response.name, uuid=response.uuid)
async def _install_to_destination( self, bundle: Bundle, destination: Destination ) -> InstalledArtifact: async with self.get_stub() as stub, stub.install.open() as stream: generator = None if isinstance(bundle, str): url = urllib.parse.urlparse(bundle) if url.scheme: # send url payload = Payload(url=bundle) generator = generate_requests([InstallRequest(payload=payload)]) else: file_path = str(Path(bundle).resolve(strict=True)) if none_throws(self.companion_info).is_local: # send file_path generator = generate_requests( [InstallRequest(payload=Payload(file_path=file_path))] ) else: # chunk file from file_path generator = generate_binary_chunks( path=file_path, destination=destination, logger=self.logger ) else: # chunk file from memory generator = generate_io_chunks(io=bundle, logger=self.logger) # stream to companion await stream.send_message(InstallRequest(destination=destination)) response = await drain_to_stream( stream=stream, generator=generator, logger=self.logger ) return InstalledArtifact(name=response.name, uuid=response.uuid)
async def _install_to_destination(client: CompanionClient, path: str, destination: Destination) -> str: url = urllib.parse.urlparse(path) if url.scheme: payload = Payload(url=path) else: payload = Payload(file_path=str(Path(path).resolve(strict=True))) async with client.stub.install.open() as stream: await stream.send_message(InstallRequest(destination=destination)) await stream.send_message(InstallRequest(payload=payload)) await stream.end() response = await stream.recv_message() return response.bundle_id
async def _install_to_destination( self, bundle: Bundle, destination: Destination, compression: Optional[Compression] = None, ) -> AsyncIterator[InstalledArtifact]: async with self.stub.install.open() as stream: generator = None if isinstance(bundle, str): url = urllib.parse.urlparse(bundle) if url.scheme: # send url payload = Payload(url=bundle) generator = generate_requests([InstallRequest(payload=payload)]) else: file_path = str(Path(bundle).resolve(strict=True)) if self.is_local: # send file_path generator = generate_requests( [InstallRequest(payload=Payload(file_path=file_path))] ) else: # chunk file from file_path generator = generate_binary_chunks( path=file_path, destination=destination, compression=compression, logger=self.logger, ) else: # chunk file from memory generator = generate_io_chunks(io=bundle, logger=self.logger) # stream to companion await stream.send_message(InstallRequest(destination=destination)) if compression is not None: await stream.send_message( InstallRequest( payload=Payload(compression=COMPRESSION_MAP[compression]) ) ) async for message in generator: await stream.send_message(message) await stream.end() async for response in stream: yield InstalledArtifact( name=response.name, uuid=response.uuid, progress=response.progress )
async def _generate_framework_chunks( path: str, logger: Logger ) -> AsyncIterator[InstallRequest]: logger.debug(f"Generating chunks for {path}") async for chunk in tar.generate_tar([path]): yield InstallRequest(payload=Payload(data=chunk)) logger.debug(f"Finished generating chunks {path}")
async def _generate_dylib_chunks( path: str, logger: Logger) -> AsyncIterator[InstallRequest]: logger.debug(f"Generating chunks for {path}") yield InstallRequest(name_hint=os.path.basename(path)) async for chunk in gzip.generate_gzip(path): yield InstallRequest(payload=Payload(data=chunk)) logger.debug(f"Finished generating chunks {path}")
async def client(client: CompanionClient, file_paths: List[str]) -> None: async with client.stub.add_media.open() as stream: for file_path in file_paths: await stream.send_message( AddMediaRequest(payload=Payload(file_path=file_path))) await stream.end() await stream.recv_message()
async def _generate_app_chunks( app_path: str, logger: Logger ) -> AsyncIterator[InstallRequest]: logger.debug(f"Generating chunks for .app {app_path}") async for chunk in tar.generate_tar([app_path]): yield InstallRequest(payload=Payload(data=chunk)) logger.debug(f"Finished generating .app chunks {app_path}")
async def _generate_dsym_chunks( path: str, compression: Compression, logger: Logger) -> AsyncIterator[InstallRequest]: logger.debug(f"Generating chunks for {path}") async for chunk in tar.generate_tar([path], compression): yield InstallRequest(payload=Payload(data=chunk)) logger.debug(f"Finished generating chunks {path}")
async def daemon(client: CompanionClient, stream: Stream[RecordResponse, RecordRequest]) -> None: client.logger.info(f"Starting connection to backend") request = await stream.recv_message() output_file = none_throws(request).start.file_path async with client.stub.record.open() as forward_stream: if client.is_local: client.logger.info( f"Starting video recording to local file {output_file}") await forward_stream.send_message( RecordRequest(start=Start(file_path=output_file))) else: client.logger.info(f"Starting video recording with response data") await forward_stream.send_message( RecordRequest(start=Start(file_path=None))) client.logger.info("Request sent") await stream.recv_message() client.logger.info("Stopping video recording") await forward_stream.send_message(RecordRequest(stop=Stop())) await forward_stream.stream.end() if client.is_local: client.logger.info("Responding with file path") response = await forward_stream.recv_message() await stream.send_message(response) else: client.logger.info(f"Decompressing gzip to {output_file}") await drain_gzip_decompress(_generate_bytes(forward_stream), output_path=output_file) client.logger.info(f"Finished decompression to {output_file}") await stream.send_message( RecordResponse(payload=Payload(file_path=output_file)))
async def add_media(self, file_paths: List[str]) -> None: async with self.get_stub() as stub, stub.add_media.open() as stream: if none_throws(self.companion_info).is_local: for file_path in file_paths: await stream.send_message( AddMediaRequest(payload=Payload(file_path=file_path))) await stream.end() await stream.recv_message() else: generator = stream_map( generate_tar(paths=file_paths, place_in_subfolders=True), lambda chunk: AddMediaRequest(payload=Payload(data=chunk)), ) await drain_to_stream(stream=stream, generator=generator, logger=self.logger)
async def _generate_io_chunks(io: IO[bytes], logger: Logger) -> AsyncIterator[InstallRequest]: logger.debug("Generating io chunks") while True: chunk = io.read(CHUNK_SIZE) if not chunk: logger.debug(f"Finished generating byte chunks") return yield InstallRequest(payload=Payload(data=chunk)) logger.debug("Finished generating io chunks")
async def client(client: CompanionClient, src_paths: List[str], bundle_id: str, dest_path: str) -> None: async with client.stub.push.open() as stream: await stream.send_message( PushRequest(inner=Inner(bundle_id=bundle_id, dst_path=dest_path))) for src_path in src_paths: await stream.send_message( PushRequest(payload=Payload(file_path=src_path))) await stream.end() await stream.recv_message()
async def _generate_ipa_chunks( ipa_path: str, logger: Logger) -> AsyncIterator[InstallRequest]: logger.debug(f"Generating Chunks for .ipa {ipa_path}") async with aiofiles.open(ipa_path, "r+b") as file: while True: chunk = await file.read(CHUNK_SIZE) if not chunk: logger.debug(f"Finished generating .ipa chunks for {ipa_path}") return yield InstallRequest(payload=Payload(data=chunk))
async def add_media(self, file_paths: List[str]) -> None: async with self.stub.add_media.open() as stream: if self.is_local: for file_path in file_paths: await stream.send_message( AddMediaRequest(payload=Payload(file_path=file_path))) await stream.end() await stream.recv_message() else: self.logger.info(f"Adding media from {file_paths}") generator = stream_map( generate_tar( paths=file_paths, place_in_subfolders=True, verbose=self._is_verbose, ), lambda chunk: AddMediaRequest(payload=Payload(data=chunk)), ) await drain_to_stream(stream=stream, generator=generator, logger=self.logger)
async def push(self, src_paths: List[str], bundle_id: str, dest_path: str) -> None: async with self.get_stub() as stub, stub.push.open() as stream: await stream.send_message( PushRequest(inner=PushRequest.Inner(bundle_id=bundle_id, dst_path=dest_path))) if none_throws(self.companion_info).is_local: for src_path in src_paths: await stream.send_message( PushRequest(payload=Payload(file_path=src_path))) await stream.end() await stream.recv_message() else: await drain_to_stream( stream=stream, generator=stream_map( generate_tar(paths=src_paths), lambda chunk: PushRequest(payload=Payload(data=chunk)), ), logger=self.logger, )
async def daemon(client: CompanionClient, stream: Stream[AddMediaResponse, AddMediaRequest]) -> None: async with client.stub.add_media.open() as companion: if client.is_local: generator = stream else: paths = [request.payload.file_path async for request in stream] generator = stream_map( generate_tar(paths=paths, place_in_subfolders=True), lambda chunk: AddMediaRequest(payload=Payload(data=chunk)), ) response = await drain_to_stream(stream=companion, generator=generator, logger=client.logger) await stream.send_message(response)
async def daemon(client: CompanionClient, stream: Stream[PushResponse, PushRequest]) -> None: async with client.stub.push.open() as companion: await companion.send_message(await stream.recv_message()) if client.is_local: generator = stream else: paths = [request.payload.file_path async for request in stream] generator = stream_map( generate_tar(paths=paths), lambda chunk: PushRequest(payload=Payload(data=chunk)), ) response = await drain_to_stream(stream=companion, generator=generator, logger=client.logger) await stream.send_message(response)
async def daemon(client: CompanionClient, request: PullRequest) -> PullResponse: destination = request.dst_path async with client.stub.pull.open() as stream: if not client.is_local: # not sending the destination to remote companion # so it streams the file back request = PullRequest(bundle_id=request.bundle_id, src_path=request.src_path, dst_path=None) await stream.send_message(request, end=True) if client.is_local: await stream.recv_message() else: await drain_untar(generate_bytes(stream), output_path=destination) client.logger.info(f"pulled file to {destination}") return PullResponse(payload=Payload(file_path=destination))
async def pull(self, bundle_id: str, src_path: str, dest_path: str) -> None: async with self.get_stub() as stub, stub.pull.open() as stream: request = request = PullRequest( bundle_id=bundle_id, src_path=src_path, # not sending the destination to remote companion # so it streams the file back dst_path=dest_path if none_throws(self.companion_info).is_local else None, ) await stream.send_message(request) await stream.end() if none_throws(self.companion_info).is_local: await stream.recv_message() else: await drain_untar(generate_bytes(stream), output_path=dest_path) self.logger.info(f"pulled file to {dest_path}") return PullResponse(payload=Payload(file_path=dest_path))
async def contacts_update(self, contacts_path: str) -> None: async with self.get_stub() as stub: data = await create_tar([contacts_path]) await stub.contacts_update( ContactsUpdateRequest(payload=Payload(data=data)) )
async def client(client: CompanionClient, contacts_path: str) -> None: data = await create_tar([contacts_path]) await client.stub.contacts_update(ContactsUpdateRequest(payload=Payload(data=data)))