Giter Site home page Giter Site logo

rxbonjour's Introduction

RxBonjour

Travis Build Status

⚠️ THIS PROJECT IS ARCHIVED. No further development is scheduled.

A reactive wrapper around network service discovery functionalities for Kotlin and Java.

Download

RxBonjour 2 is available on jcenter() and consists of three distinct components, all of which are detailed below.

// Always include this
implementation "de.mannodermaus.rxjava2:rxbonjour:2.0.0-RC1"

// Example: Usage on Android with JmDNS
implementation "de.mannodermaus.rxjava2:rxbonjour-platform-android:2.0.0-RC1"
implementation "de.mannodermaus.rxjava2:rxbonjour-driver-jmdns:2.0.0-RC1"

For the (less flexible & Android-only) RxJava 1 version, have a look at the 1.x branch.

Components

RxBonjour 2 is composed of a core library, a Platform to run on, and a Driver to access the NSD stack.

Core Library (rxbonjour)

The main entry point to the API, RxBonjour is contained in this library. All other libraries depend on this common core.

Platform Library (rxbonjour-platform-xxx)

Provides access to the host device's IP and Network controls. During the creation of your RxBonjour instance, you attach exactly 1 implementation of the Platform interface.

Below is a list of available Platform libraries supported by RxBonjour 2:

Group Artifact Description
de.mannodermaus.rxjava2 rxbonjour-platform-android Android-aware Platform, utilizing WifiManager APIs
de.mannodermaus.rxjava2 rxbonjour-platform-desktop Default JVM Platform

About the AndroidPlatform

When running on Android, the rxbonjour-platform-android has to be applied to the module. Doing so will add the following permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>

Driver Library (rxbonjour-driver-xxx)

Provides the connection to a Network Service Discovery stack. During the creation of your RxBonjour instance, you attach exactly 1 implementation of the Driver interface.

Below is a list of available Driver libraries supported by RxBonjour 2:

Group Artifact Description
de.mannodermaus.rxjava2 rxbonjour-driver-jmdns Service Discovery with JmDNS
de.mannodermaus.rxjava2 rxbonjour-driver-nsdmanager Service Discovery with Android's NsdManager APIs

Usage

Creation

Configure a RxBonjour service object using its Builder, attaching your desired Platform and Driver implementations. If you forget to provide either dependency, an Exception will be thrown:

val rxBonjour = RxBonjour.Builder()
    .platform(AndroidPlatform.create(this))
    .driver(JmDNSDriver.create())
    .create()

Your RxBonjour is ready for use now!

Discovery

Create a network service discovery request using RxBonjour#newDiscovery(String):

val disposable = rxBonjour.newDiscovery("_http._tcp")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        { event ->
            when(event) {
                is BonjourEvent.Added -> println("Resolved Service: ${event.service}")
                is BonjourEvent.Removed -> println("Lost Service: ${event.service}")
            }
        },
        { error -> println("Error during Discovery: ${error.message}") }
    )

Make sure to off-load this work onto a background thread, since the library won't enforce any threading. In this example, RxAndroid is utilized to return the events back to Android's main thread.

Registration

Configure your advertised service & start the broadcast using RxBonjour#newBroadcast(BonjourBroadcastConfig). The only required property to set on a BonjourBroadcastConfig is its Bonjour type, the remaining parameters are filled with defaults as stated in the comments below:

val broadcastConfig = BonjourBroadcastConfig(
        type = "_http._tcp",
        name = "My Bonjour Service",        // default: "RxBonjour Service"
        address = null,                     // default: Fallback to WiFi address provided by Platform
        port = 13337,                       // default: 80
        txtRecords = mapOf(                 // default: Empty Map
                "my.record" to "my value",
                "other.record" to "0815"))
                
val disposable = rxBonjour.newBroadcast(broadcastConfig)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe()

The broadcast is valid until the returned Completable is unsubscribed from. Again, make sure to off-load this work onto a background thread like above, since the library won't do it for you.

License

Copyright 2017-2018 Marcel Schnelle

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

rxbonjour's People

Contributors

aurae avatar curioustechizen avatar i906 avatar ivbaranov avatar mannodermaus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxbonjour's Issues

Getting host address as 0.0.0.0

When I try to use this library in android devices connected to WiFi network it works smoothly and discovers the service as desired.

But when I try to use it on Android devices connected to network through Ethernet cable it finds/discovers the service but it returns host address as 0.0.0.0

Is there any solution to find host address while connected over ethernet, or it only supports devices connected to WiFi.

Crash - JmDNSDiscoveryEngine.kt:39

Hi,

We're using
implementation "de.mannodermaus.rxjava2:rxbonjour:2.0.0-RC1"
implementation "de.mannodermaus.rxjava2:rxbonjour-platform-android:2.0.0-RC1"
implementation "de.mannodermaus.rxjava2:rxbonjour-driver-jmdns:2.0.0-RC1"

and have seen one instance of a crash reported in JmDNSDiscoveryEngine.kt:39

Device details -
Android 7.1.1
Brand: motorola
Model: Moto E (4) Plus
Orientation: Portrait
RAM free: 1.24 GB
Disk free: 2.1 GB

No idea on the particular users network setup I'm afraid

If you would like any more details on the crash report let me know.

Thanks
John

Split into RxBonjour core and RxBonjour Android

I am developing a set of applications which are intended to run on Desktop and Android devices. RxBonjour is good (because it is rx ^_^ ), but as far as I understand it can't be a dependency to pure java app because of its' android nature and android dependencies.

What are your thoughts about it?

Terrible message: Skipped 119 frames! The application may be doing too much work on its main thread.

Hi there is a very fat issue in you lib.

First i am registrate service :
private var disposableBonjourBradcast: Disposable = Disposables.empty()

val chatNameCode = PrefProvider.getInstance().currentTourCode
      val broadcastConfig = BonjourBroadcastConfig(
              type = "_$chatNameCode._tcp",
              name = PrefProvider.getInstance().userId,
              address = inetAddress,
              port = tcpServerPort,
              txtRecords = mapOf(
                      HOST to inetAddress.hostAddress!!,
                      TCP_PORT to tcpServerPort.toString(),
                      UDP_PORT to udpServerPort.toString(),
                      USER_ID to PrefProvider.getInstance().userId,
                      USER_TYPE to PrefProvider.getInstance().myCurrentRole,
                      USER_NAME to PrefProvider.getInstance().userName,

              ))

      disposableBonjourBradcast = rxBonjour.newBroadcast(broadcastConfig)
              .onErrorComplete { throw ConnectionException(it) }
              .subscribeOn(Schedulers.io())
              .subscribe()

It is work ok.

But when i try to unsubscribe for re -register service for example to pull to-refresh by this :

disposableBonjourBradcast.dispose()

My screen became freeze some during milliseconds. In logcat i see terrible message:

I/Choreographer: Skipped 119 frames! The application may be doing too much work on its main thread.

Discovery no longer works with JMDNS

Recently (in the past two days or so) service discovery with JMDNS has stopped working. It was working last week. It works with NSDManager but then I can't get the txt records that I need. Going back to previous versions doesn't work, as does going back to previous versions of my code. If I open up a different app that does service discovery, like https://play.google.com/store/apps/details?id=com.druk.bonjour.browser&hl=en and then go back to my app it will find some services. Do you know anything that could be causing this issue? I am using a Moto X 2nd gen with Android 6.0.

Many thanks.

Crash if there are multiple services discovered

This caught me off-guard. Apparently, an instance of NsdManager.ResolveListener cannot be re-used. That is to say, for each newly found service, you need to supply a new instance of ResolveListener to the resolveService() method. If you try to reuse the listener, you get a crash with the following trace:

Caused by: java.lang.IllegalArgumentException: listener already in use
            at android.net.nsd.NsdManager.resolveService(NsdManager.java:613)
            at rxbonjour.internal.JBBonjourDiscovery$1$2.onNext(JBBonjourDiscovery.java:99)

The easiest way to solve this is to replace the offending line with:

nsdManager.resolveService(info, createResolveListener());

and then, instead of having a member variable resolveListener, you create a new one in the method:

private NsdManager.ResolveListener createResolveListener() {
    return new NsdManager.ResolveListener() {
        //Rest of the code here
    };
}

I would have sent this change as a PR but I am not sure if this change will impact any of the Rx stuff.

Can't bind to any interface except WIFI

If android device has multiple interfaces along with WIFI binding to particular address explicitly results in 0.0.0.0 address if WIFI is disabled or in actual WIFI address if WIFI is enabled broadcasted in mDNS service record. Thus value passed to .address method is completely ignored.

Example code in kotlin:

val subscription = RxBonjour.newBroadcast("_http._tcp")
        .name("_my_service")
        .address(InetAddress.getByName("192.168.0.11"))
        .port(HTTP_PORT)
        .build()
        .start(this)
        .subscribe({
            log.info("{}", it)
        })

Result would be either 0.0.0.0 or ip of WIFI network.

This happens because of this method of SupportUtils class:

/**
 * Returns the JmDNS shared among all subscribers for Bonjour events, creating it if necessary.
 *
 * @param context Context used to access the WifiManager for the device's IP address with which JmDNS is initialized
 * @return The JmDNS instance
 * @throws IOException In case the device's address can't be resolved
 */
@Override public JmDNS getManager(Context context) throws IOException {
    synchronized (jmdnsLock) {
        if (jmdnsInstance == null || !isAvailable()) {
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            InetAddress inetAddress = getInetAddress(wifiManager);
            jmdnsInstance = JmDNS.create(inetAddress, inetAddress.toString());
            jmdnsSubscriberCount.set(0);
        }
        return jmdnsInstance;
    }
}

which gets context passed in SupportBonjourBroadcast class' start method:

final JmDNS jmdns = utils.getManager(context);

To override this behaviour I wrote another implementation of BonjourBroadcast abstract class which is almost the same except it uses differen method in support utils. This is its kotlin code:

    fun getManager(inetAddress: InetAddress): JmDNS? {
        synchronized(jmdnsLock) {
            if (jmdnsInstance == null || !isAvailable()) {
                jmdnsInstance = JmDNS.create(inetAddress, inetAddress.toString())
                jmdnsSubscriberCount.set(0)
            }
            return jmdnsInstance
        }
    }

I am not proposing this exact fix but I think something should be done with the issue of binding to the address specified by corresponding method.

Crash Observed in Discovery

We are using:

        implementation "de.mannodermaus.rxjava2:rxbonjour:2.0.0-RC1"
        implementation "de.mannodermaus.rxjava2:rxbonjour-platform-android:2.0.0-RC1"
        implementation('de.mannodermaus.rxjava2:rxbonjour-driver-nsdmanager:2.0.0-RC1') {
            exclude group: "org.slf4j"
        }

Saw this random crash:

kotlin.KotlinNullPointerException
    at de.mannodermaus.rxbonjour.BonjourService.<init>(Models.kt:27)
    at de.mannodermaus.rxbonjour.drivers.nsdmanager.ExtensionsKt.toLibraryModel(Extensions.kt:36)
    at de.mannodermaus.rxbonjour.drivers.nsdmanager.NsdManagerDiscoveryEngine$NsdDiscoveryListener.onServiceLost(NsdManagerDiscoveryEngine.kt:61)
    at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:390)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:214)
    at android.os.HandlerThread.run(HandlerThread.java:67)

Creating a network service discovery request

So I have an observable singleton:

/** Provides {@link BonjourEvent} observable. */
  @Provides @Singleton Observable<BonjourEvent> provideBonjourEventStream(Application app) {
    return RxBonjour.startDiscovery(app, "_myservers._tcp");
  }

"myservers" never changes.
In my fragment I have:

@Override public void onStart() {
    super.onStart();
    subscription = bonjourEventStream  
        .subscribeOn(Schedulers.computation()) //
        .observeOn(AndroidSchedulers.mainThread()) //
        .subscribe(bonjourEvent -> {
            ...
         });
}

@Override public void onPause() {
    super.onPause();
    if (subscription != null && !subscription.isUnsubscribed()) subscription.unsubscribe();
  }

So when I switch the screen on an off the subscription unsubscribes and subscribes again. One out of ten times of switching the screen I have:

FATAL EXCEPTION: RxCachedThreadScheduler-15
E/AndroidRuntime: Process: com.symway.assist, PID: 24660
E/AndroidRuntime: java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
E/AndroidRuntime:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:60)
E/AndroidRuntime:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:841)
E/AndroidRuntime:  Caused by: rx.exceptions.OnErrorNotImplementedException: MulticastLock under-locked RxBonjourDiscovery
E/AndroidRuntime:     at rx.Observable$29.onError(Observable.java:7498)
E/AndroidRuntime:     at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:154)
E/AndroidRuntime:     at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
E/AndroidRuntime:     at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:197)
E/AndroidRuntime:     at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:170)
E/AndroidRuntime:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
E/AndroidRuntime:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:841) 
E/AndroidRuntime:  Caused by: java.lang.RuntimeException: MulticastLock under-locked RxBonjourDiscovery
E/AndroidRuntime:     at android.net.wifi.WifiManager$MulticastLock.release(WifiManager.java:2132)
E/AndroidRuntime:     at rxbonjour.internal.SupportBonjourDiscovery$2$1.call(SupportBonjourDiscovery.java:171)
E/AndroidRuntime:     at rxbonjour.internal.SupportBonjourDiscovery$2$1.call(SupportBonjourDiscovery.java:163)
E/AndroidRuntime:     at rx.Observable.unsafeSubscribe(Observable.java:7713)
E/AndroidRuntime:     at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
E/AndroidRuntime:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) 
E/AndroidRuntime:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152) 
E/AndroidRuntime:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265) 
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:841) 

On SupportBonjourDiscovery.java:171 I see the release, so when I try to subscribe again on screen on it SHOULD go wrong but sometimes it doesn't.

Finally, I have got a question if one just shouldn't unsubscribe ever or one must not have singleton BonjourEvent observable?

NoClassDefFoundError

On a new Android project using the dependency from jcenter()

compile "de.mannodermaus.rxjava2:rxbonjour:2.0.0-beta1"

I get

java.lang.NoClassDefFoundError: de.mannodermaus.rxbonjour.discovery.SupportBonjourDiscovery$1$2

when I use

        RxBonjour.newDiscovery(this, "_http._tcp")
                .subscribeOn(Schedulers.io())
                .subscribe({ it ->
                    val item = it.service
                    val type = if (it.type == ADDED) "Added" else "Removed"
                    Log.v("DiscoveryService", "$type: ${item.name} @  ${item.host}:${item.port}")

                }, {
                    Log.e("DiscoveryService", it.message)
                })

Removed events not fired

I've written a very simple test application to test out this library, which seems very promising for our needs, but run into an issue where it doesn't seem that Removed events are ever fired.

This is with the README example setup in gradle, eg

implementation "de.mannodermaus.rxjava2:rxbonjour:2.0.0-RC1"
implementation "de.mannodermaus.rxjava2:rxbonjour-platform-android:2.0.0-RC1"
implementation "de.mannodermaus.rxjava2:rxbonjour-driver-jmdns:2.0.0-RC1"

I start a simple one-activity app on android that advertises on one device and discovers on another, with disposing onPause, but never receive a Removed BonjourEvent on the discovering device, even though I'm navigating away from the activity on the advertising device and stopping the broadcast.

In comparison, using an open source app available on the play store https://github.com/andriydruk/BonjourBrowser seems to remove my custom advertising app almost immediately...

Update JmDNS dependency

Last I checked, the guys over at JmDNS are at version 3.5.1 right now, whereas RxBonjour still pulls in an older version.

java.lang.IllegalStateException: Queue full

Sometime I am have the following crash in my app due to
java.lang.IllegalStateException: Queue full at java.util.AbstractQueue.add(AbstractQueue.java:69) at rxbonjour.internal.Backlog.add(Backlog.java:75) at rxbonjour.discovery.JBBonjourDiscovery$1$1.onServiceFound(JBBonjourDiscovery.java:115) at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:333) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:145) at android.os.HandlerThread.run(HandlerThread.java:61)

Can we fix it by increasing a queue from 32 to some bigger value? or any other better fixes also welcome. Thank you!

Add Service Registration

At the moment, RxBonjour can discover services, but isn't able to register new ones. This may be implemented in a future version!

onServiceLost producing NullPointerException

I have the below code in a background service.

I also tried JmDNSDriver but thats results in the following error
W/art: Failed to open zip archive '/system/framework/qcom.fmradio.jar': I/O Error

val rxBonjour = RxBonjour.Builder()
                .platform(AndroidPlatform.create(this))
                .driver(NsdManagerDriver.create(this))
                .create()

val nsdDisposable = rxBonjour.newDiscovery("_octoprint._tcp")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        { event ->
            when(event) {
                is BonjourEvent.Added -> println("Resolved Service: ${event.service}")
                is BonjourEvent.Removed -> println("Lost Service: ${event.service}")
            }
        },
        { error -> println("Error during Discovery: ${error.message}") }
    )
com.robo3d E/AndroidRuntime: FATAL EXCEPTION: NsdManager
                                                            Process: com.robo3d, PID: 10842
                                                            kotlin.KotlinNullPointerException
                                                                at de.mannodermaus.rxbonjour.BonjourService.<init>(Models.kt:27)
                                                                at de.mannodermaus.rxbonjour.drivers.nsdmanager.ExtensionsKt.toLibraryModel(Extensions.kt:36)
                                                                at de.mannodermaus.rxbonjour.drivers.nsdmanager.NsdManagerDiscoveryEngine$NsdDiscoveryListener.onServiceLost(NsdManagerDiscoveryEngine.kt:61)
                                                                at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:336)
                                                                at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                at android.os.Looper.loop(Looper.java:148)
                                                                at android.os.HandlerThread.run(HandlerThread.java:61)

Expose DNS-SD TXT records in BonjourService

JmDNS already provides this info via ServiceInfo#getPropertyNames and ServiceInfo#getProprtyString(String) methods.

NsdManager only has getAttributes from API 21 onwards, so you could consider returning an empty collection if user chooses to use the NsdManager API and running on API level < 21.

Observed a crash in service discovery

Currently i am using version "de.mannodermaus:rxbonjour-1x:1.0.0" in my android app.
I found a crash in the process of service discovery. Please see the log below for detailed analysis

15:07:27.229 [Thread-526] ERROR ExceptionHandler - Unhandled exception
java.util.ConcurrentModificationException: null
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:967) ~[na:0.0]
at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[na:0.0]
at java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:0.0]
at java.lang.String.valueOf(String.java:2683) ~[na:0.0]
at java.lang.StringBuilder.append(StringBuilder.java:129) ~[na:0.0]
at javax.jmdns.impl.JmDNSImpl.toString(JmDNSImpl.java:1959) ~[na:0.0]
at java.lang.String.valueOf(String.java:2683) ~[na:0.0]
at java.lang.StringBuilder.append(StringBuilder.java:129) ~[na:0.0]
at javax.jmdns.impl.JmDNSImpl.close(JmDNSImpl.java:1862) ~[na:0.0]
at rxbonjour.utils.SupportUtils.close(SupportUtils.java:111) ~[na:0.0]
at rxbonjour.utils.SupportUtils.closeIfNecessary(SupportUtils.java:100) ~[na:0.0]
at rxbonjour.discovery.SupportBonjourDiscovery$2.run(SupportBonjourDiscovery.java:162) ~[na:0.0]

We are in process to release the app so could you please revert me on this.

NsdManager is garbage. Add implementation selector

The JB implementation using NsdManager breaks after a while:

For now, it seems like JmDNS should become the default implementation, with NsdManager as an opt-in alternative.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.