aboutsummaryrefslogtreecommitdiff
path: root/jvm/src/main/scala/xyz/driver/core/file/package.scala
blob: 58955e5d5f1156b53cbf00234fbd07df7ef65d18 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package xyz.driver.core

import java.io.File
import java.nio.file.Path

import xyz.driver.core.time.Time

import scala.concurrent.Future
import scalaz.{ListT, OptionT}

package file {

  import akka.NotUsed
  import akka.stream.scaladsl.Source
  import akka.util.ByteString
  import java.net.URL

  import scala.concurrent.duration.Duration

  final case class FileLink(
      name: Name[File],
      location: Path,
      revision: Revision[File],
      lastModificationDate: Time,
      fileSize: Long
  )

  trait FileService {

    def getFileLink(id: Name[File]): FileLink

    def getFile(fileLink: FileLink): File
  }

  trait FileStorage {

    def upload(localSource: File, destination: Path): Future[Unit]

    def download(filePath: Path): OptionT[Future, File]

    def stream(filePath: Path): OptionT[Future, Source[ByteString, NotUsed]]

    def delete(filePath: Path): Future[Unit]

    /** List contents of a directory */
    def list(directoryPath: Path): ListT[Future, FileLink]

    def exists(path: Path): Future[Boolean]

    /** List of characters to avoid in S3 (I would say file names in general)
      *
      * @see http://stackoverflow.com/questions/7116450/what-are-valid-s3-key-names-that-can-be-accessed-via-the-s3-rest-api
      */
    private val illegalChars = "\\^`><{}][#%~|&@:,$=+?; "

    protected def checkSafeFileName[T](filePath: Path)(f: => T): T = {
      filePath.toString.find(c => illegalChars.contains(c)) match {
        case Some(illegalCharacter) =>
          throw new IllegalArgumentException(s"File name cannot contain character `$illegalCharacter`")
        case None => f
      }
    }
  }

  trait SignedFileStorage extends FileStorage {
    def signedFileUrl(filePath: Path, duration: Duration): OptionT[Future, URL]
  }
}