org.beangle.ems.app.blob.RemoteRepository.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of beangle-ems-app Show documentation
Show all versions of beangle-ems-app Show documentation
The Beangle EMS Application
/*
* Copyright (C) 2005, The Beangle Software.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package org.beangle.ems.app.blob
import com.google.gson.{JsonDeserializationContext, JsonDeserializer}
import org.beangle.commons.codec.digest.Digests
import org.beangle.commons.conversion.Converter
import org.beangle.commons.io.{Files, IOs}
import org.beangle.commons.lang.Strings
import org.beangle.commons.lang.Strings.isEmpty
import org.beangle.commons.logging.Logging
import org.beangle.commons.net.Networks
import org.beangle.commons.net.http.{HttpMethods, Https}
import java.io.*
import java.lang.reflect.Type
import java.net.{HttpURLConnection, URL}
import java.nio.charset.StandardCharsets
import java.time.format.DateTimeFormatter
import java.time.{Instant, LocalDateTime, ZoneId}
import java.util.Base64
class RemoteRepository(val base: String, val dir: String, user: String, key: String) extends Repository with Logging {
private val formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss")
require(!dir.endsWith("/"))
override def remove(path: String): Boolean = {
require(path.startsWith("/"))
val url = Networks.url(s"$base$dir${path}")
val conn = url.openConnection.asInstanceOf[HttpURLConnection]
Https.noverify(conn)
conn.setDoOutput(true)
conn.setRequestMethod(HttpMethods.DELETE)
val encoded = Base64.getEncoder.encodeToString((s"${user}:${key}").getBytes(StandardCharsets.UTF_8))
conn.setRequestProperty("Authorization", s"Basic $encoded")
if (conn.getResponseCode >= 300) {
throw new Exception("Remove Failed,Response code is " + conn.getResponseCode)
} else {
conn.getResponseCode == 200
}
}
override def path(p: String): Option[String] = {
require(p.startsWith("/"))
Some(s"$base$dir${p}")
}
override def url(path: String): Option[URL] = {
require(path.startsWith("/"))
val now = LocalDateTime.now.format(formatter)
val token = Digests.sha1Hex(s"$dir${path}$user$key$now")
Some(Networks.url(s"$base$dir${path}?token=$token&u=$user&t=$now"))
}
override def upload(folder: String, is: InputStream, fileName: String, owner: String): BlobMeta = {
require(folder.startsWith("/"))
val folderUrl = if (folder.endsWith("/")) folder else folder + "/"
val target = Networks.url(s"$base$dir$folderUrl")
val params = Map("owner" -> owner)
doUpload(target, is, fileName, params, Some(s"$user:$key"))
}
import java.nio.charset.StandardCharsets
import java.util.Base64
private def doUpload(url: URL, is: InputStream, fileName: String,
params: Map[String, String], basicAuth: Option[String]): BlobMeta = {
val end = "\r\n"
val twoHyphens = "--"
val boundary = "*****";
val conn = url.openConnection.asInstanceOf[HttpURLConnection]
Https.noverify(conn)
conn.setDoOutput(true)
conn.setDoInput(true)
conn.setRequestMethod(HttpMethods.POST)
conn.setRequestProperty("Content-Type", s"multipart/form-data;boundary=$boundary")
conn.setRequestProperty("Connection", "Keep-Alive")
basicAuth foreach { auth =>
val encoded = Base64.getEncoder.encodeToString((auth).getBytes(StandardCharsets.UTF_8))
conn.setRequestProperty("Authorization", s"Basic $encoded")
}
val os = conn.getOutputStream
val ds = new DataOutputStream(os)
val text = new StringBuilder
params foreach { case (k, v) =>
text.append(twoHyphens).append(boundary).append(end)
text.append(s"""Content-Disposition: form-data; name="${k}"""")
text.append(end).append(end)
text.append(v).append(end);
}
ds.write(text.toString().getBytes())
val strBuf = new StringBuilder
strBuf.append(twoHyphens).append(boundary).append(end)
strBuf.append(s"""Content-Disposition: form-data; name="file"; filename="${Files.purify(fileName)}"""")
strBuf.append(end).append(end)
ds.write(strBuf.toString().getBytes())
IOs.copy(is, ds)
ds.writeBytes(end)
ds.writeBytes(twoHyphens + boundary + twoHyphens + end)
ds.flush()
ds.close()
os.close() //don't forget to close the OutputStream
try {
if (conn.getResponseCode == 200) {
val response = IOs.readString(conn.getInputStream)
import com.google.gson.GsonBuilder
val gson = new GsonBuilder().registerTypeAdapter(classOf[Instant], new InstantAdapter).create
gson.fromJson(response, classOf[BlobMeta])
} else {
var msg: String = ""
try msg = IOs.readString(conn.getInputStream)
catch case e: Throwable => {} //ignore
throw new RuntimeException("Upload failed,response code is " + conn.getResponseCode + " and response body:" + msg)
}
} catch {
case e: Throwable =>
logger.warn("Upload failure:url:" + url.toString + " fileName:" + fileName + " params:" + params)
throw e
}
}
@throws[RuntimeException]
private def logError(str: String, e: Throwable): Unit = {
logger.error(str, e)
throw e
}
import com.google.gson.JsonElement
class InstantAdapter extends JsonDeserializer[Instant] {
def deserialize(elem: JsonElement, `type`: Type, context: JsonDeserializationContext): Instant = {
InstantConverter(elem.getAsString)
}
}
object InstantConverter extends Converter[String, Instant] {
override def apply(value: String): Instant = {
if (isEmpty(value)) return null
if (!value.endsWith("Z")) {
LocalDateTime.parse(normalize(value)).atZone(ZoneId.systemDefault).toInstant
} else {
Instant.parse(value)
}
}
}
/**
* Change DateTime Format
* 1. YYYY-MM-DD HH:mm into YYYY-MM-DDTHH:mm:00
* 2. YYYY-MM-DD HH:mm:ss into YYYY-MM-DDTHH:mm:ss
*/
def normalize(value: String): String = {
val v = if (value.length == 16) value + ":00" else value
Strings.replace(v, " ", "T")
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy