mirror of https://github.com/sbt/sbt.git
Resume partial downloads
This commit is contained in:
parent
2463e41df1
commit
7a8a626064
|
|
@ -53,7 +53,8 @@ object Cache {
|
||||||
in: InputStream,
|
in: InputStream,
|
||||||
out: OutputStream,
|
out: OutputStream,
|
||||||
logger: Option[Logger],
|
logger: Option[Logger],
|
||||||
url: String
|
url: String,
|
||||||
|
alreadyDownloaded: Long
|
||||||
): Unit = {
|
): Unit = {
|
||||||
|
|
||||||
val b = Array.fill[Byte](bufferSize)(0)
|
val b = Array.fill[Byte](bufferSize)(0)
|
||||||
|
|
@ -69,7 +70,7 @@ object Cache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
helper(0L)
|
helper(alreadyDownloaded)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def withLockFor[T](file: File)(f: => FileError \/ T): FileError \/ T = {
|
private def withLockFor[T](file: File)(f: => FileError \/ T): FileError \/ T = {
|
||||||
|
|
@ -141,6 +142,8 @@ object Cache {
|
||||||
new File(dir, s"$name.part")
|
new File(dir, s"$name.part")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val partialContentResponseCode = 206
|
||||||
|
|
||||||
private def download(
|
private def download(
|
||||||
artifact: Artifact,
|
artifact: Artifact,
|
||||||
cache: Seq[(String, File)],
|
cache: Seq[(String, File)],
|
||||||
|
|
@ -228,20 +231,42 @@ object Cache {
|
||||||
Task {
|
Task {
|
||||||
withLockFor(file) {
|
withLockFor(file) {
|
||||||
downloading(url, file, logger) {
|
downloading(url, file, logger) {
|
||||||
val conn = urlConn(url)
|
val tmp = temporaryFile(file)
|
||||||
|
|
||||||
for (len <- Option(conn.getContentLengthLong) if len >= 0L)
|
val alreadyDownloaded = tmp.length()
|
||||||
|
|
||||||
|
val conn0 = urlConn(url)
|
||||||
|
|
||||||
|
val (partialDownload, conn) = conn0 match {
|
||||||
|
case conn0: HttpURLConnection if alreadyDownloaded > 0L =>
|
||||||
|
conn0.setRequestProperty("Range", s"bytes=$alreadyDownloaded-")
|
||||||
|
|
||||||
|
if (conn0.getResponseCode == partialContentResponseCode) {
|
||||||
|
val ackRange = Option(conn0.getHeaderField("Content-Range")).getOrElse("")
|
||||||
|
|
||||||
|
if (ackRange.startsWith(s"bytes $alreadyDownloaded-"))
|
||||||
|
(true, conn0)
|
||||||
|
else
|
||||||
|
// unrecognized Content-Range header -> start a new connection with no resume
|
||||||
|
(false, urlConn(url))
|
||||||
|
} else
|
||||||
|
(false, conn0)
|
||||||
|
|
||||||
|
case _ => (false, conn0)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (len0 <- Option(conn.getContentLengthLong) if len0 >= 0L) {
|
||||||
|
val len = len0 + (if (partialDownload) alreadyDownloaded else 0L)
|
||||||
logger.foreach(_.downloadLength(url, len))
|
logger.foreach(_.downloadLength(url, len))
|
||||||
|
}
|
||||||
|
|
||||||
val in = new BufferedInputStream(conn.getInputStream, bufferSize)
|
val in = new BufferedInputStream(conn.getInputStream, bufferSize)
|
||||||
|
|
||||||
val tmp = temporaryFile(file)
|
|
||||||
|
|
||||||
val result =
|
val result =
|
||||||
try {
|
try {
|
||||||
tmp.getParentFile.mkdirs()
|
tmp.getParentFile.mkdirs()
|
||||||
val out = new FileOutputStream(tmp)
|
val out = new FileOutputStream(tmp, partialDownload)
|
||||||
try \/-(readFullyTo(in, out, logger, url))
|
try \/-(readFullyTo(in, out, logger, url, if (partialDownload) alreadyDownloaded else 0L))
|
||||||
finally out.close()
|
finally out.close()
|
||||||
} finally in.close()
|
} finally in.close()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue