class RemoteClusterMultiChunkTransfer extends MultiChunkTransfer<StoreFileMetadata, RemoteClusterRepositoryFileChunk> {

    private static final String RESTORE_SHARD_TEMP_FILE_PREFIX = "CLUSTER_REPO_TEMP_";
    private static final Logger LOGGER = LogManager.getLogger(RemoteClusterMultiChunkTransfer.class);

    private final DiscoveryNode remoteNode;
    private final String restoreUUID;
    private final ShardId remoteShardId;
    private final String localClusterName;
    private final Client client;
    private final ThreadPool threadPool;
    private final ByteSizeValue chunkSize;
    private final String tempFilePrefix;
    private final MultiFileWriter multiFileWriter;
    private long offset = 0L;

    public RemoteClusterMultiChunkTransfer(Logger logger,
                                           String localClusterName,
                                           Store localStore,
                                           int maxConcurrentChunks,
                                           String restoreUUID,
                                           DiscoveryNode remoteNode,
                                           ShardId remoteShardId,
                                           List<StoreFileMetadata> remoteFiles,
                                           Client client,
                                           ThreadPool threadPool,
                                           RecoveryState recoveryState,
                                           ByteSizeValue chunkSize,
                                           ActionListener<Void> listener) {
        super(logger, listener, maxConcurrentChunks, remoteFiles);
        this.localClusterName = localClusterName;
        this.restoreUUID = restoreUUID;
        this.remoteNode = remoteNode;
        this.remoteShardId = remoteShardId;
        this.client = client;
        this.threadPool = threadPool;
        this.chunkSize = chunkSize;
        this.tempFilePrefix = RESTORE_SHARD_TEMP_FILE_PREFIX + restoreUUID + ".";
        this.multiFileWriter = new MultiFileWriter(localStore, recoveryState.getIndex(), tempFilePrefix, logger, () -> {});

        // Add all the available files to show the recovery status
        for (var fileMetadata : remoteFiles) {
            recoveryState.getIndex().addFileDetail(fileMetadata.name(), fileMetadata.length(), false);
        }
    }

    @Override
    protected RemoteClusterRepositoryFileChunk nextChunkRequest(StoreFileMetadata resource) throws IOException {
        var chunkReq = new RemoteClusterRepositoryFileChunk(resource, offset, chunkSize.bytesAsInt());
        offset += chunkSize.bytesAsInt();
        return chunkReq;
    }

    @Override
    protected void executeChunkRequest(RemoteClusterRepositoryFileChunk request,
                                       ActionListener<Void> listener) {<FILL_FUNCTION_BODY>}

    @Override
    protected void handleError(StoreFileMetadata resource, Exception e) throws Exception {
        LOGGER.error("Error while transferring segments ", e);
    }

    @Override
    protected void onNewResource(StoreFileMetadata resource) throws IOException {
        offset = 0L;
    }

    @Override
    public void close() throws IOException {
        multiFileWriter.renameAllTempFiles();
        multiFileWriter.close();
    }
}

        var getFileChunkRequest = new GetFileChunkAction.Request(
            restoreUUID,
            remoteNode,
            remoteShardId,
            localClusterName,
            request.storeFileMetadata(),
            request.offset(),
            request.length()
        );
        var fileChunkResponse = client.execute(GetFileChunkAction.INSTANCE, getFileChunkRequest);
        fileChunkResponse.whenComplete((response, err) -> {
            if (err == null) {
                LOGGER.debug("Filename: {}, response_size: {}, response_offset: {}",
                                request.storeFileMetadata().name(),
                                response.data().length(),
                                response.offset()
                );
                try {
                    threadPool.executor(ThreadPool.Names.SNAPSHOT).execute(() -> {
                        try {
                            multiFileWriter.writeFileChunk(
                                response.storeFileMetadata(),
                                response.offset(),
                                response.data(),
                                request.lastChunk()
                            );
                            listener.onResponse(null);
                        } catch (IOException e) {
                            listener.onFailure(new UncheckedIOException(e));
                        }
                    });
                } catch (EsRejectedExecutionException e) {
                    listener.onFailure(e);
                }
            } else {
                LOGGER.error(
                    "Failed to fetch file chunk for {} with offset {}",
                    request.storeFileMetadata().name(),
                    request.offset(),
                    err
                );
            }
        });
    
<methods>public final void start() <variables>private org.elasticsearch.index.store.StoreFileMetadata currentSource,private final non-sealed ActionListener<java.lang.Void> listener,private final non-sealed Logger logger,private final non-sealed int maxConcurrentChunks,private final non-sealed AsyncIOProcessor<FileChunkResponseItem<org.elasticsearch.index.store.StoreFileMetadata>> processor,private Tuple<org.elasticsearch.index.store.StoreFileMetadata,io.crate.replication.logical.repository.RemoteClusterRepositoryFileChunk> readAheadRequest,private final non-sealed Iterator<org.elasticsearch.index.store.StoreFileMetadata> remainingSources,private final org.elasticsearch.index.seqno.LocalCheckpointTracker requestSeqIdTracker,private org.elasticsearch.indices.recovery.MultiChunkTransfer.Status status