From eef25cd418b8a9b06f252c3f98da889260aef74d Mon Sep 17 00:00:00 2001 From: xis Date: Fri, 13 Oct 2023 17:23:17 +0200 Subject: [PATCH] refactoring --- .../net/schowek/nextclouddlna/DllnaService.kt | 32 ++-- .../controller/ContentController.kt | 33 ++-- .../dlna/RegistryWithOverrides.kt | 6 - .../nextclouddlna/dlna/StreamRequestMapper.kt | 13 -- .../dlna/media/ContentDirectoryService.kt | 79 +++++----- .../nextclouddlna/dlna/media/MediaServer.kt | 18 +-- .../nextclouddlna/dlna/media/NodeConverter.kt | 34 ++-- .../dlna/transport/ApacheStreamClient.kt | 126 ++++----------- .../ApacheStreamClientConfiguration.kt | 18 +-- .../transport/MyStreamServerConfiguration.kt | 5 +- .../dlna/transport/MyStreamServerImpl.kt | 25 +-- .../dlna/transport/StreamsLoggerHelper.kt | 146 ------------------ .../nextcloud/content/ContentElements.kt | 18 +-- .../nextcloud/content/ContentTreeProvider.kt | 20 +-- .../nextclouddlna/util/ExternalUrls.kt | 4 +- 15 files changed, 151 insertions(+), 426 deletions(-) delete mode 100644 src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/StreamsLoggerHelper.kt diff --git a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt b/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt index 109a57d..8453f8d 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt @@ -71,39 +71,27 @@ class DlnaService( inner class MyUpnpService( configuration: UpnpServiceConfiguration ) : UpnpServiceImpl(configuration) { - override fun createRegistry(pf: ProtocolFactory): Registry { - return RegistryImplWithOverrides(this) - } + override fun createRegistry(pf: ProtocolFactory) = + RegistryImplWithOverrides(this) } private inner class MyUpnpServiceConfiguration : DefaultUpnpServiceConfiguration(serverInfoProvider.port) { - override fun createStreamClient(): StreamClient<*> { - return ApacheStreamClient( - ApacheStreamClientConfiguration(syncProtocolExecutorService) - ) - } + override fun createStreamClient() = + ApacheStreamClient(ApacheStreamClientConfiguration(syncProtocolExecutorService)) - override fun createStreamServer(networkAddressFactory: NetworkAddressFactory): StreamServer<*> { - return MyStreamServerImpl( - MyStreamServerConfiguration(networkAddressFactory.streamListenPort) - ) - } + override fun createStreamServer(networkAddressFactory: NetworkAddressFactory) = + MyStreamServerImpl(MyStreamServerConfiguration(networkAddressFactory.streamListenPort)) - override fun createNetworkAddressFactory( - streamListenPort: Int, - multicastResponsePort: Int - ): NetworkAddressFactory { - return MyNetworkAddressFactory(streamListenPort, multicastResponsePort) - } + override fun createNetworkAddressFactory(streamListenPort: Int, multicastResponsePort: Int) = + MyNetworkAddressFactory(streamListenPort, multicastResponsePort) } inner class MyNetworkAddressFactory( streamListenPort: Int, multicastResponsePort: Int ) : NetworkAddressFactoryImpl(streamListenPort, multicastResponsePort) { - override fun isUsableAddress(iface: NetworkInterface, address: InetAddress): Boolean { - return addressesToBind.contains(address) - } + override fun isUsableAddress(iface: NetworkInterface, address: InetAddress) = + addressesToBind.contains(address) } companion object : KLogging() diff --git a/src/main/kotlin/net/schowek/nextclouddlna/controller/ContentController.kt b/src/main/kotlin/net/schowek/nextclouddlna/controller/ContentController.kt index 9feb9e1..1993e13 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/controller/ContentController.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/controller/ContentController.kt @@ -25,7 +25,7 @@ import java.util.* @RestController class ContentController( private val contentTreeProvider: ContentTreeProvider -) { +) { @RequestMapping(method = [RequestMethod.GET, RequestMethod.HEAD], value = ["/c/{id}"]) @ResponseBody fun getResource( @@ -33,20 +33,20 @@ class ContentController( request: HttpServletRequest, response: HttpServletResponse ): ResponseEntity { - val item = contentTreeProvider.getItem(id) - if (item == null) { + return contentTreeProvider.getItem(id)?.let { item -> + if (!request.getHeaders("range").hasMoreElements()) { + logger.info("Serving content {} {}", request.method, id) + } + val fileSystemResource = FileSystemResource(item.path) + response.addHeader("Content-Type", item.format.mime) + response.addHeader("contentFeatures.dlna.org", makeProtocolInfo(item.format).toString()) + response.addHeader("transferMode.dlna.org", "Streaming") + response.addHeader("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*") + ResponseEntity(fileSystemResource, HttpStatus.OK) + } ?: let { logger.info("Could not find item id: {}", id) - return ResponseEntity(HttpStatus.NOT_FOUND) + ResponseEntity(HttpStatus.NOT_FOUND) } - if (!request.getHeaders("range").hasMoreElements()) { - logger.info("Serving content {} {}", request.method, id) - } - val fileSystemResource = FileSystemResource(item.path) - response.addHeader("Content-Type", item.format.mime) - response.addHeader("contentFeatures.dlna.org", makeProtocolInfo(item.format).toString()) - response.addHeader("transferMode.dlna.org", "Streaming") - response.addHeader("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*") - return ResponseEntity(fileSystemResource, HttpStatus.OK) } @RequestMapping(method = [RequestMethod.GET], value = ["/rebuild"]) @@ -57,9 +57,7 @@ class ContentController( } private fun makeProtocolInfo(mediaFormat: MediaFormat): DLNAProtocolInfo { - val attributes = EnumMap>( - Type::class.java - ) + val attributes = EnumMap>(Type::class.java) if (mediaFormat.contentGroup === VIDEO) { attributes[DLNA_ORG_PN] = DLNAProfileAttribute(AVC_MP4_LPCM) attributes[DLNA_ORG_OP] = DLNAOperationsAttribute(RANGE) @@ -73,6 +71,7 @@ class ContentController( } return DLNAProtocolInfo(Protocol.HTTP_GET, ProtocolInfo.WILDCARD, mediaFormat.mime, attributes) } - companion object: KLogging() + + companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/RegistryWithOverrides.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/RegistryWithOverrides.kt index ce2fa9c..e87463d 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/RegistryWithOverrides.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/RegistryWithOverrides.kt @@ -34,11 +34,5 @@ class RegistryImplWithOverrides( } else super.getResource(pathQuery) } - fun maintain() { - logger.info { "REGISTRY MAINTAIN" } - Thread(registryMaintainer).start() - logger.info { "REGISTRY MAINTAIN DONE" } - } - companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/StreamRequestMapper.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/StreamRequestMapper.kt index e9e6670..03437a1 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/StreamRequestMapper.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/StreamRequestMapper.kt @@ -21,7 +21,6 @@ class StreamRequestMapper { throw RuntimeException("Method not supported: {}" + request.method) } - requestMessage.connection = MyHttpServerConnection(request) requestMessage.headers = createHeaders(request) return requestMessage } @@ -38,18 +37,6 @@ class StreamRequestMapper { return UpnpHeaders(headers) } - inner class MyHttpServerConnection( - private val request: HttpServletRequest - ) : Connection { - override fun isOpen() = true - - override fun getRemoteAddress(): InetAddress? = - request.remoteAddr?.let { InetAddress.getByName(request.remoteAddr) } - - override fun getLocalAddress(): InetAddress? = - request.localAddr?.let { InetAddress.getByName(request.localAddr) } - } - companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/ContentDirectoryService.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/ContentDirectoryService.kt index d2455db..49a0480 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/ContentDirectoryService.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/ContentDirectoryService.kt @@ -43,27 +43,29 @@ class ContentDirectoryService( ): BrowseResult { val startTime = System.nanoTime() return try { - // TODO optimize: - // * checking if it's node or item before fetching them in two queries - // * not fetching children for METADATA browse flag - val node = contentTreeProvider.getNode(objectID) - if (node != null) { + contentTreeProvider.getNode(objectID)?.let { node -> if (browseFlag == METADATA) { - val didl = DIDLContent() - didl.addContainer(nodeConverter.makeContainerWithoutSubContainers(node)) - return BrowseResult(DIDLParser().generate(didl), 1, 1) + val result = DIDLParser().generate( + DIDLContent().also { + it.addContainer(nodeConverter.makeContainerWithoutSubContainers(node)) + } + ) + return BrowseResult(result, 1, 1) } val containers: List = nodeConverter.makeSubContainersWithoutTheirSubContainers(node) val items: List = nodeConverter.makeItems(node) return toRangedResult(containers, items, firstResult, maxResults) } - val item = contentTreeProvider.getItem(objectID) - if (item != null) { - val didl = DIDLContent() - didl.addItem(nodeConverter.makeItem(item)) - val result = DIDLParser().generate(didl) + + contentTreeProvider.getItem(objectID)?.let { item -> + val result = DIDLParser().generate( + DIDLContent().also { + it.addItem(nodeConverter.makeItem(item)) + } + ) return BrowseResult(result, 1, 1) } + BrowseResult(DIDLParser().generate(DIDLContent()), 0, 0) } catch (e: Exception) { logger.warn( @@ -78,33 +80,32 @@ class ContentDirectoryService( ) } } - - companion object : KLogging() { - @Throws(Exception::class) - private fun toRangedResult( - containers: List, - items: List, - firstResult: Long, - maxResultsParam: Long - ): BrowseResult { - val maxResults = if (maxResultsParam == 0L) (containers.size + items.size).toLong() else maxResultsParam - val didl = DIDLContent() - if (containers.size > firstResult) { - val from = firstResult.toInt() - val to = min((firstResult + maxResults).toInt(), containers.size) - didl.containers = containers.subList(from, to) - } - if (didl.containers.size < maxResults) { - val from = max(firstResult - containers.size, 0).toInt() - val to = min(items.size, from + (maxResults - didl.containers.size).toInt()) - didl.items = items.subList(from, to) - } - return BrowseResult( - DIDLParser().generate(didl), - (didl.containers.size + didl.items.size).toLong(), - (containers.size + items.size).toLong() - ) + @Throws(Exception::class) + private fun toRangedResult( + containers: List, + items: List, + firstResult: Long, + maxResultsParam: Long + ): BrowseResult { + val maxResults = if (maxResultsParam == 0L) (containers.size + items.size).toLong() else maxResultsParam + val didl = DIDLContent() + if (containers.size > firstResult) { + val from = firstResult.toInt() + val to = min((firstResult + maxResults).toInt(), containers.size) + didl.containers = containers.subList(from, to) } + if (didl.containers.size < maxResults) { + val from = max(firstResult - containers.size, 0).toInt() + val to = min(items.size, from + (maxResults - didl.containers.size).toInt()) + didl.items = items.subList(from, to) + } + return BrowseResult( + DIDLParser().generate(didl), + (didl.containers.size + didl.items.size).toLong(), + (containers.size + items.size).toLong() + ) } + + companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt index a313e88..819bd94 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt @@ -1,6 +1,5 @@ package net.schowek.nextclouddlna.dlna.media -import jakarta.annotation.PostConstruct import mu.KLogging import net.schowek.nextclouddlna.util.ExternalUrls import org.jupnp.model.meta.* @@ -10,7 +9,6 @@ import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import java.io.IOException -import java.io.InputStream @Component @@ -24,7 +22,7 @@ class MediaServer( externalUrls: ExternalUrls ) { final val device = LocalDevice( - DeviceIdentity(uniqueSystemIdentifier("Nextcloud-DLNA-MediaServer"), 300), + DeviceIdentity(uniqueSystemIdentifier("Nextcloud-DLNA-MediaServer"), ADVERTISEMENT_AGE_IN_S), UDADeviceType(DEVICE_TYPE, VERSION), DeviceDetails(friendlyName, externalUrls.selfURI), createDeviceIcon(), @@ -36,24 +34,22 @@ class MediaServer( } companion object : KLogging() { + const val ICON_FILENAME = "icon.png" private const val DEVICE_TYPE = "MediaServer" private const val VERSION = 1 - const val ICON_FILENAME = "icon.png" + private const val ADVERTISEMENT_AGE_IN_S = 60 @Throws(IOException::class) - fun createDeviceIcon(): Icon { - val resource = iconResource() - return resource.use { res -> + fun createDeviceIcon() = with(iconResource()) { + this.use { res -> Icon("image/png", 48, 48, 8, ICON_FILENAME, res).also { it.validate() } } } - fun iconResource(): InputStream { - return MediaServer::class.java.getResourceAsStream("/$ICON_FILENAME") - ?: throw IllegalStateException("Icon not found.") - } + fun iconResource() = MediaServer::class.java.getResourceAsStream("/$ICON_FILENAME") + ?: throw IllegalStateException("Icon not found.") } } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/NodeConverter.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/NodeConverter.kt index baac7b0..57b1f9c 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/NodeConverter.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/NodeConverter.kt @@ -31,24 +31,20 @@ class NodeConverter( val externalUrls: ExternalUrls ) { fun makeSubContainersWithoutTheirSubContainers(n: ContentNode) = - n.getNodes().map { node -> makeContainerWithoutSubContainers(node) }.toList() + n.nodes.map { node -> makeContainerWithoutSubContainers(node) }.toList() - fun makeContainerWithoutSubContainers(n: ContentNode): Container { - val c = Container() - c.setClazz(DIDLObject.Class("object.container")) - c.setId("${n.id}") - c.setParentID("${n.parentId}") - c.setTitle(n.name) + fun makeContainerWithoutSubContainers(n: ContentNode) = Container().also { c -> + c.clazz = DIDLObject.Class("object.container") + c.id = "${n.id}" + c.parentID = "${n.parentId}" + c.title = n.name c.childCount = n.nodeAndItemCount - c.setRestricted(true) - c.setWriteStatus(NOT_WRITABLE) + c.isRestricted = true + c.writeStatus = NOT_WRITABLE c.isSearchable = true - return c } - fun makeItems(n: ContentNode): List = - n.getItems().map { item -> makeItem(item) }.toList() - + fun makeItems(n: ContentNode): List = n.items.map { item -> makeItem(item) }.toList() fun makeItem(c: ContentItem): Item { val res = Res(c.format.asMimetype(), c.fileLength, externalUrls.contentUrl(c.id)) @@ -58,10 +54,14 @@ class NodeConverter( AUDIO -> AudioItem("${c.id}", "${c.parentId}", c.name, "", res) else -> throw IllegalArgumentException() }.also { - val t = c.thumb - if (t != null) { - val thumbUri: String = externalUrls.contentUrl(t.id) - it.addResource(Res(makeProtocolInfo(t.format.asMimetype()), t.fileLength, thumbUri)) + c.thumb?.let { t -> + it.addResource( + Res( + makeProtocolInfo(t.format.asMimetype()), + t.fileLength, + externalUrls.contentUrl(t.id) + ) + ) } } } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt index 998a36e..0b44f92 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt @@ -1,19 +1,17 @@ package net.schowek.nextclouddlna.dlna.transport import mu.KLogging -import org.apache.http.* +import org.apache.http.HttpMessage +import org.apache.http.HttpVersion +import org.apache.http.NoHttpResponseException import org.apache.http.client.ResponseHandler import org.apache.http.client.config.RequestConfig -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase import org.apache.http.client.methods.HttpGet -import org.apache.http.client.methods.HttpPost import org.apache.http.client.methods.HttpRequestBase import org.apache.http.config.ConnectionConfig import org.apache.http.config.RegistryBuilder import org.apache.http.conn.socket.ConnectionSocketFactory import org.apache.http.conn.socket.PlainConnectionSocketFactory -import org.apache.http.entity.ByteArrayEntity -import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.DefaultHttpRequestRetryHandler import org.apache.http.impl.client.HttpClients @@ -24,7 +22,6 @@ import org.jupnp.model.message.* import org.jupnp.model.message.header.UpnpHeader import org.jupnp.transport.spi.AbstractStreamClient import java.nio.charset.Charset -import java.nio.charset.UnsupportedCharsetException import java.util.concurrent.Callable @@ -77,42 +74,17 @@ class ApacheStreamClient( override fun createRequest(requestMessage: StreamRequestMessage): HttpRequestBase { val requestOperation = requestMessage.operation - val request: HttpRequestBase - when (requestOperation.method) { - UpnpRequest.Method.GET -> { - request = HttpGet(requestOperation.uri) - } - + val request = when (requestOperation.method) { + UpnpRequest.Method.GET, + UpnpRequest.Method.NOTIFY, + UpnpRequest.Method.POST, + UpnpRequest.Method.UNSUBSCRIBE, UpnpRequest.Method.SUBSCRIBE -> { - request = object : HttpGet(requestOperation.uri) { - override fun getMethod(): String { - return UpnpRequest.Method.SUBSCRIBE.httpName - } + object : HttpGet(requestOperation.uri) { + override fun getMethod() = requestOperation.method.httpName } } - UpnpRequest.Method.UNSUBSCRIBE -> { - request = object : HttpGet(requestOperation.uri) { - override fun getMethod(): String { - return UpnpRequest.Method.UNSUBSCRIBE.httpName - } - } - } - - UpnpRequest.Method.POST -> { - request = HttpPost(requestOperation.uri) - (request as HttpEntityEnclosingRequestBase).entity = createHttpRequestEntity(requestMessage) - } - - UpnpRequest.Method.NOTIFY -> { - request = object : HttpPost(requestOperation.uri) { - override fun getMethod(): String { - return UpnpRequest.Method.NOTIFY.httpName - } - } - (request as HttpEntityEnclosingRequestBase).entity = createHttpRequestEntity(requestMessage) - } - else -> throw RuntimeException("Unknown HTTP method: " + requestOperation.httpMethodName) } @@ -143,9 +115,6 @@ class ApacheStreamClient( ): Callable { return Callable { logger.trace("Sending HTTP request: $requestMessage") - if (logger.isTraceEnabled) { - StreamsLoggerHelper.logStreamClientRequestMessage(requestMessage) - } httpClient.execute(request, createResponseHandler(requestMessage)) } } @@ -172,79 +141,50 @@ class ApacheStreamClient( clientConnectionManager.shutdown() } - private fun createHttpRequestEntity(upnpMessage: UpnpMessage<*>): HttpEntity { - return if (upnpMessage.bodyType == UpnpMessage.BodyType.BYTES) { - logger.trace("Preparing HTTP request entity as byte[]") - ByteArrayEntity(upnpMessage.bodyBytes) - } else { - logger.trace("Preparing HTTP request entity as string") - var charset = upnpMessage.contentTypeCharset - if (charset == null) { - charset = "UTF-8" - } - try { - StringEntity(upnpMessage.bodyString, charset) - } catch (ex: UnsupportedCharsetException) { - logger.trace("HTTP request does not support charset: {}", charset) - throw RuntimeException(ex) - } - } - } - private fun createResponseHandler(requestMessage: StreamRequestMessage?): ResponseHandler { - return ResponseHandler { httpResponse: HttpResponse -> - val statusLine = httpResponse.statusLine + return ResponseHandler { response -> + val statusLine = response.statusLine logger.trace("Received HTTP response: $statusLine") // Status val responseOperation = UpnpResponse(statusLine.statusCode, statusLine.reasonPhrase) - // Message val responseMessage = StreamResponseMessage(responseOperation) - // Headers - responseMessage.headers = UpnpHeaders(getHeaders(httpResponse)) - + responseMessage.headers = UpnpHeaders(getHeaders(response)) // Body - val entity = httpResponse.entity - if (entity == null || entity.contentLength == 0L) { + response.entity?.let { entity -> + val data = EntityUtils.toByteArray(entity) + if (data != null) { + if (responseMessage.isContentTypeMissingOrText) { + logger.trace("HTTP response message contains text entity") + responseMessage.setBodyCharacters(data) + } else { + logger.trace("HTTP response message contains binary entity") + responseMessage.setBody(UpnpMessage.BodyType.BYTES, data) + } + } else { + logger.trace("HTTP response message has no entity") + } + responseMessage + } ?: let { logger.trace("HTTP response message has no entity") return@ResponseHandler responseMessage } - val data = EntityUtils.toByteArray(entity) - if (data != null) { - if (responseMessage.isContentTypeMissingOrText) { - logger.trace("HTTP response message contains text entity") - responseMessage.setBodyCharacters(data) - } else { - logger.trace("HTTP response message contains binary entity") - responseMessage.setBody(UpnpMessage.BodyType.BYTES, data) - } - } else { - logger.trace("HTTP response message has no entity") - } - if (logger.isTraceEnabled) { - StreamsLoggerHelper.logStreamClientResponseMessage(responseMessage, requestMessage) - } - responseMessage } } companion object : KLogging() { private fun addHeaders(httpMessage: HttpMessage, headers: Headers) { - for ((key, value1) in headers) { - for (value in value1) { - httpMessage.addHeader(key, value) - } - } + headers.map { header -> header.value.forEach { httpMessage.addHeader(header.key, it) } } } private fun getHeaders(httpMessage: HttpMessage): Headers { - val headers = Headers() - for (header in httpMessage.allHeaders) { - headers.add(header.name, header.value) + return Headers().also { headers -> + httpMessage.allHeaders.forEach { + headers.add(it.name, it.value) + } } - return headers } } } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt index d9d04a2..a05ca44 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt @@ -4,18 +4,12 @@ import org.jupnp.transport.spi.AbstractStreamClientConfiguration import java.util.concurrent.ExecutorService -class ApacheStreamClientConfiguration : AbstractStreamClientConfiguration { - var maxTotalConnections = 1024 - - var maxTotalPerRoute = 100 - - var contentCharset = "UTF-8" // UDA spec says it's always UTF-8 entity content - - constructor(timeoutExecutorService: ExecutorService?) : super(timeoutExecutorService) - constructor(timeoutExecutorService: ExecutorService?, timeoutSeconds: Int) : super( - timeoutExecutorService, - timeoutSeconds - ) +class ApacheStreamClientConfiguration( + timeoutExecutorService: ExecutorService +) : AbstractStreamClientConfiguration(timeoutExecutorService) { + val maxTotalConnections = 1024 + val maxTotalPerRoute = 100 + val contentCharset = "UTF-8" // UDA spec says it's always UTF-8 entity content val socketBufferSize: Int get() = -1 diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt index d5125d1..5df9171 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt @@ -5,9 +5,6 @@ import org.jupnp.transport.spi.StreamServerConfiguration class MyStreamServerConfiguration( private val listenPort: Int ) : StreamServerConfiguration { - val tcpConnectionBacklog = 0 - override fun getListenPort(): Int { - return listenPort - } + override fun getListenPort() = listenPort } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt index ac0123c..5108ca7 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt @@ -1,6 +1,5 @@ package net.schowek.nextclouddlna.dlna.transport -import com.sun.net.httpserver.HttpExchange import mu.KLogging import org.jupnp.transport.Router import org.jupnp.transport.spi.StreamServer @@ -10,28 +9,16 @@ import java.net.InetAddress class MyStreamServerImpl( private val configuration: MyStreamServerConfiguration ) : StreamServer { - override fun init(bindAddress: InetAddress, router: Router) { - } + override fun init(bindAddress: InetAddress, router: Router) {} - override fun getPort(): Int { - return configuration.listenPort; - } + override fun getPort() = configuration.listenPort - override fun getConfiguration(): MyStreamServerConfiguration { - return configuration - } + override fun getConfiguration() = configuration - override fun run() { - } + override fun run() {} - override fun stop() { - } + override fun stop() {} - private fun isConnectionOpen(exchange: HttpExchange?): Boolean { - logger.warn("Can't check client connection, socket access impossible on JDK webserver!") - return true - } - - companion object: KLogging() + companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/StreamsLoggerHelper.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/StreamsLoggerHelper.kt deleted file mode 100644 index 050c878..0000000 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/StreamsLoggerHelper.kt +++ /dev/null @@ -1,146 +0,0 @@ -package net.schowek.nextclouddlna.dlna.transport - -import io.micrometer.common.util.StringUtils -import mu.KLogging -import org.jupnp.model.message.StreamRequestMessage -import org.jupnp.model.message.StreamResponseMessage -import org.jupnp.model.message.UpnpMessage - - -class StreamsLoggerHelper { - companion object : KLogging() { - private const val HTTPSERVER_REQUEST_BEGIN = - "================================== HTTPSERVER REQUEST BEGIN =====================================" - private const val HTTPSERVER_REQUEST_END = - "================================== HTTPSERVER REQUEST END =======================================" - private const val HTTPSERVER_RESPONSE_BEGIN = - "================================== HTTPSERVER RESPONSE BEGIN ====================================" - private const val HTTPSERVER_RESPONSE_END = - "================================== HTTPSERVER RESPONSE END ======================================" - private const val HTTPCLIENT_REQUEST_BEGIN = - "==================================== HTTPCLIENT REQUEST BEGIN ====================================" - private const val HTTPCLIENT_REQUEST_END = - "==================================== HTTPCLIENT REQUEST END ======================================" - private const val HTTPCLIENT_RESPONSE_BEGIN = - "==================================== HTTPCLIENT RESPONSE BEGIN ===================================" - private const val HTTPCLIENT_RESPONSE_END = - "==================================== HTTPCLIENT RESPONSE END =====================================" - - fun logStreamServerRequestMessage(requestMessage: StreamRequestMessage) { - val formattedRequest = getFormattedRequest(requestMessage) - val formattedHeaders = getFormattedHeaders(requestMessage) - val formattedBody = getFormattedBody(requestMessage) - logger.trace( - "Received a request from {}:\n{}\n{}{}{}{}", - requestMessage.connection.remoteAddress.hostAddress, - HTTPSERVER_REQUEST_BEGIN, - formattedRequest, - formattedHeaders, - formattedBody, - HTTPSERVER_REQUEST_END - ) - } - - fun logStreamServerResponseMessage( - responseMessage: StreamResponseMessage, - requestMessage: StreamRequestMessage - ) { - val formattedResponse = getFormattedResponse(responseMessage) - val formattedHeaders = getFormattedHeaders(responseMessage) - val formattedBody = getFormattedBody(responseMessage) - logger.trace( - "Send a response to {}:\n{}\n{}{}{}{}", - requestMessage.connection.remoteAddress.hostAddress, - HTTPSERVER_RESPONSE_BEGIN, - formattedResponse, - formattedHeaders, - formattedBody, - HTTPSERVER_RESPONSE_END - ) - } - - fun logStreamClientRequestMessage(requestMessage: StreamRequestMessage) { - val formattedRequest = getFormattedRequest(requestMessage) - val formattedHeaders = getFormattedHeaders(requestMessage) - val formattedBody = getFormattedBody(requestMessage) - logger.trace( - "Send a request to {}:\n{}\n{}{}{}{}", - requestMessage.uri.host, - HTTPCLIENT_REQUEST_BEGIN, - formattedRequest, - formattedHeaders, - formattedBody, - HTTPCLIENT_REQUEST_END - ) - } - - fun logStreamClientResponseMessage( - responseMessage: StreamResponseMessage, - requestMessage: StreamRequestMessage? - ) { - val formattedResponse = getFormattedResponse(responseMessage) - val formattedHeaders = getFormattedHeaders(responseMessage) - val formattedBody = getFormattedBody(responseMessage) - logger.trace( - "Received a response from {}:\n{}\n{}{}{}{}", - requestMessage?.uri?.host, - HTTPCLIENT_RESPONSE_BEGIN, - formattedResponse, - formattedHeaders, - formattedBody, - HTTPCLIENT_RESPONSE_END - ) - } - - private fun getFormattedRequest(requestMessage: StreamRequestMessage): String { - val request = StringBuilder() - request.append(requestMessage.operation.httpMethodName).append(" ").append(requestMessage.uri.path) - request.append(" HTTP/1.").append(requestMessage.operation.httpMinorVersion).append("\n") - return request.toString() - } - - private fun getFormattedResponse(responseMessage: StreamResponseMessage): String { - val response = StringBuilder() - response.append("HTTP/1.").append(responseMessage.operation.httpMinorVersion) - response.append(" ").append(responseMessage.operation.responseDetails).append("\n") - return response.toString() - } - - private fun getFormattedHeaders(message: UpnpMessage<*>): String { - val headers = StringBuilder() - for ((key, value1) in message.headers) { - if (StringUtils.isNotEmpty(key)) { - for (value in value1) { - headers.append(" ").append(key).append(": ").append(value).append("\n") - } - } - } - if (headers.isNotEmpty()) { - headers.insert(0, "\nHEADER:\n") - } - return headers.toString() - } - - private fun getFormattedBody(message: UpnpMessage<*>): String { - var formattedBody = "" - //message.isBodyNonEmptyString throw StringIndexOutOfBoundsException if string is empty - try { - val bodyNonEmpty = message.body != null && - (message.body is String && (message.body as String).isNotEmpty() - || message.body is ByteArray && (message.body as ByteArray).isNotEmpty()) - if (bodyNonEmpty && message.isBodyNonEmptyString) { - formattedBody = message.bodyString - } - } catch (e: Exception) { - formattedBody = "" - } - formattedBody = if (StringUtils.isNotEmpty(formattedBody)) { - "\nCONTENT:\n$formattedBody" - } else { - "" - } - return formattedBody - } - } -} - diff --git a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentElements.kt b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentElements.kt index 4461671..6a66e85 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentElements.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentElements.kt @@ -1,6 +1,6 @@ package net.schowek.nextclouddlna.nextcloud.content -class ContentItem( +data class ContentItem( val id: Int, val parentId: Int, val name: String, @@ -11,14 +11,13 @@ class ContentItem( var thumb: ContentItem? = null } -class ContentNode( +data class ContentNode( val id: Int, val parentId: Int, val name: String ) { - private val nodes: MutableList = ArrayList() - private val items: MutableList = ArrayList() - + val nodes: MutableList = ArrayList() + val items: MutableList = ArrayList() private val nodeCount: Int get() = nodes.size private val itemCount: Int get() = items.size @@ -31,13 +30,4 @@ class ContentNode( fun addNode(node: ContentNode) { nodes.add(node) } - - fun getItems(): List { - return items - } - - fun getNodes(): List { - return nodes - } - } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt index da10c1a..35110f9 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt @@ -50,14 +50,14 @@ class ContentTreeProvider( logger.info("Loading thumbnails...") val thumbsCount = AtomicInteger() nextcloudDB.processThumbnails { thumb -> - val id = getItemIdForThumbnail(thumb) - if (id != null) { - val item = tree.getItem(id) - if (item != null && item.thumb == null) { - logger.debug("Adding thumbnail for item {}: {}", id, thumb) - item.thumb = thumb - tree.addItem(thumb) - thumbsCount.getAndIncrement() + getItemIdForThumbnail(thumb)?.let { id -> + tree.getItem(id)?.let { item -> + item.thumb ?: let { + logger.debug("Adding thumbnail for item {}: {}", id, thumb) + item.thumb = thumb + tree.addItem(thumb) + thumbsCount.getAndIncrement() + } } } } @@ -75,11 +75,11 @@ class ContentTreeProvider( private fun fillNode(node: ContentNode, tree: ContentTree) { nextcloudDB.appendChildren(node) tree.addNode(node) - node.getItems().forEach { item -> + node.items.forEach { item -> logger.debug("Adding item[{}]: " + item.path, item.id) tree.addItem(item) } - node.getNodes().forEach { n -> + node.nodes.forEach { n -> logger.debug("Adding node: " + n.name) fillNode(n, tree) } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/util/ExternalUrls.kt b/src/main/kotlin/net/schowek/nextclouddlna/util/ExternalUrls.kt index e56236d..e70bfb0 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/util/ExternalUrls.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/util/ExternalUrls.kt @@ -11,8 +11,6 @@ class ExternalUrls(private val serverInfoProvider: ServerInfoProvider) { val selfURI : URI get() = URI(selfUriString) - fun contentUrl(id: Int): String { - return "$selfUriString/c/$id" - } + fun contentUrl(id: Int) = "$selfUriString/c/$id" }