app/models/StorageEntry.scala (130 lines of code) (raw):

package models import slick.jdbc.PostgresProfile.api._ import akka.stream.Materializer import com.fasterxml.jackson.core.`type`.TypeReference import com.fasterxml.jackson.module.scala.JsonScalaEnumeration import play.api.libs.functional.syntax._ import play.api.libs.json.{JsPath, Reads, Writes} import scala.concurrent.ExecutionContext.Implicits.global import drivers._ import play.api.Logger import play.api.inject.Injector import slick.lifted.TableQuery import scala.concurrent.Future import scala.util.{Failure, Success, Try} object StorageStatus extends Enumeration { val ONLINE,OFFLINE,DISAPPEARED,MISCONFIGURED,UNKNOWN=Value } //used for jackson-databind in persistence jdbc class StorageStatusType extends TypeReference[StorageStatus.type] {} trait StorageSerializer { implicit val storageStatusWrites:Writes[StorageStatus.Value] = Writes.enumNameWrites implicit val storageStatusReads:Reads[StorageStatus.Value] = Reads.enumNameReads(StorageStatus) /*https://www.playframework.com/documentation/2.5.x/ScalaJson*/ implicit val storageWrites:Writes[StorageEntry] = ( (JsPath \ "id").writeNullable[Int] and (JsPath \ "nickname").writeNullable[String] and (JsPath \ "rootpath").writeNullable[String] and (JsPath \ "clientpath").writeNullable[String] and (JsPath \ "storageType").write[String] and (JsPath \ "user").writeNullable[String] and (JsPath \ "password").writeNullable[String] and (JsPath \ "host").writeNullable[String] and (JsPath \ "port").writeNullable[Int] and (JsPath \ "device").writeNullable[String] and (JsPath \ "supportsVersions").write[Boolean] and (JsPath \ "status").writeNullable[StorageStatus.Value] and (JsPath \ "backsUpTo").writeNullable[Int] )(unlift(StorageEntry.unapply)) implicit val storageReads:Reads[StorageEntry] = ( (JsPath \ "id").readNullable[Int] and (JsPath \ "nickname").readNullable[String] and (JsPath \ "rootpath").readNullable[String] and (JsPath \ "clientpath").readNullable[String] and (JsPath \ "storageType").read[String] and (JsPath \ "user").readNullable[String] and (JsPath \ "password").readNullable[String] and (JsPath \ "host").readNullable[String] and (JsPath \ "port").readNullable[Int] and (JsPath \ "device").readNullable[String] and (JsPath \ "supportsVersions").read[Boolean] and (JsPath \ "status").readNullable[StorageStatus.Value] and (JsPath \ "backsUpTo").readNullable[Int] )(StorageEntry.apply _) } case class StorageEntry(id: Option[Int], nickname:Option[String], rootpath: Option[String], clientpath: Option[String], storageType: String, user:Option[String], password:Option[String], host:Option[String], port:Option[Int], device:Option[String], supportsVersions: Boolean, @JsonScalaEnumeration(classOf[StorageStatusType]) status:Option[StorageStatus.Value], backsUpTo:Option[Int]) extends PlutoModel { def getStorageDriver(implicit injector:Injector):Option[StorageDriver] = { val logger: Logger = Logger(this.getClass) if(storageType=="Local") { Some(new PathStorage(this)) } else if(storageType=="ObjectMatrix") { Some(new MatrixStoreDriver(this)) } else { logger.warn(s"No storage driver defined for $storageType") None } } def repr:String = { s"$storageType (${rootpath.getOrElse("no root path")}) ${host.getOrElse("(no host)")}" } def save(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Try[StorageEntry]] = id match { case None=> val insertQuery = TableQuery[StorageEntryRow] returning TableQuery[StorageEntryRow].map(_.id) into ((item,id)=>item.copy(id=Some(id))) db.run( (insertQuery+=this).asTry ) case Some(realEntityId)=> db.run( TableQuery[StorageEntryRow].filter(_.id===realEntityId).update(this).asTry ).map({ case Success(rowsAffected)=>Success(this) case Failure(error)=>Failure(error) }) } def validatePathExists(filePath:String, version:Int)(implicit injector:Injector) = getStorageDriver.map(drv=>drv.pathExists(filePath, version)) match { case None=>Left(s"No storage driver exists for storage $id ($rootpath)!") case Some(result)=>Right(result) } } class StorageEntryRow(tag:Tag) extends Table[StorageEntry](tag, "StorageEntry") { implicit val storageStatusMapper = MappedColumnType.base[StorageStatus.Value,String]( e=>e.toString(), s=>StorageStatus.withName(s) ) def id = column[Int]("id",O.PrimaryKey, O.AutoInc) def nickname = column[Option[String]]("s_nickname") def rootpath = column[Option[String]]("s_root_path") def clientpath = column[Option[String]]("s_client_path") def storageType = column[String]("s_storage_type") def user = column[Option[String]]("s_user") def password = column[Option[String]]("s_password") def host = column[Option[String]]("s_host") def port = column[Option[Int]]("i_port") def device = column[Option[String]]("s_device") def status = column[Option[StorageStatus.Value]]("e_status") def supportsVersions = column[Boolean]("b_versions") def backsUpTo = column[Option[Int]]("k_backs_up_to") def * = (id.?,nickname, rootpath,clientpath,storageType,user,password,host,port,device, supportsVersions, status, backsUpTo) <> (StorageEntry.tupled, StorageEntry.unapply) } object StorageEntryHelper { def entryFor(entryId: Int)(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Option[StorageEntry]] = db.run( TableQuery[StorageEntryRow].filter(_.id===entryId).result ).map(_.headOption) def defaultProjectfileStorage(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Option[StorageEntry]] = Defaults.entryFor("project_storage_id").flatMap({ case Success(maybeOption)=> maybeOption match { case Some(storageEntryId)=>StorageEntryHelper.entryFor(storageEntryId.toInt) case None=>Future(None) } case Failure(error)=>throw error }) def allStorages(implicit db:slick.jdbc.PostgresProfile#Backend#Database):Future[Try[Seq[StorageEntry]]] = { db.run( TableQuery[StorageEntryRow].result.asTry ) } }