tinder / scarlet Goto Github PK
View Code? Open in Web Editor NEWA Retrofit inspired WebSocket client for Kotlin, Java, and Android
License: Other
A Retrofit inspired WebSocket client for Kotlin, Java, and Android
License: Other
Hy im using the 0.1.7 branch from Jitpack.
Currently I have this code and the logs don't display the "socket send event" message.
However I get the message from OkHttp
OkHttp: <-- 101 Switching Protocols https://ws.bitstamp.net/ (147ms)
Which means the handshake was successful, but the connection isn't somehow opened?
I also tried commenting out the filter operator without success.
My subscribe code looks like this:
val event = SocketEventFactory.createEvent() val repo = appRepository.observeWebSocketEvent() .filter { it is WebSocket.Event.OnConnectionOpened<*> } .subscribe({ Timber.i("[app] socket send event:%s", event) appRepository.sendEvent(event) }, { e -> Timber.e(e, "[app] socket error") })
I think theres a lifecycle issue, since when I put the app into background and then go back in, the observer receives events.
I mean to say that even though I subscribe to the socket in onResume() method, it doesn't get initiated and when I put the app in background and then resume again the sockets start working.
Been able to add scarlet-protocol-websocket-okhttp
and scarlet-stream-adapter-rxjava2
but gradle can't resolve the gson adapter.
I hope it is not a dump question...
Not sure if this a bug in scarlet, in RxJava or just unsupported use case.
Repro steps unknown it is anonymous crash report.
Scarlet usage related to cancelation looks like this:
job = launch {
fooService.receiveFoo().consumeEach { foo -> //...
}
}
job
may be canceled at anytime.
Scarlet version: 0.1.4
Stacktrace:
java.lang.NullPointerException: subscribeActual failed
at io.reactivex.Maybe.empty(SourceFile:3732)
at io.reactivex.internal.operators.maybe.MaybeMap.subscribeActual(SourceFile:40)
at io.reactivex.Maybe.empty(SourceFile:3727)
at io.reactivex.internal.operators.maybe.MaybeFilter.subscribeActual(SourceFile:39)
at io.reactivex.Maybe.empty(SourceFile:3727)
at io.reactivex.internal.operators.maybe.MaybeMap.subscribeActual(SourceFile:40)
at io.reactivex.Maybe.empty(SourceFile:3727)
at io.reactivex.internal.operators.maybe.MaybeFilter.subscribeActual(SourceFile:39)
at io.reactivex.Maybe.empty(SourceFile:3727)
at io.reactivex.internal.operators.maybe.MaybeMap.subscribeActual(SourceFile:40)
at io.reactivex.Maybe.empty(SourceFile:3727)
at io.reactivex.internal.operators.flowable.FlowableFlatMapMaybe$FlatMapMaybeSubscriber.getOrCreateQueue(SourceFile:132)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(SourceFile:400)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(SourceFile:176)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(SourceFile:61)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(SourceFile:52)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by kotlinx.coroutines.experimental.JobCancellationException: Child job was cancelled because of parent failure
Caused by kotlinx.coroutines.experimental.JobCancellationException: Job was cancelled normally
Not sure if it's an appropriate place to ask this, but it's always reproducible with Scarlet.
I created a simple empty proejct for Android in the latest Android Studio with Kotlin support. Just a simple hello world application. It worked fine, I only added some test code tp onCreate()
:
val text = "test string"
val newtext = text.replace("string", "replaced")
Then I simply added Scarlet as dependency as suggested in the README, after doing that the application crashes on android immediately when trying to work with strings (val text = "test string"
produces a crash), telling that the java.lang.NoClassDefFoundError: Failed resolution of: Lkotlin/text/StringsKt;
If I remove Scarlet from dependencies, it starts working again. What's the problem with it?
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
signingConfigs {
}
compileSdkVersion 28
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.core:core-ktx:1.1.0-alpha03'
implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
implementation 'com.github.tinder:scarlet:0.1.7'
}
I may assume that the issue arises from the fact, that the library and my project use slightly different kotlin versions (they're different only in the patch version and should be compatible though), so I'm not sure if it is the problem.
Also there is a warning in Android Studio:
/home/daniel/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.2.10/85fe1811f3e586d0cc53aba1394d8089f1862215/kotlin-stdlib-jdk8-1.2.10.jar (version 1.2)
/home/daniel/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.3.0/683e04a4e7f17437d7e1390480f312e122e42e9e/kotlin-stdlib-jdk7-1.3.0.jar (version 1.3)
/home/daniel/.gradle/caches/transforms-1/files-1.1/kotlin-reflect-1.3.0.jar/1763cf1efecf987258647674f6df6b16/jetified-kotlin-reflect-1.3.0.jar (version 1.3)
/home/daniel/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.3.0/a134b0cfe9bb44f98b0b3e889cda07923eea9428/kotlin-stdlib-1.3.0.jar (version 1.3)
/home/daniel/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.3.0/84a2e0288dc17cd64d692eb1e5e0de8cd5ff0846/kotlin-stdlib-common-1.3.0.jar (version 1.3)
Not sure where this jdk8 dependency (version 1.2) comes from.
Hi. I found a problem with reconnecting okhttp websockets on 0.1.7/0.2.3-alpha1. After several attempts the reconnection stops.
I think I found a reason. We subscribe on socket event in Connection.open(). But sometimes OkHttpWebSocketEventObserver emit WebSocket.Event.OnConnectionFailed(t) before subscription complete and this event just ignored.
Solution - replace PublishProcessor to BehaviorProcessor.
When using Scarlet with OkHttp websocket + AndroidLifecycle with `ofApplicationForeground in the configs, putting the app in the background and bringing back forward closes & re-initiates the connection.
However, turning on/off the airplane mode does not close & re-initiate the socket connection.
Scarlet version: master-SNAPSHOT
Exception in thread "main" io.reactivex.exceptions.MissingBackpressureException: Could not emit value due to lack of requests
at io.reactivex.processors.PublishProcessor$PublishSubscription.onNext(PublishProcessor.java:365)
at io.reactivex.processors.PublishProcessor.onNext(PublishProcessor.java:244)
at com.tinder.scarlet.internal.connection.Connection$StateManager.handleEvent(Connection.kt:176)
at com.tinder.scarlet.internal.connection.subscriber.WebSocketEventSubscriber.onNext(WebSocketEventSubscriber.kt:16)
at com.tinder.scarlet.internal.connection.subscriber.WebSocketEventSubscriber.onNext(WebSocketEventSubscriber.kt:12)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(FlowableMap.java:69)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(FlowableObserveOn.java:400)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(FlowableObserveOn.java:176)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Repro steps unkown, issue from crash report.
Scarlet version: 0.1.4
Fatal Exception: MissingBackpressureException: Could not emit value due to lack of requests
at io.reactivex.processors.PublishProcessor$PublishSubscription.onError(SourceFile:319)
at io.reactivex.processors.PublishProcessor.onNext(SourceFile:197)
at com.tinder.scarlet.internal.connection.Connection$StateManager.access$scheduleRetry(SourceFile:163)
at com.tinder.scarlet.internal.connection.subscriber.WebSocketEventSubscriber.onError(SourceFile:16)
at com.tinder.scarlet.internal.connection.subscriber.WebSocketEventSubscriber.onNext(SourceFile:12)
at io.reactivex.internal.operators.flowable.FlowableMap$MapSubscriber.onNext(SourceFile:69)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$ObserveOnSubscriber.runAsync(SourceFile:400)
at io.reactivex.internal.operators.flowable.FlowableObserveOn$BaseObserveOnSubscriber.run(SourceFile:176)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(SourceFile:61)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(SourceFile:52)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
I've started using Scarlet this week and I've noticed that the WebSocket connection fails and a new one is started every minute or so. Is there an easy way to keep the connection open by sending a ping instead of re-connecting every time?
I'm using version 0.1.7.
Hi, I was wandering whether it is possible to close the connection on purpose. Is it?
e.g. by pressing a button to stop receiving stuff?
Hello.
Can you please explain me, wtf is going on here?
val scarletBuilder = Scarlet.Configuration(
streamAdapterFactories = listOf(CoroutinesStreamAdapterFactory()),
debug = true
)
val protocol = object : Protocol {
override fun createChannelFactory(): Channel.Factory = object : Channel.Factory {
override fun create(listener: Channel.Listener, parent: Channel?): Channel? = parent
}
override fun createEventAdapterFactory(): ProtocolSpecificEventAdapter.Factory {
TODO: fill this
}
}
val scarlet = Scarlet(protocol, scarletBuilder)
Is this a new way to create a Scarlet instance, really?
If yes - where is documentation? Wtf is ProtocolSpecificEventAdapter
? Why i need ChannelFactory
?
My case is open WSocket with domain: abcd.xyz/admin
So how to use dynamic path like Retrofit or must change base WS url?
Many thanks!
I tried to use scarlet (0.16 and 0.17) and I having an issue when proguard is enabled.
Are there any specific rules for that?
Kotlin is already at version 1.3.0 and therefore coroutines are not experimental anymore.
This update also implied a change at package level of the coroutine classes leaving the experimental
namespace.
On the other hand, looking at CoroutinesStreamAdapterFactory
class, particularly at:
override fun create(type: Type): StreamAdapter<Any, Any> {
return when (type.getRawType()) {
ReceiveChannel::class.java -> ReceiveChannelStreamAdapter()
else -> throw IllegalArgumentException()
}
}
there's a mismatch between the old package and the current one, causing an IllegalArgumentException()
Fix should be quite easy, update kotlin version to 1.3.0 and change the package imports to the new ones.
I have added this project to my pom.xml in a regular Java application.
However I'm getting the following error
"Missing artifact androidx.appcompat:appcompat:jar:1.0.0"
Is it not possible to use this in a regular Java program? if so how?
Hi
Don't works headers for okhttp3 client, that uses for scarlet config builds.
I need to add user token in headers, but nothing happens
It's also don't displays in logs.
Can you explain this issue? Thanks
ver 0.1.7
Hi,
Using version 0.2.1-alpha4 I cannot compile sample code:
val protocol = OkHttpWebSocket(
client,
OkHttpWebSocket.SimpleRequestFactory(
{ Request.Builder().url("wss://ws-feed.gdax.com").build() },
{ ShutdownReason.GRACEFUL }
)
)
OkHttpWebSocket
constructor is internal and it doesn't have a SimpleRequestFactory
method, also constructor doesn't accept parameter types used in the sample.
Thanks.
Scarlet.Builder() not found in version 0.2.1, but 0.1.6 is ok
Hi, I'm trying to communicate with a STOMP server with my Android APP. There is an issue about that, but it is closed and not so much helpful.
For example how can I subscribe to a topic with the same Scarlet/Service instance? How to Send a message to an other subEndpoint?
It will be very useful for example extend the annotations @receive and @send to append a different endpoint like STOMP Spring Server can offer.
Thanks
What about extensions and utils from sample?
OkHttpClient.newWebSocketFactory(...)
Any plans for LoganSquare support?
I am trying to use Scarlet with Koin but everytime I acces the Service instance from the dependency graph, Scarlet throws an java.lang.IllegalStateException: Service method not found
Exception.
Here is how the Dependency definition looks like
val networkingModule = module {
single { createOkHttpClient() }
single { createScarlet(get(), "ws://demos.kaazing.com/echo") }
single { createEchoService(get()) }
}
fun createOkHttpClient(): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build()
fun createScarlet(client: OkHttpClient, url: String) = Scarlet.Builder()
.webSocketFactory(client.newWebSocketFactory(url))
.addMessageAdapterFactory(MoshiMessageAdapter.Factory())
.addStreamAdapterFactory(CoroutinesStreamAdapterFactory())
.build()
fun createEchoService(scarlet: Scarlet): EchoService = scarlet.create()
And this is how you would end up calling it (in this example Activity):
class MainActivity : AppCompatActivity() {
val service: EchoService by inject() //lazy!
override fun onCreate(savedInstanceState: Bundle?) {
...
service.observeEvents()
}
}
Injecting the Scarlet Instance and creating the service in the activity however would work:
class MainActivity : AppCompatActivity() {
val scarlet: Scarlet by inject()
override fun onCreate(savedInstanceState: Bundle?) {
...
val service: EchoService = scarlet.create()
service.observeEvents()
}
}
The only Problem with the workaround is that I would need to create new instances of the service everywhere I need it. Of course I could setup a holder pattern or something but that would defeat the purpose of using DI.
Here is the full stacktrace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sample.scarlet/com.sample.scarlet.MainActivity}: java.lang.IllegalStateException: Service method not found
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalStateException: Service method not found
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor.execute(ServiceMethodExecutor.kt:18)
at com.tinder.scarlet.internal.Service.execute(Service.kt:18)
at com.tinder.scarlet.Scarlet$createInvocationHandler$1.invoke(Scarlet.kt:123)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy2.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2896)
at java.lang.StringBuilder.append(StringBuilder.java:132)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$1.invoke(InstanceRegistry.kt:112)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1$1.invoke(InstanceRegistry.kt:36)
at org.koin.core.stack.ResolutionStack.resolve(ResolutionStack.kt:44)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:105)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:36)
at org.koin.core.time.DurationKt.measureDuration(Duration.kt:8)
at org.koin.core.instance.InstanceRegistry.proceedResolution(InstanceRegistry.kt:84)
at org.koin.core.instance.InstanceRegistry.resolve(InstanceRegistry.kt:63)
at org.koin.core.instance.InstanceRegistry.resolve$default(InstanceRegistry.kt:48)
at com.sample.scarlet.MainActivity$$special$$inlined$inject$1.invoke(ComponentCallbacksExt.kt:148)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.sample.scarlet.MainActivity.getService(Unknown Source:7)
at com.sample.scarlet.MainActivity.onCreate(MainActivity.kt:19)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
If I do not specify lifecycle
for Scarlet.Configuration
, SocketIoClient
is not connecting.
My dagger module which creates Scarlet
@Module
class MykModule {
@Singleton
@Provides
fun provideScarletConfiguration(app: Application): Scarlet.Configuration {
return Scarlet.Configuration(
lifecycle = AndroidLifecycle.ofApplicationForeground(app), // With out this, Scarlet is not connectin
messageAdapterFactories = listOf(MoshiMessageAdapter.Factory()),
streamAdapterFactories = listOf(RxJava2StreamAdapterFactory()),
)
}
@Singleton
@Provides
fun provideScarlet(config: Scarlet.Configuration): Scarlet {
val client = SocketIoClient({ "https://my.api" })
return Scarlet(client, config)
}
@Singleton
@Provides
fun provideMyApi(scarlet: Scarlet): MyApi {
return scarlet.create<MyApi>()
}
@Singleton
@Provides
fun providePingTopic(scarlet: Scarlet, config: Scarlet.Configuration): PingTopic {
return scarlet.child(SocketIoEventName("ping"), config).create<PingTopic>()
}
}
I try to keep my connection alive even when the app is in background, so I can not use lifecycle AndroidLifecycle.ofApplicationForeground(app)
Im using Scarlet 0.2.1-alpha4
Hi, my backend generates a wss:// url for me, which however is a one time thing, meaning upon connetion lost, I wont be able to reconnect, which is what Im seeing with Scarlet, (infinite loop of WaitingToRetry, Connecting)
Is there way to disable the reconnecting policy and Ill maybe handle connecting back manually? Since I need to call backend api again to generate a new wss:// url
Thanks
Hi,
The same code using RxJava stream adapter works fine.
val scarlet = Scarlet.Builder().webSocketFactory(client.newWebSocketFactory(SOCKET_URL))
.lifecycle(lifecycle)
.addMessageAdapterFactory(GsonMessageAdapter.Factory())
.addStreamAdapterFactory(CoroutinesStreamAdapterFactory()).build()
return scarlet.create()
interface CashCoolSocketService {
@Receive
fun observeUser(): ReceiveChannel<UserSerializer>
}
GlobalScope.launch(CoroutineExceptionHandler { _, throwable ->
Log.e(
"SOCKET ERROR",
throwable.message
)
}) {
val user = ws.observeUser().receive()
Log.d("SOCKET MESSAGE", user.toString())
}
E/AndroidRuntime: FATAL EXCEPTION: main
Process: app.cashcool.cashcool, PID: 3109
java.lang.IllegalStateException: Cannot resolve stream adapter for type kotlinx.coroutines.channels.ReceiveChannel.
at com.tinder.scarlet.internal.servicemethod.StreamAdapterResolver.resolve(StreamAdapterResolver.kt:26)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.createStreamAdapter(ServiceMethod.kt:89)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:81)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:66)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.toServiceMethod(ServiceMethodExecutor.kt:47)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.findServiceMethods(ServiceMethodExecutor.kt:38)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.create(ServiceMethodExecutor.kt:32)
at com.tinder.scarlet.internal.Service$Factory.create(Service.kt:28)
at com.tinder.scarlet.Scarlet.implementService(Scarlet.kt:108)
at com.tinder.scarlet.Scarlet.create(Scarlet.kt:100)
at app.cashcool.cashcool.core.di.ApplicationModule.provideCashCoolSocketService(ApplicationModule.kt:109)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.proxyProvideCashCoolSocketService(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:55)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.provideInstance(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:41)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:34)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.injectCreateUserFragment(DaggerApplicationComponent.java:328)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.inject(DaggerApplicationComponent.java:288)
at app.cashcool.cashcool.features.user.create.CreateUserFragment.onCreate(CreateUserFragment.kt:109)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:844)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1196)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1079)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:118)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1844)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1802)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1709)
at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManagerImpl.java:147)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: io.reactivex.exceptions.CompositeException: 2 exceptions occurred.
at com.tinder.scarlet.internal.servicemethod.StreamAdapterResolver.resolve(StreamAdapterResolver.kt:25)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.createStreamAdapter(ServiceMethod.kt:89)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:81)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:66)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.toServiceMethod(ServiceMethodExecutor.kt:47)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.findServiceMethods(ServiceMethodExecutor.kt:38)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.create(ServiceMethodExecutor.kt:32)
at com.tinder.scarlet.internal.Service$Factory.create(Service.kt:28)
at com.tinder.scarlet.Scarlet.implementService(Scarlet.kt:108)
at com.tinder.scarlet.Scarlet.create(Scarlet.kt:100)
at app.cashcool.cashcool.core.di.ApplicationModule.provideCashCoolSocketService(ApplicationModule.kt:109)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.proxyProvideCashCoolSocketService(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:55)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.provideInstance(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:41)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:34)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.injectCreateUserFragment(DaggerApplicationComponent.java:328)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.inject(DaggerApplicationComponent.java:288)
at app.cashcool.cashcool.features.user.create.CreateUserFragment.onCreate(CreateUserFragment.kt:109)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:844)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1196)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1079)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:118)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1844)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1802)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1709)
at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManagerImpl.java:147)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: io.reactivex.exceptions.CompositeException$CompositeExceptionCausalChain: Chain of Causes for CompositeException In Order Received =>
at android.util.Log.printlns(Log.java:417)
E/AndroidRuntime: at com.android.internal.os.RuntimeInit.Clog_e(RuntimeInit.java:60)
at com.android.internal.os.RuntimeInit.-wrap0(Unknown Source:0)
at com.android.internal.os.RuntimeInit$LoggingHandler.uncaughtException(RuntimeInit.java:89)
at java.lang.Thread.dispatchUncaughtException(Thread.java:1948)
Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lkotlinx/coroutines/experimental/channels/ReceiveChannel;
at com.tinder.streamadapter.coroutines.CoroutinesStreamAdapterFactory.create(CoroutinesStreamAdapterFactory.kt:19)
at com.tinder.scarlet.internal.servicemethod.StreamAdapterResolver.resolve(StreamAdapterResolver.kt:19)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.createStreamAdapter(ServiceMethod.kt:89)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:81)
at com.tinder.scarlet.internal.servicemethod.ServiceMethod$Receive$Factory.create(ServiceMethod.kt:66)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.toServiceMethod(ServiceMethodExecutor.kt:47)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.findServiceMethods(ServiceMethodExecutor.kt:38)
at com.tinder.scarlet.internal.servicemethod.ServiceMethodExecutor$Factory.create(ServiceMethodExecutor.kt:32)
at com.tinder.scarlet.internal.Service$Factory.create(Service.kt:28)
at com.tinder.scarlet.Scarlet.implementService(Scarlet.kt:108)
at com.tinder.scarlet.Scarlet.create(Scarlet.kt:100)
at app.cashcool.cashcool.core.di.ApplicationModule.provideCashCoolSocketService(ApplicationModule.kt:109)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.proxyProvideCashCoolSocketService(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:55)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.provideInstance(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:41)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:34)
at app.cashcool.cashcool.core.di.ApplicationModule_ProvideCashCoolSocketServiceFactory.get(ApplicationModule_ProvideCashCoolSocketServiceFactory.java:11)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.injectCreateUserFragment(DaggerApplicationComponent.java:328)
at app.cashcool.cashcool.core.di.DaggerApplicationComponent.inject(DaggerApplicationComponent.java:288)
at app.cashcool.cashcool.features.user.create.CreateUserFragment.onCreate(CreateUserFragment.kt:109)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2414)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:844)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1196)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1079)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:118)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1844)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1802)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1709)
at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManagerImpl.java:147)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "kotlinx.coroutines.experimental.channels.ReceiveChannel" on path: DexPathList[[zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/base.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_dependencies_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_resources_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_0_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_1_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_2_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_3_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_4_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_5_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_6_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_7_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_8_apk.apk", zip file "/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/lib/x86, /system/lib, /system/vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 36 more
Suppressed: java.io.IOException: No original dex files found for dex location /data/app/app.cashcool.cashcool-Szw56xvjCrKy9lGGtl4lKg==/split_lib_resources_apk.apk
at dalvik.system.DexFile.openDexFileNative(Native Method)
at dalvik.system.DexFile.openDexFile(DexFile.java:353)
at dalvik.system.DexFile.(DexFile.java:100)
at dalvik.system.DexFile.(DexFile.java:74)
at dalvik.system.DexPathList.loadDexFile(DexPathList.java:374)
at dalvik.system.DexPathList.makeDexElements(DexPathList.java:337)
at dalvik.system.DexPathList.(DexPathList.java:157)
at dalvik.system.BaseDexClassLoader.(BaseDexClassLoader.java:65)
at dalvik.system.PathClassLoader.(PathClassLoader.java:64)
at com.android.internal.os.PathClassLoaderFactory.createClassLoader(PathClassLoaderFactory.java:43)
at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:69)
at android.app.ApplicationLoaders.getClassLoader(ApplicationLoaders.java:36)
at android.app.LoadedApk.createOrUpdateClassLoaderLocked(LoadedApk.java:676)
at android.app.LoadedApk.getClassLoader(LoadedApk.java:709)
at android.app.LoadedApk.getResources(LoadedApk.java:936)
at android.app.ContextImpl.createAppContext(ContextImpl.java:2242)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5672)
at android.app.ActivityThread.-wrap1(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1661)
at android.os.Handler.dispatchMessage(Handler.java:105)
... 5 more
getting Runtime exception for the Filepicker
ava.lang.RuntimeException: Unable to get provider droidninja.filepicker.utils.FilePickerProvider: java.lang.IllegalArgumentException: Missing android.support.FILE_PROVIDER_PATHS meta-data
The current documentation for 0.2.x is obsolete. Some classes are not present anymore. Example WebSocketEvent
.
I'm trying to emulate socket.emit with this library and I'm not really sure how to do that? Is communicating with a SocketIO server supported?
Any plans to introduce a StreamAdapter
for Kotlin coroutines ? Maybe returning a ReceiveChannel
?
Thanks
The standard for websocket communication is often regarded as being STOMP. Does this / will this library have STOMP compatibility in its message layer?
Hi, I'm having trouble integrating Scarlet into my Android app written in Java. Can you provide an example please (maybe put it in the Readme section along with the Kotlin example)?
I have a Scarlet instance inside a Android LifecycleService which has been started in foreground, in order for the service to not be destroyed when the application is not in foreground anymore. I've set the Scarlet lifecycle owner as the LifecycleService in which it resides.
I'm trying to start the Scarlet instance, but it fails (404 not found), hence the BackoffStrategy kicks in, which works as expected. However, if I kill the service (its onDestroy is called), the Scarlet instance continues to retry connecting to the server. I expected it to die along with the service.
Unfortunately, no WebSocket event is being called, thus I don't have access to the WebSocket object and I cannot close it when the service gets destroyed:
disposables += webSocketService.observeOnConnectionEvent().subscribe { when (it) { is WebSocket.Event.OnConnectionOpened<*> -> { Log.i(TAG, "Web socket opened") webSocket = it.webSocket as WebSocket } is WebSocket.Event.OnConnectionClosing -> Log.i(TAG, "Web socket closing") is WebSocket.Event.OnConnectionClosed -> Log.i(TAG, "Web socket closed") is WebSocket.Event.OnConnectionFailed -> Log.e(TAG, "Web socket failed", it.throwable) is WebSocket.Event.OnMessageReceived -> Log.i(TAG, "Web socket message received $it.message") } }
FAILURE: Build failed with an exception.
com.android.build.api.transform.TransformException: java.lang.RuntimeException: java.lang.RuntimeException: Unable to pre-dex 'C:\Users\mike.gradle\caches\modules-2\files-2.1\com.github.tinder.scarlet\scarlet-core\0.1.4\b5366480d19f19212823e2f7a42f0664bc878daa\scarlet-core-0.1.4.jar' to 'D:\AndroidStudioProjects\android-juli\app\build\intermediates\transforms\dex\free\debug\folders\1000\10\scarlet-core-0.1.4_d0e9a0649fe7c644f8281caa71c5828931a34219'
We can ideally replace the following line
val expectedString = "{\"name\":\"value\"}"
with this one:
val expectedString = """{"name":"value"}"""
by leveraging raw strings provided by Kotlin.
Hi,
I'm trying to add the library trough gradle but I get: Failed to resolve: com.tinder.scarlet:scarlet:0.1.0
Can't find the library using: https://search.maven.org/#search%7Cga%7C1%7Cscarlet
Is there any plan to support phoenix framework for channels?
Is there a reason why it's set to 19?
In retrofit, we can embed @HeaderMap and @fieldmap in case of POST or @QueryMap in case of GET. This way we can embed an authorized token in the header and pass by parameters either in GET or as a form in POST. My question, how can we achieve a similar thing in scarlet to pass by authorization token to the server?
v. 0.2.1-alpha4
There is a basic entity of the socket response that differs in the content of the data field and the value of the endpoint field. For example. First is a payment structure:
{
"endpoint": "updates.payments",
"data": {
"payments": [
{
"payment_status": "success",
//...other fields...
"currency": {
"decimal_places": 2,
"currency_code": "GBP",
"currency_name": "UK Sterling"
}
}
]
}
}
And message structure:
{
"endpoint": "updates.messages",
"data": {
"messages": [
{
"message_status": "send_success",
//other fields
"text":"blah blag blah"
}
]
}
}
In SocketInterface i have next code:
interface SocketInterface {
@Receive
fun subscribeToMessages(): Flowable<PushMessage<MessagesData>>
@Receive
fun subscribeToPayments(): Flowable<PushMessage<PaymentData>>
}
And PushMessage model see this:
data class PushMessage<T>(
@SerializedName("endpoint") val method: String,
@SerializedName("data") val data: T
)
data class MessagesData(
@SerializedName("messages") val messages: List<ChatMessage>
)
data class PaymentData(
@SerializedName("payments") val payments: List<BaseTransactionNet>
)
By subscribing to both events, I receive two events if I receive one of them.
Is there any way to fix it?
My build.gradle top lvl:
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
build.gradle app lvl:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.ng.exttest3"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.github.tinder.scarlet:scarlet:0.2.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
it looks absolutely standard, but many modules not load. I see only scarlet, carlet-core, scarlet-core-internal, scarlet-message-adapter, scarlet-stream-adapter. In older dependency versions (kotlin, gradle plugin and other) i catch other error - #50
And please, move it to maven central or other great place for libraries
Hi, thanks for the library. I have question regarding to how did you handle such state transition:
App Opened -> App Sent to background -> App came to foreground (all in a second)
Is it:
connecting
-> disconnecting
-> connecting
? Do you queue states or just immediately transition to next state by cancelling, or restarting okHttp calls?
I'm getting the following error:
IllegalArgumentException: Method return type must not include a type variable or wildcard: io.reactivex.Flowable<com.tinder.scarlet.WebSocket$Event$OnConnectionOpened<?>>
at
@Receive fun observeOnConnectionOpenedEvent(): Flowable<WebSocket.Event.OnConnectionOpened<*>>
fun <T> create(service: Class<T>): T { val clientBuilder = OkHttpClient.Builder() clientBuilder.addInterceptor(AuthInterceptor() val scarlet = Scarlet.Builder() .webSocketFactory(clientBuilder.build().newWebSocketFactory(ApiEndPoint.WEBSOCKET)) .addMessageAdapterFactory(GsonMessageAdapter.Factory()) .addStreamAdapterFactory(RxJava2StreamAdapterFactory()) .build() return scarlet.create(service) }
val websocketApi = BaseScarletBuilder.create(WebsocketApi::class.java)
Is this the way we are suppose to use the lib?
After adding the library, all android extension methods are broken. And i see demo in 0.2.x version - why you not use kotlin-android-extensions?
Looks like you know something...
com.android.builder.multidex.D8MainDexList$MainDexListException:
com.android.tools.r8.errors.CompilationError:
Program type already present: com.tinder.scarlet.lifecycle.android.BuildConfig
Hello!
I'm trying to add this dependency:
Gradle Kotlin DSL
implementation("com.github.tinder.scarlet:scarlet-websocket-okhttp:0.2.4")
But all versions > 1.7.0 (I tried 1.8.0 ... 2.4.0
) are not available.
if implement lifecycle-android , other packages like all the message-adapter,protocols will be added in the project.
I've got multiple methods annotated with @ Receive inside Scarlet's interface. The problem is that, for example, when a Route is sent on the socket from the server, all 4 observable callbacks are being called, instead of only the observeRoute() one. What can be causing this and why? I mean, I can get why the observeRoute() and observeOnConnectionEvent() callbacks are called; but why are the other 2 called which have nothing to do with the connection or the Route model?
@Receive
fun observeOnConnectionEvent(): Flowable<WebSocket.Event>
@Receive
fun observeAlerts(): Flowable<Alert>
@Receive
fun observeRoute(): Flowable<Route>
@Receive
fun observeVehicle(): Flowable<Vehicle>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.