This commit is contained in:
xis 2023-10-12 19:40:38 +02:00
parent 70ed4185fd
commit aecc8c5973
4 changed files with 32 additions and 62 deletions

View file

@ -32,48 +32,31 @@ class UpnpController(
@PathVariable("uid") uid: String,
request: HttpServletRequest
): Resource {
logger.info { "GET ICON request from ${request.remoteAddr}: ${request.requestURI}" }
logger.info { "GET icon request from ${request.remoteAddr}: ${request.requestURI}" }
return InputStreamResource(MediaServer.iconResource());
}
@RequestMapping(
method = [GET, HEAD], value = [
method = [GET, HEAD, POST], value = [
"/dev/{uid}/desc",
"/dev/{uid}/svc/upnp-org/ContentDirectory/desc",
"/dev/{uid}/svc/upnp-org/ConnectionManager/desc"
],
produces = ["application/xml;charset=utf8", "text/xml;charset=utf8"]
)
fun handleGet(
@PathVariable("uid") uid: String,
request: HttpServletRequest
): ResponseEntity<Any> {
logger.info { "GET request from ${request.remoteAddr}: ${request.requestURI}" }
val r = upnpStreamProcessor.processMessage(streamRequestMapper.map(request))
return ResponseEntity(
r.body,
HttpHeaders().also { h -> r.headers.entries.forEach { h.add(it.key, it.value.joinToString { it }) } },
HttpStatusCode.valueOf(r.operation.statusCode)
)
}
@RequestMapping(
method = [POST], value = [
"/dev/{uid}/svc/upnp-org/ConnectionManager/desc",
"/dev/{uid}/svc/upnp-org/ContentDirectory/action"
],
produces = ["application/xml;charset=utf8", "text/xml;charset=utf8"]
)
fun handlePost(
fun handleUpnp(
@PathVariable("uid") uid: String,
request: HttpServletRequest
): ResponseEntity<Any> {
logger.info { "POST request from ${request.remoteAddr}: ${request.requestURI}" }
val r = upnpStreamProcessor.processMessage(streamRequestMapper.map(request))
return ResponseEntity(
r.body,
HttpHeaders().also { h -> r.headers.entries.forEach { h.add(it.key, it.value.joinToString { it }) } },
HttpStatusCode.valueOf(r.operation.statusCode)
)
logger.info { "Upnp ${request.method} request from ${request.remoteAddr}: ${request.requestURI}" }
return with(upnpStreamProcessor.processMessage(streamRequestMapper.map(request))) {
ResponseEntity(
body,
HttpHeaders().also { h -> headers.entries.forEach { e -> h.add(e.key, e.value.joinToString { it }) } },
HttpStatusCode.valueOf(operation.statusCode)
)
}
}
companion object : KLogging()

View file

@ -14,7 +14,7 @@ import java.util.function.Consumer
@Component
class MediaDB(
class NextcloudDB(
private val nextcloudConfig: NextcloudConfigDiscovery,
private val mimetypeRepository: MimetypeRepository,
private val filecacheRepository: FilecacheRepository,

View file

@ -1,25 +1,26 @@
package net.schowek.nextclouddlna.nextcloud.content
import jakarta.annotation.PostConstruct
import mu.KLogging
import net.schowek.nextclouddlna.nextcloud.MediaDB
import net.schowek.nextclouddlna.nextcloud.NextcloudDB
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import java.time.Instant
import java.util.concurrent.atomic.AtomicInteger
import java.util.regex.Pattern
@Component
class ContentTreeProvider(
private val mediaDB: MediaDB
private val nextcloudDB: NextcloudDB
) {
private var tree = buildContentTree()
private var lastMTime = 0L
@Scheduled(fixedDelay = 1000 * 60, initialDelay = 1000 * 60)
@Scheduled(fixedDelay = REBUILD_TREE_DELAY_IN_MS, initialDelay = REBUILD_TREE_INIT_DELAY_IN_MS)
final fun rebuildTree() {
val maxMtime: Long = mediaDB.maxMtime()
if (lastMTime < maxMtime) {
val maxMtime: Long = nextcloudDB.maxMtime()
val now = Instant.now().epochSecond
if (lastMTime < maxMtime || lastMTime + MAX_REBUILD_OFFSET_IN_S > now) {
logger.info("ContentTree seems to be outdated - Loading...")
this.tree = buildContentTree()
lastMTime = maxMtime
@ -30,12 +31,12 @@ class ContentTreeProvider(
val tree = ContentTree()
val root = ContentNode(0, -1, "ROOT")
tree.addNode(root)
mediaDB.mainNodes().forEach { n ->
nextcloudDB.mainNodes().forEach { n ->
root.addNode(n)
fillNode(n, tree)
}
logger.info("Getting content from group folders...")
mediaDB.groupFolders().forEach { n ->
nextcloudDB.groupFolders().forEach { n ->
logger.info(" Group folder found: {}", n.name)
root.addNode(n)
fillNode(n, tree)
@ -48,7 +49,7 @@ class ContentTreeProvider(
private fun loadThumbnails(tree: ContentTree) {
logger.info("Loading thumbnails...")
val thumbsCount = AtomicInteger()
mediaDB.processThumbnails { thumb ->
nextcloudDB.processThumbnails { thumb ->
val id = getItemIdForThumbnail(thumb)
if (id != null) {
val item = tree.getItem(id)
@ -72,7 +73,7 @@ class ContentTreeProvider(
}
private fun fillNode(node: ContentNode, tree: ContentTree) {
mediaDB.appendChildren(node)
nextcloudDB.appendChildren(node)
tree.addNode(node)
node.getItems().forEach { item ->
logger.debug("Adding item[{}]: " + item.path, item.id)
@ -87,7 +88,11 @@ class ContentTreeProvider(
fun getItem(id: String): ContentItem? = tree.getItem(id)
fun getNode(id: String): ContentNode? = tree.getNode(id)
companion object : KLogging()
companion object : KLogging() {
const val REBUILD_TREE_DELAY_IN_MS = 1000 * 60L // 1m
const val REBUILD_TREE_INIT_DELAY_IN_MS = 1000 * 60L // 1m
const val MAX_REBUILD_OFFSET_IN_S = 60 * 60 * 12L // 12h
}
}

View file

@ -12,8 +12,9 @@ class StreamRequestMapper {
fun map(request: HttpServletRequest): StreamRequestMessage {
val requestMessage = StreamRequestMessage(
UpnpRequest.Method.getByHttpName(request.method),
URI(request.requestURI)
// TODO put request.inputStream.readBytes() here
URI(request.requestURI),
// TODO check if request is binary and create body as unwrapped byteArray
String(request.inputStream.readBytes())
)
if (requestMessage.operation.method == UpnpRequest.Method.UNKNOWN) {
logger.warn("Method not supported by UPnP stack: {}", request.method)
@ -22,28 +23,9 @@ class StreamRequestMapper {
requestMessage.connection = MyHttpServerConnection(request)
requestMessage.headers = createHeaders(request)
setBody(request, requestMessage)
return requestMessage
}
private fun setBody(
request: HttpServletRequest,
requestMessage: StreamRequestMessage
) {
val bodyBytes = request.inputStream.readBytes()
logger.debug(" Reading request body bytes: " + bodyBytes.size)
if (bodyBytes.isNotEmpty() && requestMessage.isContentTypeMissingOrText) {
logger.debug("Request contains textual entity body, converting then setting string on message")
requestMessage.setBodyCharacters(bodyBytes)
} else if (bodyBytes.isNotEmpty()) {
logger.debug("Request contains binary entity body, setting bytes on message")
requestMessage.setBody(UpnpMessage.BodyType.BYTES, bodyBytes)
} else {
logger.debug("Request did not contain entity body")
}
}
private fun createHeaders(request: HttpServletRequest): UpnpHeaders {
val headers = mutableMapOf<String, List<String>>()
with(request.headerNames) {