Skip to content

Commit

Permalink
WIP - copy file without touching source
Browse files Browse the repository at this point in the history
  • Loading branch information
dantb committed Nov 19, 2023
1 parent d95aff2 commit 0450af6
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.operations

import akka.http.scaladsl.model.Uri
import cats.effect.{Blocker, ContextShift, IO}
import ch.epfl.bluebrain.nexus.delta.plugins.storage.files.model.FileAttributes.FileAttributesOrigin.Client
import ch.epfl.bluebrain.nexus.delta.plugins.storage.files.model.{FileAttributes, FileDescription}
import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.model.Storage.DiskStorage
import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.operations.disk.DiskStorageSaveFile.initLocation
import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.operations.remote.RemoteDiskStorageLinkFile

import java.nio.file.{CopyOption, Path, StandardCopyOption}
import scala.concurrent.ExecutionContext

object CopyFile {

def copyLocal(destDesc: FileDescription, destStorage: DiskStorage, sourceAttr: FileAttributes): IO[FileAttributes] = {
val ec = ExecutionContext.global
implicit val cs: ContextShift[IO] = IO.contextShift(ec)
val blocker: Blocker = Blocker.liftExecutionContext(ec)
val source: Path = Path.of("/")
val dest: Path = Path.of("/")
val flags: Seq[CopyOption] = Seq(StandardCopyOption.COPY_ATTRIBUTES)

for {
(fullPath, relativePath) <- initLocation(destStorage.project, destStorage.value, destDesc.uuid, destDesc.filename)
createdFilePath <- fs2.io.file.copy[IO](blocker, source, dest, flags)
_ <- IO.raiseUnless(createdFilePath == fullPath)(new Exception("Created file not consistent with path"))
} yield FileAttributes(
uuid = destDesc.uuid,
location = Uri(fullPath.toUri.toString),
path = Uri.Path(relativePath.toString),
filename = destDesc.filename,
mediaType = destDesc.mediaType,
bytes = sourceAttr.bytes,
digest = sourceAttr.digest,
origin = Client
)
}

def copyRemote(
sourcePath: Uri.Path,
destDesc: FileDescription
): IO[FileAttributes] = ???

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.operations.disk

import akka.actor.ActorSystem
import akka.http.scaladsl.model.{BodyPartEntity, Uri}
import akka.stream.IOOperationIncompleteException
import akka.stream.{IOOperationIncompleteException, IOResult}
import akka.stream.scaladsl.FileIO
import akka.util.ByteString
import cats.effect.{ContextShift, IO}
import cats.implicits.catsSyntaxMonadError
import ch.epfl.bluebrain.nexus.delta.plugins.storage.files.model.Digest.ComputedDigest
import ch.epfl.bluebrain.nexus.delta.plugins.storage.files.model.FileAttributes.FileAttributesOrigin.Client
import ch.epfl.bluebrain.nexus.delta.plugins.storage.files.model.{FileAttributes, FileDescription}
import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.model.Storage.DiskStorage
Expand Down Expand Up @@ -35,7 +37,10 @@ final class DiskStorageSaveFile(storage: DiskStorage)(implicit as: ActorSystem,
IO.fromFuture(
IO.delay(
entity.dataBytes.runWith(
SinkUtils.combineMat(digestSink(storage.value.algorithm), FileIO.toPath(fullPath, openOpts)) {
SinkUtils.combineMat[ByteString, ComputedDigest, IOResult, FileAttributes](
digestSink(storage.value.algorithm),
FileIO.toPath(fullPath, openOpts)
) {
case (digest, ioResult) if fullPath.toFile.exists() =>
Future.successful(
FileAttributes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class RemoteDiskStorageLinkFile(storage: RemoteDiskStorage, client: RemoteDiskSt

def apply(sourcePath: Uri.Path, description: FileDescription): IO[FileAttributes] = {
val destinationPath = Uri.Path(intermediateFolders(storage.project, description.uuid, description.filename))
client.moveFile(storage.value.folder, sourcePath, destinationPath)(storage.value.endpoint).map {
client.copyFile(storage.value.folder, sourcePath, destinationPath, keepSource = false)(storage.value.endpoint).map {
case RemoteDiskStorageFileAttributes(location, bytes, digest, _) =>
FileAttributes(
uuid = description.uuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import akka.http.scaladsl.model.BodyPartEntity
import akka.http.scaladsl.model.Multipart.FormData
import akka.http.scaladsl.model.Multipart.FormData.BodyPart
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.model.Uri.Path
import akka.http.scaladsl.model.Uri.{Path, Query}
import cats.effect.{ContextShift, IO, Timer}
import cats.implicits.{catsSyntaxApplicativeError, catsSyntaxMonadError, toFunctorOps}
import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.operations.StorageFileRejection.FetchFileRejection.UnexpectedFetchError
Expand Down Expand Up @@ -155,13 +155,15 @@ final class RemoteDiskStorageClient(client: HttpClient, getAuthToken: AuthTokenP
* @param destRelativePath
* the destination relative path location inside the nexus folder
*/
def moveFile(
def copyFile(
bucket: Label,
sourceRelativePath: Path,
destRelativePath: Path
destRelativePath: Path,
keepSource: Boolean
)(implicit baseUri: BaseUri): IO[RemoteDiskStorageFileAttributes] = {
getAuthToken(credentials).flatMap { authToken =>
val endpoint = baseUri.endpoint / "buckets" / bucket.value / "files" / destRelativePath
val endpoint = (baseUri.endpoint / "buckets" / bucket.value / "files" / destRelativePath)
.withQuery(Query("keepSource" -> keepSource.toString))
val payload = Json.obj("source" -> sourceRelativePath.toString.asJson)
client
.fromJsonTo[RemoteDiskStorageFileAttributes](Put(endpoint, payload).withCredentials(authToken))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ class RemoteStorageClientSpec(docker: RemoteStorageDocker)
}

"move a file" in {
client.moveFile(bucket, Uri.Path("my/file-1.txt"), Uri.Path("other/file-1.txt"))(baseUri).accepted shouldEqual
client
.copyFile(bucket, Uri.Path("my/file-1.txt"), Uri.Path("other/file-1.txt"), keepSource = false)(baseUri)
.accepted shouldEqual
attributes.copy(
location = s"file:///app/$BucketName/nexus/other/file-1.txt",
digest = NotComputedDigest
Expand All @@ -95,7 +97,7 @@ class RemoteStorageClientSpec(docker: RemoteStorageDocker)

"fail to move a file that does not exist" in {
client
.moveFile(bucket, Uri.Path("my/file.txt"), Uri.Path("other/file.txt"))(baseUri)
.copyFile(bucket, Uri.Path("my/file.txt"), Uri.Path("other/file.txt"), keepSource = false)(baseUri)
.rejectedWith[MoveFileRejection.FileNotFound]

}
Expand Down

0 comments on commit 0450af6

Please sign in to comment.