From f5a8a6e98223fac0c18e007571f3e4017bc68721 Mon Sep 17 00:00:00 2001 From: xis Date: Thu, 19 Oct 2023 17:53:36 +0200 Subject: [PATCH 1/5] UpnpService as bean --- build.gradle | 1 + .../support/IntegrationSpecification.groovy | 3 ++ .../groovy/support/beans/TestConfig.groovy | 7 +++ .../upnp/UpnpServiceConfigurationInt.groovy | 29 ++++++++++++ .../config/NextcloudAppPathProviderInt.groovy | 4 +- .../beans}/util/ServerInfoProviderInt.groovy | 3 +- .../beans}/util/ServerPortCustomizer.groovy | 2 +- .../net/schowek/nextclouddlna/DllnaService.kt | 47 ++----------------- .../nextclouddlna/dlna/upnp/MyUpnpService.kt | 14 ++++++ .../dlna/upnp/MyUpnpServiceConfiguration.kt | 44 +++++++++++++++++ .../transport/ApacheStreamClient.kt | 2 +- .../ApacheStreamClientConfiguration.kt | 2 +- .../transport/MyStreamServerConfiguration.kt | 2 +- .../transport/MyStreamServerImpl.kt | 2 +- 14 files changed, 110 insertions(+), 52 deletions(-) create mode 100644 src/integration/groovy/support/beans/TestConfig.groovy create mode 100644 src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy rename src/integration/groovy/{net/schowek/nextclouddlna => support/beans}/nextcloud/config/NextcloudAppPathProviderInt.groovy (75%) rename src/integration/groovy/{net/schowek/nextclouddlna => support/beans}/util/ServerInfoProviderInt.groovy (88%) rename src/integration/groovy/{net/schowek/nextclouddlna => support/beans}/util/ServerPortCustomizer.groovy (94%) create mode 100644 src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt create mode 100644 src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt rename src/main/kotlin/net/schowek/nextclouddlna/dlna/{ => upnp}/transport/ApacheStreamClient.kt (99%) rename src/main/kotlin/net/schowek/nextclouddlna/dlna/{ => upnp}/transport/ApacheStreamClientConfiguration.kt (90%) rename src/main/kotlin/net/schowek/nextclouddlna/dlna/{ => upnp}/transport/MyStreamServerConfiguration.kt (79%) rename src/main/kotlin/net/schowek/nextclouddlna/dlna/{ => upnp}/transport/MyStreamServerImpl.kt (90%) diff --git a/build.gradle b/build.gradle index c985f2e..d81cc9a 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ dependencies { implementation 'org.jupnp:org.jupnp:2.7.1' implementation 'org.jupnp:org.jupnp.support:2.7.1' + implementation 'org.osgi:org.osgi.service.http:1.2.2' implementation 'org.apache.httpcomponents:httpclient:4.5.14' // to avoid snakeyaml-1.3 vulnerability CVE-2022-1471 implementation 'org.yaml:snakeyaml:2.2' diff --git a/src/integration/groovy/support/IntegrationSpecification.groovy b/src/integration/groovy/support/IntegrationSpecification.groovy index c248ad3..0f51d52 100644 --- a/src/integration/groovy/support/IntegrationSpecification.groovy +++ b/src/integration/groovy/support/IntegrationSpecification.groovy @@ -6,15 +6,18 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootContextLoader import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate +import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.ContextConfiguration import spock.lang.Specification +import support.beans.TestConfig import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT @ContextConfiguration(loader = SpringBootContextLoader, classes = NextcloudDLNAApp.class) @SpringBootTest(webEnvironment = DEFINED_PORT) @ActiveProfiles("integration") +@Import(TestConfig.class) class IntegrationSpecification extends Specification { @Autowired private TestRestTemplate restTemplate diff --git a/src/integration/groovy/support/beans/TestConfig.groovy b/src/integration/groovy/support/beans/TestConfig.groovy new file mode 100644 index 0000000..cebb120 --- /dev/null +++ b/src/integration/groovy/support/beans/TestConfig.groovy @@ -0,0 +1,7 @@ +package support.beans + +import org.springframework.context.annotation.ComponentScan + +@ComponentScan(["support", "net.schowek.nextclouddlna"]) +class TestConfig { +} \ No newline at end of file diff --git a/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy b/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy new file mode 100644 index 0000000..4d95c90 --- /dev/null +++ b/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy @@ -0,0 +1,29 @@ +package support.beans.dlna.upnp + +import org.jupnp.DefaultUpnpServiceConfiguration +import org.jupnp.transport.spi.DatagramIO +import org.jupnp.transport.spi.NetworkAddressFactory +import org.jupnp.transport.spi.StreamClient +import org.jupnp.transport.spi.StreamServer +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Component + +@Component +@Profile("integration") +class UpnpServiceConfigurationInt extends DefaultUpnpServiceConfiguration { + @Override + public StreamClient createStreamClient() { + return null + } + + + @Override + public StreamServer createStreamServer(NetworkAddressFactory networkAddressFactory) { + return null + } + +// @Override +// public DatagramIO createDatagramIO(NetworkAddressFactory networkAddressFactory) { +// +// } +} diff --git a/src/integration/groovy/net/schowek/nextclouddlna/nextcloud/config/NextcloudAppPathProviderInt.groovy b/src/integration/groovy/support/beans/nextcloud/config/NextcloudAppPathProviderInt.groovy similarity index 75% rename from src/integration/groovy/net/schowek/nextclouddlna/nextcloud/config/NextcloudAppPathProviderInt.groovy rename to src/integration/groovy/support/beans/nextcloud/config/NextcloudAppPathProviderInt.groovy index 2bd3b98..dfa76da 100644 --- a/src/integration/groovy/net/schowek/nextclouddlna/nextcloud/config/NextcloudAppPathProviderInt.groovy +++ b/src/integration/groovy/support/beans/nextcloud/config/NextcloudAppPathProviderInt.groovy @@ -1,6 +1,6 @@ -package net.schowek.nextclouddlna.nextcloud.config - +package support.beans.nextcloud.config +import net.schowek.nextclouddlna.nextcloud.config.NextcloudAppPathProvider import org.springframework.context.annotation.Profile import org.springframework.stereotype.Component diff --git a/src/integration/groovy/net/schowek/nextclouddlna/util/ServerInfoProviderInt.groovy b/src/integration/groovy/support/beans/util/ServerInfoProviderInt.groovy similarity index 88% rename from src/integration/groovy/net/schowek/nextclouddlna/util/ServerInfoProviderInt.groovy rename to src/integration/groovy/support/beans/util/ServerInfoProviderInt.groovy index 1a30d66..47b96ff 100644 --- a/src/integration/groovy/net/schowek/nextclouddlna/util/ServerInfoProviderInt.groovy +++ b/src/integration/groovy/support/beans/util/ServerInfoProviderInt.groovy @@ -1,5 +1,6 @@ -package net.schowek.nextclouddlna.util +package support.beans.util +import net.schowek.nextclouddlna.util.ServerInfoProvider import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Profile import org.springframework.stereotype.Component diff --git a/src/integration/groovy/net/schowek/nextclouddlna/util/ServerPortCustomizer.groovy b/src/integration/groovy/support/beans/util/ServerPortCustomizer.groovy similarity index 94% rename from src/integration/groovy/net/schowek/nextclouddlna/util/ServerPortCustomizer.groovy rename to src/integration/groovy/support/beans/util/ServerPortCustomizer.groovy index 4c997ad..5b5f23d 100644 --- a/src/integration/groovy/net/schowek/nextclouddlna/util/ServerPortCustomizer.groovy +++ b/src/integration/groovy/support/beans/util/ServerPortCustomizer.groovy @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.util +package support.beans.util import org.springframework.beans.factory.annotation.Value import org.springframework.boot.web.server.ConfigurableWebServerFactory diff --git a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt b/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt index 9b10166..4c76a91 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt @@ -3,36 +3,20 @@ package net.schowek.nextclouddlna import jakarta.annotation.PreDestroy import mu.KLogging import net.schowek.nextclouddlna.dlna.media.MediaServer -import net.schowek.nextclouddlna.dlna.transport.ApacheStreamClient -import net.schowek.nextclouddlna.dlna.transport.ApacheStreamClientConfiguration -import net.schowek.nextclouddlna.dlna.transport.MyStreamServerConfiguration -import net.schowek.nextclouddlna.dlna.transport.MyStreamServerImpl -import net.schowek.nextclouddlna.util.ServerInfoProvider -import org.jupnp.DefaultUpnpServiceConfiguration -import org.jupnp.UpnpServiceConfiguration -import org.jupnp.UpnpServiceImpl +import org.jupnp.UpnpService import org.jupnp.model.message.StreamRequestMessage import org.jupnp.model.message.StreamResponseMessage import org.jupnp.model.message.UpnpResponse -import org.jupnp.protocol.ProtocolFactory -import org.jupnp.registry.RegistryImpl -import org.jupnp.transport.impl.NetworkAddressFactoryImpl -import org.jupnp.transport.spi.NetworkAddressFactory import org.springframework.context.event.ContextRefreshedEvent import org.springframework.context.event.EventListener import org.springframework.stereotype.Component -import java.net.InetAddress -import java.net.NetworkInterface @Component class DlnaService( - private val mediaServer: MediaServer, - private val serverInfoProvider: ServerInfoProvider, + private val upnpService: UpnpService, + private val mediaServer: MediaServer ) { - private val addressesToBind: List = listOf(serverInfoProvider.host) - var upnpService = MyUpnpService(MyUpnpServiceConfiguration()) - fun start() { upnpService.startup() upnpService.registry.addDevice(mediaServer.device) @@ -61,30 +45,5 @@ class DlnaService( } } - inner class MyUpnpService( - configuration: UpnpServiceConfiguration - ) : UpnpServiceImpl(configuration) { - override fun createRegistry(pf: ProtocolFactory) = RegistryImpl(this) - } - - private inner class MyUpnpServiceConfiguration : DefaultUpnpServiceConfiguration(serverInfoProvider.port) { - override fun createStreamClient() = - ApacheStreamClient(ApacheStreamClientConfiguration(syncProtocolExecutorService)) - - override fun createStreamServer(networkAddressFactory: NetworkAddressFactory) = - MyStreamServerImpl(MyStreamServerConfiguration(networkAddressFactory.streamListenPort)) - - 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) = - addressesToBind.contains(address.hostAddress) - } - companion object : KLogging() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt new file mode 100644 index 0000000..99996e9 --- /dev/null +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt @@ -0,0 +1,14 @@ +package net.schowek.nextclouddlna.dlna.upnp + +import org.jupnp.UpnpServiceConfiguration +import org.jupnp.UpnpServiceImpl +import org.jupnp.protocol.ProtocolFactory +import org.jupnp.registry.RegistryImpl +import org.springframework.stereotype.Component + +@Component +class MyUpnpService( + upnpServiceConfiguration: UpnpServiceConfiguration +) : UpnpServiceImpl(upnpServiceConfiguration) { + override fun createRegistry(pf: ProtocolFactory) = RegistryImpl(this) +} diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt new file mode 100644 index 0000000..9edff5c --- /dev/null +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt @@ -0,0 +1,44 @@ +package net.schowek.nextclouddlna.dlna.upnp + +import net.schowek.nextclouddlna.dlna.upnp.transport.ApacheStreamClient +import net.schowek.nextclouddlna.dlna.upnp.transport.ApacheStreamClientConfiguration +import net.schowek.nextclouddlna.dlna.upnp.transport.MyStreamServerConfiguration +import net.schowek.nextclouddlna.dlna.upnp.transport.MyStreamServerImpl +import net.schowek.nextclouddlna.util.ServerInfoProvider +import org.jupnp.DefaultUpnpServiceConfiguration +import org.jupnp.transport.impl.NetworkAddressFactoryImpl +import org.jupnp.transport.spi.DatagramIO +import org.jupnp.transport.spi.NetworkAddressFactory +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Component +import java.net.InetAddress +import java.net.NetworkInterface + +@Component +@Profile("!integration") +class MyUpnpServiceConfiguration( + private val serverInfoProvider: ServerInfoProvider +) : DefaultUpnpServiceConfiguration(serverInfoProvider.port) { + val addressesToBind = listOf(serverInfoProvider.host) + + override fun createStreamClient() = + ApacheStreamClient(ApacheStreamClientConfiguration(syncProtocolExecutorService)) + + override fun createStreamServer(networkAddressFactory: NetworkAddressFactory) = + MyStreamServerImpl(MyStreamServerConfiguration(networkAddressFactory.streamListenPort)) + + override fun createDatagramIO(networkAddressFactory: NetworkAddressFactory): DatagramIO<*> { + return super.createDatagramIO(networkAddressFactory) + } + + override fun createNetworkAddressFactory(streamListenPort: Int, multicastResponsePort: Int) = + MyNetworkAddressFactory(serverInfoProvider, multicastResponsePort) + + inner class MyNetworkAddressFactory( + private val serverInfoProvider: ServerInfoProvider, + multicastResponsePort: Int + ) : NetworkAddressFactoryImpl(serverInfoProvider.port, multicastResponsePort) { + override fun isUsableAddress(iface: NetworkInterface, address: InetAddress) = + addressesToBind.contains(address.hostAddress) + } +} diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClient.kt similarity index 99% rename from src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClient.kt index 863b7ce..5e21fa4 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClient.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClient.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.dlna.transport +package net.schowek.nextclouddlna.dlna.upnp.transport import mu.KLogging import org.apache.http.HttpMessage diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClientConfiguration.kt similarity index 90% rename from src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClientConfiguration.kt index a05ca44..3d824ac 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/ApacheStreamClientConfiguration.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/ApacheStreamClientConfiguration.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.dlna.transport +package net.schowek.nextclouddlna.dlna.upnp.transport import org.jupnp.transport.spi.AbstractStreamClientConfiguration import java.util.concurrent.ExecutorService diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerConfiguration.kt similarity index 79% rename from src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerConfiguration.kt index 5df9171..e6fc950 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerConfiguration.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerConfiguration.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.dlna.transport +package net.schowek.nextclouddlna.dlna.upnp.transport import org.jupnp.transport.spi.StreamServerConfiguration diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerImpl.kt similarity index 90% rename from src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerImpl.kt index 5108ca7..e7d2eca 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/transport/MyStreamServerImpl.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/transport/MyStreamServerImpl.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.dlna.transport +package net.schowek.nextclouddlna.dlna.upnp.transport import mu.KLogging import org.jupnp.transport.Router From c3dadfd8455495ab6701f48d13fcf54214953050 Mon Sep 17 00:00:00 2001 From: xis Date: Thu, 19 Oct 2023 19:42:51 +0200 Subject: [PATCH 2/5] Multicast search request tested --- .../controller/UpnpControllerIntTest.groovy | 7 ++- .../dlna/DlnaServiceIntTest.groovy | 55 +++++++++++++++++++ .../support/IntegrationSpecification.groovy | 5 +- .../upnp/UpnpServiceConfigurationInt.groovy | 32 +++++++++-- .../controller/UpnpController.kt | 4 +- .../{DllnaService.kt => dlna/DlnaService.kt} | 5 +- .../dlna/{media => }/MediaServer.kt | 2 +- .../nextclouddlna/dlna/upnp/MyUpnpService.kt | 6 +- .../dlna/upnp/MyUpnpServiceConfiguration.kt | 6 +- .../nextcloud/content/ContentTreeProvider.kt | 19 +++---- .../nextcloud/{ => db}/NextcloudDB.kt | 3 +- .../content/ContentTreeProviderTest.groovy | 2 +- 12 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy rename src/main/kotlin/net/schowek/nextclouddlna/{DllnaService.kt => dlna/DlnaService.kt} (92%) rename src/main/kotlin/net/schowek/nextclouddlna/dlna/{media => }/MediaServer.kt (97%) rename src/main/kotlin/net/schowek/nextclouddlna/nextcloud/{ => db}/NextcloudDB.kt (97%) diff --git a/src/integration/groovy/net/schowek/nextclouddlna/controller/UpnpControllerIntTest.groovy b/src/integration/groovy/net/schowek/nextclouddlna/controller/UpnpControllerIntTest.groovy index dcbfbbf..c41c7bd 100644 --- a/src/integration/groovy/net/schowek/nextclouddlna/controller/UpnpControllerIntTest.groovy +++ b/src/integration/groovy/net/schowek/nextclouddlna/controller/UpnpControllerIntTest.groovy @@ -1,7 +1,7 @@ package net.schowek.nextclouddlna.controller - -import net.schowek.nextclouddlna.dlna.media.MediaServer +import net.schowek.nextclouddlna.dlna.DlnaService +import net.schowek.nextclouddlna.dlna.MediaServer import org.jupnp.support.model.DIDLObject import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus @@ -14,11 +14,14 @@ class UpnpControllerIntTest extends UpnpAwareSpecification { @Autowired private MediaServer mediaServer + @Autowired + private DlnaService dlnaService def uid def setup() { uid = mediaServer.serviceIdentifier + dlnaService.start() } def "should serve icon"() { diff --git a/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy b/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy new file mode 100644 index 0000000..f79b0de --- /dev/null +++ b/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy @@ -0,0 +1,55 @@ +package net.schowek.nextclouddlna.dlna + +import org.jupnp.UpnpService +import org.jupnp.model.message.discovery.OutgoingSearchRequest +import org.jupnp.model.message.header.HostHeader +import org.jupnp.model.message.header.MANHeader +import org.jupnp.model.message.header.STAllHeader +import org.jupnp.model.message.header.UpnpHeader +import org.jupnp.model.types.HostPort +import org.springframework.beans.factory.annotation.Autowired +import support.IntegrationSpecification +import support.beans.dlna.upnp.UpnpServiceConfigurationInt + +import static org.jupnp.model.Constants.IPV4_UPNP_MULTICAST_GROUP +import static org.jupnp.model.Constants.UPNP_MULTICAST_PORT +import static org.jupnp.model.message.UpnpRequest.Method.MSEARCH +import static org.jupnp.model.message.header.UpnpHeader.Type.* +import static org.jupnp.model.types.NotificationSubtype.ALL +import static org.jupnp.model.types.NotificationSubtype.DISCOVER + +class DlnaServiceIntTest extends IntegrationSpecification { + @Autowired + private UpnpService upnpService + @Autowired + private MediaServer mediaServer + + def "should send initial multicast Upnp datagrams on start"() { + given: + def configuration = upnpService.configuration as UpnpServiceConfigurationInt + def sut = new DlnaService(upnpService, mediaServer) + + expect: + configuration.outgoingDatagramMessages == [] + + when: + sut.start() + + then: + configuration.outgoingDatagramMessages.any() + configuration.outgoingDatagramMessages[0].class == OutgoingSearchRequest + with(configuration.outgoingDatagramMessages[0] as OutgoingSearchRequest) { + assert it.operation.method == MSEARCH + assert it.destinationAddress == InetAddress.getByName(IPV4_UPNP_MULTICAST_GROUP) + assert it.destinationPort == UPNP_MULTICAST_PORT + + assert header(it, MAN, MANHeader.class) == DISCOVER.headerString + assert header(it, ST, STAllHeader.class).headerString == ALL.headerString + assert header(it, HOST, HostHeader.class) == new HostPort(IPV4_UPNP_MULTICAST_GROUP, UPNP_MULTICAST_PORT) + } + } + + def T header(OutgoingSearchRequest request, UpnpHeader.Type type, Class> clazz) { + return clazz.cast(request.headers.get(type).find()).value + } +} diff --git a/src/integration/groovy/support/IntegrationSpecification.groovy b/src/integration/groovy/support/IntegrationSpecification.groovy index 0f51d52..ff4001d 100644 --- a/src/integration/groovy/support/IntegrationSpecification.groovy +++ b/src/integration/groovy/support/IntegrationSpecification.groovy @@ -7,17 +7,20 @@ import org.springframework.boot.test.context.SpringBootContextLoader import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.context.annotation.Import +import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.ContextConfiguration import spock.lang.Specification import support.beans.TestConfig import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT +import static org.springframework.test.annotation.DirtiesContext.ClassMode.* @ContextConfiguration(loader = SpringBootContextLoader, classes = NextcloudDLNAApp.class) @SpringBootTest(webEnvironment = DEFINED_PORT) @ActiveProfiles("integration") @Import(TestConfig.class) +@DirtiesContext(classMode = AFTER_CLASS) class IntegrationSpecification extends Specification { @Autowired private TestRestTemplate restTemplate @@ -30,6 +33,6 @@ class IntegrationSpecification extends Specification { private ServerInfoProvider serverInfoProvider protected String urlWithPort(String uri = "") { - return "http://localhost:" + serverInfoProvider.port + uri; + return "http://" + serverInfoProvider.host + ":" + serverInfoProvider.port + uri; } } diff --git a/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy b/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy index 4d95c90..91b269e 100644 --- a/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy +++ b/src/integration/groovy/support/beans/dlna/upnp/UpnpServiceConfigurationInt.groovy @@ -1,6 +1,9 @@ package support.beans.dlna.upnp import org.jupnp.DefaultUpnpServiceConfiguration +import org.jupnp.model.message.OutgoingDatagramMessage +import org.jupnp.transport.impl.DatagramIOConfigurationImpl +import org.jupnp.transport.impl.DatagramIOImpl import org.jupnp.transport.spi.DatagramIO import org.jupnp.transport.spi.NetworkAddressFactory import org.jupnp.transport.spi.StreamClient @@ -11,19 +14,38 @@ import org.springframework.stereotype.Component @Component @Profile("integration") class UpnpServiceConfigurationInt extends DefaultUpnpServiceConfiguration { + List outgoingDatagramMessages = new ArrayList<>() + @Override public StreamClient createStreamClient() { return null } - @Override public StreamServer createStreamServer(NetworkAddressFactory networkAddressFactory) { return null } -// @Override -// public DatagramIO createDatagramIO(NetworkAddressFactory networkAddressFactory) { -// -// } + @Override + public DatagramIO createDatagramIO(NetworkAddressFactory networkAddressFactory) { + return new MockDatagramIO(this, new DatagramIOConfigurationImpl()) + } + + private void onOutgoingDatagramMessage(OutgoingDatagramMessage message) { + outgoingDatagramMessages.add(message) + } + + class MockDatagramIO extends DatagramIOImpl { + private final UpnpServiceConfigurationInt upnpServiceConfiguration + + MockDatagramIO(UpnpServiceConfigurationInt upnpServiceConfiguration, DatagramIOConfigurationImpl configuration) { + super(configuration) + this.upnpServiceConfiguration = upnpServiceConfiguration + } + + @Override + void send(OutgoingDatagramMessage message) { + upnpServiceConfiguration.onOutgoingDatagramMessage(message) + } + } } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/controller/UpnpController.kt b/src/main/kotlin/net/schowek/nextclouddlna/controller/UpnpController.kt index 0aabcc8..3256c01 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/controller/UpnpController.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/controller/UpnpController.kt @@ -2,9 +2,9 @@ package net.schowek.nextclouddlna.controller import jakarta.servlet.http.HttpServletRequest import mu.KLogging -import net.schowek.nextclouddlna.DlnaService +import net.schowek.nextclouddlna.dlna.DlnaService import net.schowek.nextclouddlna.dlna.StreamMessageMapper -import net.schowek.nextclouddlna.dlna.media.MediaServer +import net.schowek.nextclouddlna.dlna.MediaServer import org.springframework.core.io.InputStreamResource import org.springframework.core.io.Resource import org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE diff --git a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/DlnaService.kt similarity index 92% rename from src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/DlnaService.kt index 4c76a91..5e1c8e1 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/DllnaService.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/DlnaService.kt @@ -1,8 +1,7 @@ -package net.schowek.nextclouddlna +package net.schowek.nextclouddlna.dlna import jakarta.annotation.PreDestroy import mu.KLogging -import net.schowek.nextclouddlna.dlna.media.MediaServer import org.jupnp.UpnpService import org.jupnp.model.message.StreamRequestMessage import org.jupnp.model.message.StreamResponseMessage @@ -22,7 +21,7 @@ class DlnaService( upnpService.registry.addDevice(mediaServer.device) } - @EventListener + @EventListener(condition = "!@environment.acceptsProfiles('integration')") fun handleContextRefresh(event: ContextRefreshedEvent) { start() } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/MediaServer.kt similarity index 97% rename from src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt rename to src/main/kotlin/net/schowek/nextclouddlna/dlna/MediaServer.kt index 5c0a1a6..208a64a 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/media/MediaServer.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/MediaServer.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.dlna.media +package net.schowek.nextclouddlna.dlna import mu.KLogging import net.schowek.nextclouddlna.util.ExternalUrls diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt index 99996e9..52051c7 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpService.kt @@ -2,13 +2,9 @@ package net.schowek.nextclouddlna.dlna.upnp import org.jupnp.UpnpServiceConfiguration import org.jupnp.UpnpServiceImpl -import org.jupnp.protocol.ProtocolFactory -import org.jupnp.registry.RegistryImpl import org.springframework.stereotype.Component @Component class MyUpnpService( upnpServiceConfiguration: UpnpServiceConfiguration -) : UpnpServiceImpl(upnpServiceConfiguration) { - override fun createRegistry(pf: ProtocolFactory) = RegistryImpl(this) -} +) : UpnpServiceImpl(upnpServiceConfiguration) diff --git a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt index 9edff5c..a8b65c4 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/dlna/upnp/MyUpnpServiceConfiguration.kt @@ -32,12 +32,12 @@ class MyUpnpServiceConfiguration( } override fun createNetworkAddressFactory(streamListenPort: Int, multicastResponsePort: Int) = - MyNetworkAddressFactory(serverInfoProvider, multicastResponsePort) + MyNetworkAddressFactory(streamListenPort, multicastResponsePort) inner class MyNetworkAddressFactory( - private val serverInfoProvider: ServerInfoProvider, + streamListenPort: Int, multicastResponsePort: Int - ) : NetworkAddressFactoryImpl(serverInfoProvider.port, multicastResponsePort) { + ) : NetworkAddressFactoryImpl(streamListenPort, multicastResponsePort) { override fun isUsableAddress(iface: NetworkInterface, address: InetAddress) = addressesToBind.contains(address.hostAddress) } 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 a57e5e5..9712178 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProvider.kt @@ -1,7 +1,7 @@ package net.schowek.nextclouddlna.nextcloud.content import mu.KLogging -import net.schowek.nextclouddlna.nextcloud.NextcloudDB +import net.schowek.nextclouddlna.nextcloud.db.NextcloudDB import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import java.time.Clock @@ -100,8 +100,8 @@ class ContentTreeProvider( } } - fun getItem(id: String): ContentItem? = tree.getItem(id) - fun getNode(id: String): ContentNode? = tree.getNode(id) + fun getItem(id: String) = tree.getItem(id) + fun getNode(id: String) = tree.getNode(id) companion object : KLogging() { const val REBUILD_TREE_DELAY_IN_MS = 1000 * 60L // 1m @@ -115,13 +115,11 @@ class ContentTree { private val nodes: MutableMap = HashMap() private val items: MutableMap = HashMap() - fun getNode(id: String): ContentNode? { - return nodes[id] - } + val itemsCount get() = items.size + val nodesCount get() = nodes.size - fun getItem(id: String): ContentItem? { - return items[id] - } + fun getNode(id: String) = nodes[id] + fun getItem(id: String) = items[id] fun addItem(item: ContentItem) { items["${item.id}"] = item @@ -130,8 +128,5 @@ class ContentTree { fun addNode(node: ContentNode) { nodes["${node.id}"] = node } - - val itemsCount get() = items.size - val nodesCount get() = nodes.size } diff --git a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/NextcloudDB.kt b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/db/NextcloudDB.kt similarity index 97% rename from src/main/kotlin/net/schowek/nextclouddlna/nextcloud/NextcloudDB.kt rename to src/main/kotlin/net/schowek/nextclouddlna/nextcloud/db/NextcloudDB.kt index 5eae2f2..8292cad 100644 --- a/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/NextcloudDB.kt +++ b/src/main/kotlin/net/schowek/nextclouddlna/nextcloud/db/NextcloudDB.kt @@ -1,4 +1,4 @@ -package net.schowek.nextclouddlna.nextcloud +package net.schowek.nextclouddlna.nextcloud.db import jakarta.annotation.PostConstruct import mu.KLogging @@ -6,7 +6,6 @@ import net.schowek.nextclouddlna.nextcloud.config.NextcloudConfigDiscovery import net.schowek.nextclouddlna.nextcloud.content.ContentItem import net.schowek.nextclouddlna.nextcloud.content.ContentNode import net.schowek.nextclouddlna.nextcloud.content.MediaFormat -import net.schowek.nextclouddlna.nextcloud.db.* import net.schowek.nextclouddlna.nextcloud.db.Filecache.Companion.FOLDER_MIME_TYPE import org.springframework.dao.InvalidDataAccessResourceUsageException import org.springframework.stereotype.Component diff --git a/src/test/groovy/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProviderTest.groovy b/src/test/groovy/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProviderTest.groovy index 3bbecce..cd41fb7 100644 --- a/src/test/groovy/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProviderTest.groovy +++ b/src/test/groovy/net/schowek/nextclouddlna/nextcloud/content/ContentTreeProviderTest.groovy @@ -1,6 +1,6 @@ package net.schowek.nextclouddlna.nextcloud.content -import net.schowek.nextclouddlna.nextcloud.NextcloudDB +import net.schowek.nextclouddlna.nextcloud.db.NextcloudDB import spock.lang.Specification import java.time.Clock import java.time.ZoneId From c915b0b9b1e5189e067ac23ce5a3fc7d41d5657b Mon Sep 17 00:00:00 2001 From: xis Date: Sun, 22 Oct 2023 12:52:25 +0200 Subject: [PATCH 3/5] Postgresql support added --- README.md | 1 + build.gradle | 1 + .../util/DriverManagerDataSourceConfig.kt | 57 +++++++++++++++++++ src/main/resources/application.yml | 12 ++-- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/net/schowek/nextclouddlna/util/DriverManagerDataSourceConfig.kt diff --git a/README.md b/README.md index c7990f3..eb55bfe 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Available env variables with their default values that you can overwrite: | NEXTCLOUD_DLNA_INTERFACE | eth0 | interface the server will be listening on | | NEXTCLOUD_DLNA_FRIENDLY_NAME | Nextcloud-DLNA | friendly name of the DLNA service | | NEXTCLOUD_DATA_DIR | | nextcloud installation directory (that ends with /data) | +| NEXTCLOUD_DB_TYPE | mariadb | nextcloud database type (mysql, mariadb, postgresql) | | NEXTCLOUD_DB_HOST | localhost | nextcloud database host | | NEXTCLOUD_DB_PORT | 3306 | nextcloud database port | | NEXTCLOUD_DB_NAME | nextcloud | nextcloud database name | diff --git a/build.gradle b/build.gradle index c985f2e..f37090a 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.mariadb.jdbc:mariadb-java-client:3.2.0' + implementation 'org.postgresql:postgresql:42.6.0' implementation 'org.jupnp:org.jupnp:2.7.1' implementation 'org.jupnp:org.jupnp.support:2.7.1' diff --git a/src/main/kotlin/net/schowek/nextclouddlna/util/DriverManagerDataSourceConfig.kt b/src/main/kotlin/net/schowek/nextclouddlna/util/DriverManagerDataSourceConfig.kt new file mode 100644 index 0000000..69bab07 --- /dev/null +++ b/src/main/kotlin/net/schowek/nextclouddlna/util/DriverManagerDataSourceConfig.kt @@ -0,0 +1,57 @@ +package net.schowek.nextclouddlna.util + +import mu.KLogging +import net.schowek.nextclouddlna.util.NextcloudDBType.* +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile +import org.springframework.jdbc.datasource.DriverManagerDataSource + +@Configuration +@Profile("!integration") +@EnableConfigurationProperties(NextcloudDBConfigProperties::class) +class DriverManagerDataSourceConfig { + @Bean + fun driverManagerDataSource(props: NextcloudDBConfigProperties): DriverManagerDataSource { + logger.info { "Using Nextcloud DB connection parameters: $props" } + return DriverManagerDataSource().also { dataSource -> + when (props.type) { + MARIADB, MYSQL -> { + dataSource.setDriverClassName("org.mariadb.jdbc.Driver"); + dataSource.url = "jdbc:mariadb://${props.host}:${props.port}/${props.name}"; + } + + POSTGRES -> { + dataSource.setDriverClassName("org.mariadb.jdbc.Driver"); + dataSource.url = "jdbc:postgresql://${props.host}:${props.port}/${props.name}"; + dataSource.connectionProperties?.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect") + } + + else -> throw RuntimeException("Unsupported DB type") + } + dataSource.username = props.user; + dataSource.password = props.pass; + } + } + + companion object : KLogging() +} + +@Profile("!integration") +@ConfigurationProperties(prefix = "nextcloud.db") +data class NextcloudDBConfigProperties( + val type: NextcloudDBType, + val host: String, + val port: Int, + val name: String, + val user: String, + val pass: String +) + +enum class NextcloudDBType(val value: String) { + MYSQL("mysql"), + MARIADB("mariadb"), + POSTGRES("postgres") +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0c8c146..978edef 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -5,13 +5,15 @@ server: nextcloud: filesDir: ${NEXTCLOUD_DATA_DIR} + db: + type: ${NEXTCLOUD_DB_TYPE:mariadb} + host: ${NEXTCLOUD_DB_HOST:localhost} + port: ${NEXTCLOUD_DB_PORT:3306} + name: ${NEXTCLOUD_DB_NAME:nextcloud} + user: ${NEXTCLOUD_DB_USER:nextcloud} + pass: ${NEXTCLOUD_DB_PASS:nextcloud} spring: - datasource: - url: "jdbc:mariadb://${NEXTCLOUD_DB_HOST:localhost}:${NEXTCLOUD_DB_PORT:3306}/${NEXTCLOUD_DB_NAME:nextcloud}" - username: ${NEXTCLOUD_DB_USER:nextcloud} - password: ${NEXTCLOUD_DB_PASS:nextcloud} - driver-class-name: org.mariadb.jdbc.Driver jpa: hibernate: ddl-auto: none From 4ae6775ecd3e172a0fa4407dedd76b5bae33d1fb Mon Sep 17 00:00:00 2001 From: xis Date: Sun, 22 Oct 2023 13:42:35 +0200 Subject: [PATCH 4/5] Running with docker examples --- README.md | 51 +++++++------ examples/docker-compose/docker-compose.yaml | 84 +++++++++++++++++++++ examples/docker-compose/readme.md | 13 ++++ examples/docker-compose/run.sh | 3 + examples/docker-standalone/readme.md | 2 + examples/docker-standalone/run.sh | 14 ++++ 6 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 examples/docker-compose/docker-compose.yaml create mode 100644 examples/docker-compose/readme.md create mode 100644 examples/docker-compose/run.sh create mode 100644 examples/docker-standalone/readme.md create mode 100644 examples/docker-standalone/run.sh diff --git a/README.md b/README.md index eb55bfe..e6a4ca6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,33 @@ DLNA addon for your self-hosted Nextcloud app instance that allows you to stream devices in your network. It supports the group folders as well. -Just edit the `application.yml` and rebuild the project with: +## Running in Docker +You can use the docker image with nextcloud-dlna e.g.: + +```bash +docker run -d \ +--name="nextcloud-dlna" \ +--net=host \ +-v /path/to/nextcloud/app/ending/with/data:/nextcloud \ +-e NEXTCLOUD_DATA_DIR=/nextcloud \ +-e NEXTCLOUD_DB_HOST='' \ +-e NEXTCLOUD_DB_PASS='' \ +nextcloud-dlna +``` + +or, if used together with the official Nextcloud docker image using the docker-composer. See the [examples](./examples) +directory. for more details about running nextcloud-dlna server in the docker container. + +You can pass to the container other env variables that are listed below. + +Note that it would not work on Mac OS since docker is a Linux container and the `host` networking mode doesn't actually +share the host's network interfaces. + +See https://hub.docker.com/r/thanek/nextcloud-dlna for more docker image details. + +## Building the project + +Build the project with: `./gradlew clean bootRun` @@ -16,6 +42,8 @@ or, if you've already built the project and created the jar file: `NEXTCLOUD_DLNA_SERVER_PORT=9999 java -jar nextcloud-dlna-X.Y.Z.jar` +## ENV variables + Available env variables with their default values that you can overwrite: | env variable | default value | description | @@ -32,27 +60,6 @@ Available env variables with their default values that you can overwrite: | NEXTCLOUD_DB_PASS | nextcloud | nextcloud database password | -## Running in Docker -You can use the docker image with nextcloud-dlna e.g.: - -``` -docker run -d \ ---name="nextcloud-dlna" \ ---net=host \ --v /path/to/nextcloud/app/ending/with/data:/nextcloud \ --e NEXTCLOUD_DATA_DIR=/nextcloud \ --e NEXTCLOUD_DB_HOST='' \ --e NEXTCLOUD_DB_PASS='' \ -nextcloud-dlna -``` - -You can pass to the container other env variables that are listed above. - -Note that it would not work on Mac OS since docker is a Linux container and the `host` networking mode doesn't actually -share the host's network interfaces. - -See https://hub.docker.com/r/thanek/nextcloud-dlna for more docker image details. - ### Code used Some java code was taken from https://github.com/haku/dlnatoad diff --git a/examples/docker-compose/docker-compose.yaml b/examples/docker-compose/docker-compose.yaml new file mode 100644 index 0000000..206f621 --- /dev/null +++ b/examples/docker-compose/docker-compose.yaml @@ -0,0 +1,84 @@ +version: '2' + +volumes: + app: + driver: local + driver_opts: + type: none + o: bind + device: ${PWD}/app + app_etc: + driver: local + driver_opts: + type: none + o: bind + device: ${PWD}/etc/apache2 + db_data: + driver: local + driver_opts: + type: none + o: bind + device: ${PWD}/db + db_etc: + driver: local + driver_opts: + type: none + o: bind + device: ${PWD}/etc/mysql + +services: + db: + image: mariadb:10.5 + restart: always + command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW + volumes: + - db_data:/var/lib/mysql + - db_etc:/etc/mysql + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=sql + - MYSQL_PASSWORD=secret + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + + redis: + image: redis + restart: always + + app: + image: nextcloud + restart: always + ports: + - "80:80" + - "443:443" + links: + - db + - redis + volumes: + - app:/var/www/html + - app_etc:/etc/apache2 + environment: + - PHP_MEMORY_LIMIT=1G + - PHP_UPLOAD_LIMIT=4G + - MYSQL_PASSWORD=secret + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + - MYSQL_HOST=db + + dlna: + image: thanek/nextcloud-dlna + restart: always + volumes: + - app:/nextcloud + network_mode: "host" + ports: + - "9999:9999" + environment: + - NEXTCLOUD_DLNA_SERVER_PORT=9999 + - NEXTCLOUD_DLNA_FRIENDLY_NAME=Nextcloud + - NEXTCLOUD_DATA_DIR=/nextcloud/data + - NEXTCLOUD_DB_TYPE=mariadb + - NEXTCLOUD_DB_HOST=localhost + - NEXTCLOUD_DB_PASS=secret + diff --git a/examples/docker-compose/readme.md b/examples/docker-compose/readme.md new file mode 100644 index 0000000..af49033 --- /dev/null +++ b/examples/docker-compose/readme.md @@ -0,0 +1,13 @@ +This will run the nextcloud-dlna in docker together with the full Nextcloud installation (containing the app, database +and redis) located in the `./app` directory. + +Note: in order to enable network access to the MariaDB server, after the first run, you'll need to edit +the `./etc/mariadb.cnf`, section `[client-config]` by adding the line: +``` +port = 3306 +``` +and removing the line: +``` +socket = /var/run/mysqld/mysqld.sock +``` +, then restart the `db` (`nextcloud-db-1`) container. \ No newline at end of file diff --git a/examples/docker-compose/run.sh b/examples/docker-compose/run.sh new file mode 100644 index 0000000..80b5727 --- /dev/null +++ b/examples/docker-compose/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker-compose up -d \ No newline at end of file diff --git a/examples/docker-standalone/readme.md b/examples/docker-standalone/readme.md new file mode 100644 index 0000000..c2c0f79 --- /dev/null +++ b/examples/docker-standalone/readme.md @@ -0,0 +1,2 @@ +This will run the nextcloud-dlna in docker and connect to the Nextcloud installation assuming it is located in the +`/opt/nextcloud` directory. diff --git a/examples/docker-standalone/run.sh b/examples/docker-standalone/run.sh new file mode 100644 index 0000000..7086777 --- /dev/null +++ b/examples/docker-standalone/run.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +docker run -d \ + --name="nextcloud-dlna" \ + --restart=unless-stopped \ + --net=host \ + -p 9999:9999 \ + -e NEXTCLOUD_DLNA_SERVER_PORT=9999 \ + -e NEXTCLOUD_DLNA_FRIENDLY_NAME="Nextcloud" \ + -e NEXTCLOUD_DB_HOST='localhost' \ + -e NEXTCLOUD_DB_PASS='secret' \ + -v '/opt/nextcloud/data:/nextcloud' \ + -e NEXTCLOUD_DATA_DIR=/nextcloud \ +thanek/nextcloud-dlna From 249b5fc33e29b4688e68a7d68f640504f47e4c60 Mon Sep 17 00:00:00 2001 From: xis Date: Sun, 22 Oct 2023 14:50:02 +0200 Subject: [PATCH 5/5] Polling condition added --- .../dlna/DlnaServiceIntTest.groovy | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy b/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy index f79b0de..87c6c7d 100644 --- a/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy +++ b/src/integration/groovy/net/schowek/nextclouddlna/dlna/DlnaServiceIntTest.groovy @@ -8,6 +8,7 @@ import org.jupnp.model.message.header.STAllHeader import org.jupnp.model.message.header.UpnpHeader import org.jupnp.model.types.HostPort import org.springframework.beans.factory.annotation.Autowired +import spock.util.concurrent.PollingConditions import support.IntegrationSpecification import support.beans.dlna.upnp.UpnpServiceConfigurationInt @@ -23,6 +24,7 @@ class DlnaServiceIntTest extends IntegrationSpecification { private UpnpService upnpService @Autowired private MediaServer mediaServer + def conditions = new PollingConditions(timeout: 1) def "should send initial multicast Upnp datagrams on start"() { given: @@ -36,16 +38,18 @@ class DlnaServiceIntTest extends IntegrationSpecification { sut.start() then: - configuration.outgoingDatagramMessages.any() - configuration.outgoingDatagramMessages[0].class == OutgoingSearchRequest - with(configuration.outgoingDatagramMessages[0] as OutgoingSearchRequest) { - assert it.operation.method == MSEARCH - assert it.destinationAddress == InetAddress.getByName(IPV4_UPNP_MULTICAST_GROUP) - assert it.destinationPort == UPNP_MULTICAST_PORT + conditions.eventually { + assert configuration.outgoingDatagramMessages.any() + assert configuration.outgoingDatagramMessages[0].class == OutgoingSearchRequest + with(configuration.outgoingDatagramMessages[0] as OutgoingSearchRequest) { + assert it.operation.method == MSEARCH + assert it.destinationAddress == InetAddress.getByName(IPV4_UPNP_MULTICAST_GROUP) + assert it.destinationPort == UPNP_MULTICAST_PORT - assert header(it, MAN, MANHeader.class) == DISCOVER.headerString - assert header(it, ST, STAllHeader.class).headerString == ALL.headerString - assert header(it, HOST, HostHeader.class) == new HostPort(IPV4_UPNP_MULTICAST_GROUP, UPNP_MULTICAST_PORT) + assert header(it, MAN, MANHeader.class) == DISCOVER.headerString + assert header(it, ST, STAllHeader.class).headerString == ALL.headerString + assert header(it, HOST, HostHeader.class) == new HostPort(IPV4_UPNP_MULTICAST_GROUP, UPNP_MULTICAST_PORT) + } } }