Commit fc1a6eea authored by Szabolcs Gyurko's avatar Szabolcs Gyurko
Browse files

Updated to latest and greatest scala 2.13.6, play 2.8.8, sbt 1.4.9

parent 9158927f
Pipeline #366 passed with stage
in 2 minutes and 2 seconds
......@@ -32,7 +32,7 @@ class DataPersister @Inject() (protected val dbConfigProvider: DatabaseConfigPro
@scala.throws[Throwable](classOf[Throwable])
override def onReceive(message: Any): Unit = {
message match {
case p: PersistEvent
case p: PersistEvent =>
val currentTime = System.currentTimeMillis()
if (p.forceSave) {
this.synchronized {
......@@ -57,8 +57,8 @@ class DataPersister @Inject() (protected val dbConfigProvider: DatabaseConfigPro
} else {
Logger.trace(s"scheduling a persist in ${Defaults.PERSIST_FREQUENCY - (currentTime - lastSave)}ms")
saveRequested = true
akka.pattern.after(Duration(Defaults.PERSIST_FREQUENCY - (currentTime - lastSave), "ms"), sget2.actorSystem.scheduler)(Future.successful(p)).onComplete { t
t.foreach { e
akka.pattern.after(Duration(Defaults.PERSIST_FREQUENCY - (currentTime - lastSave), "ms"), sget2.actorSystem.scheduler)(Future.successful(p)).onComplete { t =>
t.foreach { e =>
Logger.trace("persist() by schedule")
this.synchronized {
persist(e)
......@@ -70,7 +70,7 @@ class DataPersister @Inject() (protected val dbConfigProvider: DatabaseConfigPro
}
}
}
case _
case _ =>
}
}
......@@ -81,21 +81,21 @@ class DataPersister @Inject() (protected val dbConfigProvider: DatabaseConfigPro
val queue = TableQuery[QueueTable]
/* Iterate through the download queue */
for (d sget2.downloadQueue.persist().jobList) {
for (d <- sget2.downloadQueue.persist().jobList) {
/* Update queue table */
val qQuery = queue.filter(_.jobId === d.id).map(x (x.alive, x.status, x.activeThreads)).update(d.alive, d.status, d.activeThreads)
qQuery.statements.foreach(s Logger.trace(s"SQL: $s"))
val qQuery = queue.filter(_.jobId === d.id).map(x => (x.alive, x.status, x.activeThreads)).update(d.alive, d.status, d.activeThreads)
qQuery.statements.foreach(s => Logger.trace(s"SQL: $s"))
/* Update jobs table */
val jQuery = jobs.filter(_.id === d.id).map(x (x.url, x.path, x.bandwidth, x.threads, x.user, x.pass, x.size, x.blocksize, x.finished)).
val jQuery = jobs.filter(_.id === d.id).map(x => (x.url, x.path, x.bandwidth, x.threads, x.user, x.pass, x.size, x.blocksize, x.finished)).
update(d.url, d.path, Some(d.bandwidthLimit), Some(d.maxThreads), d.username, d.password, Some(d.size), Some(d.chunkMatrix.blockSize.toInt), Some(new Timestamp(d.finishTime)))
jQuery.statements.foreach(s Logger.trace(s"SQL: $s"))
jQuery.statements.foreach(s => Logger.trace(s"SQL: $s"))
/* Update chunks table (delete + insert the easiest here) */
val cQuery = (
for {
dcQuery chunks.filter(_.jobId === d.id).delete
cQueries DBIO.sequence(d.chunkMatrix.chunks.zipWithIndex.toSeq.map(c chunks += ChunkRecord(d.id, c._1.status, c._1.size, c._2 * d.chunkMatrix.blockSize)))
dcQuery <- chunks.filter(_.jobId === d.id).delete
cQueries <- DBIO.sequence(d.chunkMatrix.chunks.zipWithIndex.toSeq.map(c => chunks += ChunkRecord(d.id, c._1.status, c._1.size, c._2 * d.chunkMatrix.blockSize)))
} yield (dcQuery, cQueries)
).transactionally
......
......@@ -15,8 +15,8 @@ import org.apache.http.ssl.SSLContexts
import org.slf4j.LoggerFactory
import sget2.PushMessageEvent
import scala.collection.JavaConverters._
import scala.collection.mutable.ListBuffer
import scala.jdk.CollectionConverters._
@Singleton
class PushMessageHandler @Inject() (private val configuration: play.api.Configuration) extends UntypedAbstractActor {
......@@ -25,9 +25,9 @@ class PushMessageHandler @Inject() (private val configuration: play.api.Configur
@scala.throws[Throwable](classOf[Throwable])
override def onReceive(message: Any): Unit = {
message match {
case p: PushMessageEvent
case p: PushMessageEvent =>
handlePushMessage(p)
case _
case _ =>
}
}
......@@ -71,7 +71,7 @@ class PushMessageHandler @Inject() (private val configuration: play.api.Configur
httpClient.execute(method)
httpClient.close()
} catch {
case e: Exception
case e: Exception =>
Logger.warn(s"Error communicating to ${host}, exception: ${e.getClass.getSimpleName}: ${e.getMessage}")
} finally {
httpClient.close()
......
......@@ -15,9 +15,9 @@ class QueueManager @Inject() (private val sget2: SGet2) extends UntypedAbstractA
@scala.throws[Throwable](classOf[Throwable])
override def onReceive(message: Any): Unit = {
message match {
case p: JobFinishedEvent
case p: JobFinishedEvent =>
jobFinished(p)
case _
case _ =>
}
}
......
......@@ -31,17 +31,17 @@ class AddJob @Inject() (val controllerComponents: ControllerComponents, protecte
private val addPostForm = Form(
mapping(
"url" nonEmptyText,
"path" nonEmptyText,
"user" optional(text),
"pass" optional(text),
"maxThreads" optional(number(min = 1, max = 16)),
"maxBandwidth" optional(number)
"url" -> nonEmptyText,
"path" -> nonEmptyText,
"user" -> optional(text),
"pass" -> optional(text),
"maxThreads" -> optional(number(min = 1, max = 16)),
"maxBandwidth" -> optional(number)
)(AddJobData.apply)(AddJobData.unapply)
)
/* GET for the HTML form */
def index() = Action { implicit request
def index() = Action { implicit request =>
val settings = sget2.settings
var pass: Option[String] = None
......@@ -53,13 +53,15 @@ class AddJob @Inject() (val controllerComponents: ControllerComponents, protecte
}
/* POST with forms */
def addJobPost() = Action.async(parse.form(addPostForm, onErrors = (formWithErrors: Form[AddJobData]) Redirect(routes.AddJob.index()))) { implicit request
def addJobPost() = Action.async(parse.form(addPostForm, onErrors = (formWithErrors: Form[AddJobData]) => Redirect(routes.AddJob.index()))) {
implicit request =>
val addJobData = request.body
addJob(addJobData)
}
/* PUT with JSON */
def addJobJsonPost() = Action.async(parse.json) { implicit request
def addJobJsonPost() = Action.async(parse.json) { implicit request =>
implicit val addJobDataReads = Json.reads[AddJobData]
val jobData: JsResult[AddJobData] = Json.fromJson(request.body)
if (jobData.isSuccess)
......@@ -88,11 +90,11 @@ class AddJob @Inject() (val controllerComponents: ControllerComponents, protecte
jobData.maxThreads, jobData.user, jobData.pass)
for {
(jobId, queueId) dbConfig.db.run(
(jobId, queueId) <- dbConfig.db.run(
(
for {
jobId (jobs returning jobs.map(_.id)) += jobRecord // Add the job record
queueId (queue returning queue.map(_.id)) += QueueRecord(0, jobId, DownloadJobStatusCode.WAITING.id) // Add the queue record
jobId <- (jobs returning jobs.map(_.id)) += jobRecord // Add the job record
queueId <- (queue returning queue.map(_.id)) += QueueRecord(0, jobId, DownloadJobStatusCode.WAITING.id) // Add the queue record
} yield (jobId, queueId)
).transactionally
)
......
......@@ -26,7 +26,7 @@ class Job @Inject() (val controllerComponents: ControllerComponents, protected v
private val queue = TableQuery[QueueTable]
private val chunks = TableQuery[ChunksTable]
def json(id: Int) = Action { implicit request
def json(id: Int) = Action { implicit request =>
implicit val jobWrites = Json.writes[JobJson]
val jobOption = sget2.downloadQueue.job(id)
if (jobOption.nonEmpty) {
......@@ -40,7 +40,7 @@ class Job @Inject() (val controllerComponents: ControllerComponents, protected v
}
}
def pause(id: Int) = Action { implicit request
def pause(id: Int) = Action { implicit request =>
val jobOption = sget2.downloadQueue.job(id)
if (jobOption.nonEmpty) {
sget2.downloadQueue.stop(id)
......@@ -50,7 +50,7 @@ class Job @Inject() (val controllerComponents: ControllerComponents, protected v
}
}
def start(id: Int) = Action { implicit request
def start(id: Int) = Action { implicit request =>
val jobOption = sget2.downloadQueue.job(id)
if (jobOption.nonEmpty) {
sget2.downloadQueue.start(id)
......@@ -60,7 +60,7 @@ class Job @Inject() (val controllerComponents: ControllerComponents, protected v
}
}
def delete(id: Int) = Action.async { implicit request
def delete(id: Int) = Action.async { implicit request =>
val jobOption = sget2.downloadQueue.job(id)
if (jobOption.nonEmpty) {
sget2.downloadQueue.stop(id)
......@@ -72,7 +72,7 @@ class Job @Inject() (val controllerComponents: ControllerComponents, protected v
val dJob = jobs.filter(_.id === id).delete
dbConfig.db.run((dChunks andThen dQueue andThen dJob).transactionally).map {
res
res =>
Redirect(routes.Queue.index())
}
} else {
......
......@@ -3,22 +3,22 @@ package controllers
import javax.inject.Inject
import play.api.i18n.I18nSupport
import play.api.mvc.{BaseController, ControllerComponents}
import sget2.SGet2
import sget2.{DownloadJob, SGet2}
/**
* Created by sgyurko on 30/08/2016.
*/
class Queue @Inject() (val controllerComponents: ControllerComponents, val sget2: SGet2) extends BaseController with I18nSupport {
def index = Action { implicit request
Ok(views.html.queue(sget2.downloadQueue.jobList))
def index = Action { implicit request =>
Ok(views.html.queue(sget2.downloadQueue.jobList.toSeq))
}
def js = Action { implicit request
def js = Action { implicit request =>
Ok(views.js.queue()).as("text/javascript")
}
def home = Action { implicit request
def home = Action { implicit request =>
Redirect(routes.Queue.index())
}
}
......@@ -19,15 +19,15 @@ trait SGetAsync {
private val Logger = LoggerFactory.getLogger(getClass)
def withErrorHandling[T](f: Future[T], fallback: T): Future[T] = {
f.recover {
case t
case t =>
Logger.error(t.getMessage)
fallback
}
}
def withErrorHandling[T](f: Future[T], fallback: T, handler: (Throwable) Unit): Future[T] = {
def withErrorHandling[T](f: Future[T], fallback: T, handler: (Throwable) => Unit): Future[T] = {
f.recover {
case t
case t =>
handler(t)
fallback
}
......@@ -38,7 +38,7 @@ trait SGetAsync {
val timer = new HashedWheelTimer(10, TimeUnit.MILLISECONDS)
val timeout = timer.newTimeout(new TimerTask {
def run(timeout: Timeout){
def run(timeout: Timeout): Unit = {
prom.failure(new TimeoutException("Operation timed out after " + after.toMillis + " millis"))
}
}, after.toNanos, TimeUnit.NANOSECONDS)
......@@ -46,7 +46,7 @@ trait SGetAsync {
val combinedFut = Future.firstCompletedOf(List(fut, prom.future))
fut.onComplete {
_ timeout.cancel()
_ => timeout.cancel()
}
combinedFut
}
......
......@@ -18,18 +18,20 @@ final case class SettingsModel(downloadPath: Option[String],
class Settings @Inject() (val controllerComponents: ControllerComponents, private val sget2: SGet2) extends BaseController with I18nSupport {
private val settingsPostForm = Form(
mapping(
"downloadPath" optional(text),
"maxActiveJobs" optional(number(min = 1, max = Defaults.MAX_ACTIVE_JOBS)),
"user" optional(text),
"pass" optional(text)
"downloadPath" -> optional(text),
"maxActiveJobs" -> optional(number(min = 1, max = Defaults.MAX_ACTIVE_JOBS)),
"user" -> optional(text),
"pass" -> optional(text)
)(SettingsModel.apply)(SettingsModel.unapply)
)
def index = Action { implicit request
def index() = Action { implicit request =>
Ok(views.html.settings(settingsPostForm.fill(getSettings)))
}
def save = Action.async(parse.form(settingsPostForm, onErrors = (formWithErrors: Form[SettingsModel]) Redirect(routes.Settings.index()))) { implicit request
def save() = Action.async(parse.form(settingsPostForm, onErrors = (formWithErrors: Form[SettingsModel]) => Redirect(routes.Settings.index()))) {
implicit request =>
val toSave = request.body
var pass = toSave.pass
......@@ -37,12 +39,12 @@ class Settings @Inject() (val controllerComponents: ControllerComponents, privat
pass = sget2.settings.getOrElse(Defaults.SETTING_PASSWORD, None)
(for {
d sget2.saveSetting(Defaults.SETTING_DOWNLOADPATH, toSave.downloadPath)
m sget2.saveSetting(Defaults.SETTING_MAX_ACTIVE_JOBS, toSave.maxActiveJobs.flatMap(i Try(i.toString).toOption))
u sget2.saveSetting(Defaults.SETTING_USERNAME, toSave.user)
p sget2.saveSetting(Defaults.SETTING_PASSWORD, pass)
d <- sget2.saveSetting(Defaults.SETTING_DOWNLOADPATH, toSave.downloadPath)
m <- sget2.saveSetting(Defaults.SETTING_MAX_ACTIVE_JOBS, toSave.maxActiveJobs.flatMap(i => Try(i.toString).toOption))
u <- sget2.saveSetting(Defaults.SETTING_USERNAME, toSave.user)
p <- sget2.saveSetting(Defaults.SETTING_PASSWORD, pass)
} yield (d, m)).map {
res
res =>
Redirect(routes.Queue.index())
}
}
......
......@@ -57,7 +57,7 @@ abstract class AbstractWorker(protected val downloadJob: DownloadJob, protected
if (threadGroup.activeCount() <= numberOfThreads) {
val slot = downloadJob.chunkMatrix.findAndMarkDownloadingEmptySlot()
if (slot._1 != -1 && slot._2 != -1) {
new Thread(threadGroup, workerThread(slot), downloadJob.id + "-worker-" + downloadJob.chunkMatrix.slotNumber(slot)).start()
new Thread(threadGroup, workerThread(slot), s"${downloadJob.id}-worker-${downloadJob.chunkMatrix.slotNumber(slot)}").start()
}
} else {
Thread.sleep(1000)
......@@ -81,7 +81,7 @@ abstract class AbstractWorker(protected val downloadJob: DownloadJob, protected
downloadJob.status = DownloadJobStatusCode.FAILED
}
} catch {
case e: InterruptedException
case e: InterruptedException =>
Logger.info(s"Worker thread ${downloadJob.id} is interrupted")
val threads = new Array[Thread](threadGroup.activeCount())
threadGroup.enumerate(threads)
......
......@@ -11,7 +11,7 @@ import scala.io.Codec
* @author GYURKS
*/
abstract class AbstractWorkerThread(downloadJob: DownloadJob, slot: (Long, Long))(implicit val codec: Codec) extends Runnable {
protected def downloadBlock(file: RandomAccessFile)
protected def downloadBlock(file: RandomAccessFile): Unit
private val Logger = LoggerFactory.getLogger(getClass)
/**
......@@ -30,10 +30,10 @@ abstract class AbstractWorkerThread(downloadJob: DownloadJob, slot: (Long, Long)
file.close()
downloadJob.chunkMatrix.markFinished(slotNumber)
} catch {
case e: IllegalArgumentException
case e: IllegalArgumentException =>
Logger.warn("Server does not support ranges. Terminating")
downloadJob.failed = true
case e: Exception
case e: Exception =>
Logger.warn(s"Worker thread ${Thread.currentThread().getName} got an exception ${e.getClass.getSimpleName}: ${e.getMessage}")
downloadJob.chunkMatrix.markEmpty(slotNumber)
}
......@@ -67,7 +67,7 @@ abstract class AbstractWorkerThread(downloadJob: DownloadJob, slot: (Long, Long)
}
private def throttleSpeed(beforeTimestamp: Long, afterTimestamp: Long, downloaded: Int) = {
val timeToDownloadBlock: Double = (afterTimestamp - beforeTimestamp) / 1000
val timeToDownloadBlock: Double = (afterTimestamp - beforeTimestamp).toDouble / 1000
val numberOfBlocksPerSecond: Double = 1000000.0 / timeToDownloadBlock
val bytesPerSecond: Double = numberOfBlocksPerSecond * downloaded
val ratio: Double = bytesPerSecond / downloadJob.bandwidthLimit.toDouble
......
......@@ -11,9 +11,9 @@ object Defaults {
final val MAX_ACTIVE_JOBS = 128
final val BUFFER_SIZE_SSD = 32768
final val BLOCK_SIZE_MATRIX = Map(
1048576000L 104857600L,
104857600L 10485760L,
10485760L 1048576L
1048576000L -> 104857600L,
104857600L -> 10485760L,
10485760L -> 1048576L
)
final val SETTING_DOWNLOADPATH = "downloadPath"
......
......@@ -54,7 +54,7 @@ class DownloadJob (private var _url: URL, private var _path: String)(implicit pr
/* Some built in magic for block size, based on size */
def getBlockSizeForFileSize(filesize: Long): Long = {
for ((k, v) Defaults.BLOCK_SIZE_MATRIX) {
for ((k, v) <- Defaults.BLOCK_SIZE_MATRIX) {
if (filesize > k) return v
}
chunkMatrix.BLOCK_SIZE
......@@ -87,7 +87,7 @@ class DownloadJob (private var _url: URL, private var _path: String)(implicit pr
chunkMatrix.initialize(size, getBlockSizeForFileSize(fileTest.length()))
}
} catch {
case e: IOException
case e: IOException =>
Logger.warn(s"Could not create random access file: ${path}");
}
}
......
......@@ -43,7 +43,7 @@ class DownloadObjectMap (implicit private val sget2: SGet2) {
/* Allocate & Initialize the chunk map with EMPTY */
this.synchronized {
chunks = new Array(numberOfChunks)
for (i chunks.indices) {
for (i <- chunks.indices) {
chunks(i) = ChunkEntry(EMPTY, 0)
}
}
......@@ -56,7 +56,7 @@ class DownloadObjectMap (implicit private val sget2: SGet2) {
*/
def findEmptyPosition(): Int = {
chunks.synchronized {
for ((slot, index) chunks.zipWithIndex) {
for ((slot, index) <- chunks.zipWithIndex) {
if (slot.status == EMPTY) return index
}
}
......@@ -157,7 +157,7 @@ class DownloadObjectMap (implicit private val sget2: SGet2) {
def persist(): DownloadObjectMapSettings = {
this.synchronized {
if (initialized) {
DownloadObjectMapSettings(chunks.map(e ChunkEntrySerialized(e.status.id, e.size)), BLOCK_SIZE)
DownloadObjectMapSettings(chunks.map(e => ChunkEntrySerialized(e.status.id, e.size)), BLOCK_SIZE)
} else {
DownloadObjectMapSettings(Array(), BLOCK_SIZE)
}
......@@ -165,14 +165,14 @@ class DownloadObjectMap (implicit private val sget2: SGet2) {
}
def load(downloadObjectMapSettings: DownloadObjectMapSettings) = {
chunks = downloadObjectMapSettings.chunks.map(e ChunkEntry(ChunkStatus(e.status), e.size))
chunks = downloadObjectMapSettings.chunks.map(e => ChunkEntry(ChunkStatus(e.status), e.size))
resetDownloading()
BLOCK_SIZE = downloadObjectMapSettings.blockSize
}
def resetDownloading() = {
chunks.synchronized {
chunks = chunks.map(c if (c.status == ChunkStatus.DOWNLOADING) ChunkEntry(ChunkStatus.EMPTY, c.size) else c)
chunks = chunks.map(c => if (c.status == ChunkStatus.DOWNLOADING) ChunkEntry(ChunkStatus.EMPTY, c.size) else c)
}
}
......
......@@ -45,7 +45,7 @@ class DownloadQueue (private val sget2: SGet2, protected val dbConfigProvider: D
* Starts all jobs
*/
def start(): Unit = {
jobList.filter(j j.status == DownloadJobStatusCode.WAITING || j.status == DownloadJobStatusCode.NOTHING).foreach(start)
jobList.filter(j => j.status == DownloadJobStatusCode.WAITING || j.status == DownloadJobStatusCode.NOTHING).foreach(start)
}
/**
......@@ -69,10 +69,10 @@ class DownloadQueue (private val sget2: SGet2, protected val dbConfigProvider: D
}
val worker = job.url.getProtocol match {
case "http" Some(new HttpWorker(job, sget2))
case "https" Some(new HttpWorker(job, sget2))
case "ftp" Some(new FtpWorker(job, sget2))
case _
case "http" => Some(new HttpWorker(job, sget2))
case "https" => Some(new HttpWorker(job, sget2))
case "ftp" => Some(new FtpWorker(job, sget2))
case _ =>
Logger.warn("Unknown protocol: s{job.url.getProtocol}, can't find a worker implementation for it")
None
}
......@@ -138,8 +138,8 @@ class DownloadQueue (private val sget2: SGet2, protected val dbConfigProvider: D
def load(): Future[Unit] = {
/* First compose a query with Slick for all the jobs */
val query = for {
q queue
j jobs if q.jobId === j.id
q <- queue
j <- jobs if q.jobId === j.id
} yield (q, j)
/* Do the DB work and then return a HTTP 200 */
......@@ -147,13 +147,13 @@ class DownloadQueue (private val sget2: SGet2, protected val dbConfigProvider: D
this code is from SGET1.0.
*/
(for {
data dbConfig.db.run(query.result)
data <- dbConfig.db.run(query.result)
} yield data).map {
data
data =>
jobList.clear()
data.foreach { t
getChunks(t._2.id).map { chunks
val chunkMatrix = DownloadObjectMapSettings(chunks.map(r ChunkEntrySerialized(r.status, r.size)).toArray, t._2.blocksize.getOrElse(0).toLong)
data.foreach { t =>
getChunks(t._2.id).map { chunks =>
val chunkMatrix = DownloadObjectMapSettings(chunks.map(r => ChunkEntrySerialized(r.status, r.size)).toArray, t._2.blocksize.getOrElse(0).toLong)
val jobSettings = DownloadJobSettings(chunkMatrix,
t._1.status, t._2.user, t._2.pass, t._2.id,
t._2.url, t._2.threads.getOrElse(0), t._2.bandwidth.getOrElse(0), t._2.created.getTime, 0,
......@@ -169,7 +169,7 @@ class DownloadQueue (private val sget2: SGet2, protected val dbConfigProvider: D
private def getChunks(jobId: Int): Future[Seq[ChunkRecord]] = {
for {
c dbConfig.db.run(chunks.filter(_.jobId === jobId).result)
c <- dbConfig.db.run(chunks.filter(_.jobId === jobId).result)
} yield c
}
}
......@@ -29,21 +29,21 @@ class SGet2 @Inject() (protected val dbConfigProvider: DatabaseConfigProvider, v
def saveSetting(key: String, value: Option[String]) = {
val query = if (settings.contains(key)) {
(for {
s TableQuery[SettingsTable] if s.key === key
s <- TableQuery[SettingsTable] if s.key === key
} yield s.value).update(value)
} else {
TableQuery[SettingsTable] += SettingsRecord(0, key, value)
}
for {
res dbConfig.db.run(query.transactionally)
res <- dbConfig.db.run(query.transactionally)
} yield ()
}
def settings = {
/* Load settings from DB and return the result. Have to wait for the future to complete, but that's all right here as
* we want to return a Map of settings rather than Future. */
val settingsList = Await.result(for { s dbConfig.db.run(TableQuery[SettingsTable].result) } yield s, Duration.Inf)
settingsList.map(s s.key s.value).toMap
val settingsList = Await.result(for { s <- dbConfig.db.run(TableQuery[SettingsTable].result) } yield s, Duration.Inf)
settingsList.map(s => s.key -> s.value).toMap
}
}
......@@ -24,13 +24,13 @@ class SGet2Startup @Inject() (private val sget2: SGet2, val lifecycle: Applicati
sget2.subscribeTopic(queueManager)
sget2.subscribeTopic(pushMessageHandler)
lifecycle.addStopHook(() Future {
lifecycle.addStopHook(() => Future {
Logger.info("Stopping SGet2")
})
/* load() will return a future. We will execute start() asynchronously once load() redeems */
sget2.downloadQueue.load().map {
res
res =>
sget2.downloadQueue.start()
}
// We don't care when the resulting future redeems, we continue startup and the thread will complete eventually.
......
......@@ -5,40 +5,40 @@
@imageLink(status: DownloadJobStatusCode) = @{
routes.Assets.at(
status match {
case STARTED "images/state-running.png"
case FAILED "images/state-failed.png"
case WAITING "images/state-paused.png"
case PAUSED "images/state-paused.png"
case FINISHED "images/state-finished.png"
case _ "images/state-unknown.png"
case STARTED => "images/state-running.png"
case FAILED => "images/state-failed.png"
case WAITING => "images/state-paused.png"
case PAUSED => "images/state-paused.png"
case FINISHED => "images/state-finished.png"
case _ => "images/state-unknown.png"
}
)
}
@operationImageLink(status: DownloadJobStatusCode) = @{
routes.Assets.at(
status match {
case STARTED "images/state-paused.png"
case FAILED "images/state-running.png"
case WAITING "images/state-running.png"
case PAUSED "images/state-running.png"
case FINISHED "images/state-paused.png"
case _ "images/state-unknown.png"
case STARTED => "images/state-paused.png"
case FAILED => "images/state-running.png"
case WAITING => "images/state-running.png"
case PAUSED => "images/state-running.png"
case FINISHED => "images/state-paused.png"
case _ => "images/state-unknown.png"