Conn: support subscribing to particular message IDs#43
Merged
saml-dev merged 16 commits intosaml-dev:mainfrom Dec 16, 2025
Merged
Conn: support subscribing to particular message IDs#43saml-dev merged 16 commits intosaml-dev:mainfrom
Conn: support subscribing to particular message IDs#43saml-dev merged 16 commits intosaml-dev:mainfrom
Conversation
saml-dev
approved these changes
Dec 10, 2025
Contributor
Author
👍 I'll try to get to it this weekend. |
Instead of shoving incoming messages into a channel, pass them to a callback of type `Subscriber`. Have `App` deal with the channel on its side (for now).
It will be easier to route messages to the correct subscriber, and prevent subscribers from interfering with each other, if subscribing at the `Conn` level is done by message ID. Add a mechanism for doing so. For now, messages are also passed to a `defaultSubscriber`. That will soon go away.
The subscriber is invoked every time a message arrives with the message ID corresponding to the subscription.
The old code wrote incoming messages to a channel, and then (in a separate goroutine) read and processed the messages from the channel. Note that the second goroutine created yet another goroutine for processing each message. Instead, write a `Subscriber` that processes the messages directly (while continuing to create a goroutine for each message). Pass this subscriber to `Conn.ListenWebsocket()` as the default subscriber. In future commits, we will add more specific subscribers for each type of message.
Add helper methods to add single listeners.
The thing that really has to be done specially for new event types is to subscribe to them. It is possible to append to a nil list, so that can be done in shared code after the `if`.
Extract method `EventListener.maybeCall()` from `App.callEventListeners()`.
Pick the event type out of the message in the caller, and pass it into `App.callEventListeners()`. This will soon enable a simplification.
It is OK to append to a nil slice.
Use `Conn`'s subscription feature to register a listener specific to each type of event that we are watching. This allows some logic to be removed from the default subscriber, because when the even arrives, we know what event type it is for based on its message ID.
Extract method `EntityListener.maybeCall()` from `App.callEntityListeners()`.
Use `Conn`'s subscription feature to register a listener specific to state changed events. This means that we can change the default subscriber to a `NoopSubscriber`.
We don't use it anymore.
Now that the method handles incoming messages internally, all that its caller really has to know is that it is a method that has to be called to manage the connection.
7742a1c to
7815d6b
Compare
Contributor
Author
|
I just rebased this branch onto the current |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: this branch builds on top of #42, so it includes those commits, too.
Home Assistant subscriptions are based on message IDs. To subscribe to something, you send an outgoing message to HA asking to subscribe. This message, like all requests, has a unique message ID. When HA sends events related to that subscription, the event messages that it sends back to you contain the same message ID. This allows the incoming events easily to be mapped back to the subscriber who requested them.
Add support for this mechanism at the
Connlevel:LockedConnthat allow subscribing or unsubscribing to a particular message ID. TheSubscriberis a callback function that is invoked whenever any message arrives with that message ID.Subscribe()method returns aSubscription, which includes a newly-allocated message ID. That ID can be used as the message ID for a message requesting a subscription from HA, thus causingConnto route those events automatically to the registeredSubscriber.Appto register its event listeners and entity listeners using this new mechanism. This means that much of the event routing is done byConn. The rest is done in the event listenerSubscriber.Conn.ListenWebsocket()does all of the message handling itself, the caller doesn't need to know what it does. So rename it toConn.Run().The usual caveat: I still can't run my own home setup on this branch, because it relies on other changes in #21 that haven't been re-rolled yet. So, while every commit compiles and example_live_test.go runs correctly at the tip of this branch, I can't do a lot more testing than that.
/cc @saml-dev