Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for external event driven API #83

Open
njh opened this issue Sep 14, 2016 · 11 comments
Open

Add support for external event driven API #83

njh opened this issue Sep 14, 2016 · 11 comments

Comments

@njh njh changed the title Add support for Observable Add support for external event driven API Sep 14, 2016
@skandragon
Copy link

+1

In my app, I need to do the following:

  1. Periodically probe physical device endpoints for manual changes, and send MQTT messages.
  2. Periodically scan for new devices, and send MQTT messages about them, as well as begin tracking them.
  3. Process incoming MQTT state change requests and send them to physical devices

From what I can tell, I cannot do this using this mqtt library at this time. If I can, are there async examples?

@njh
Copy link
Owner Author

njh commented Nov 29, 2016

When I was writing the MQTT ruby gem I was unsure about the best approach to callbacks when messages were received; particularly when interacting with other code and libraries. So I opted to keep it synchronous/blocking to keep things simple.

At the time the premier async library for Ruby was EventMachine, so I wrote a gem for that:
https://github.com/njh/ruby-em-mqtt

It still uses message parsing/generation from this gem. But I have found EventMachine somewhat frustrating to work with - particularly when there are errors or things go wrong.

If there are better/different approaches in Ruby now, please let me know...

@skandragon
Copy link

My current project just uses threads, which since the C ruby version has a global lock, is more of a way to allow cleaner code. If I put this under JRuby, I'd have to implement some simple locking where the two meet: my data structures.

I wasn't sure how safe it was to use a single shared MQTT client, so I went with two, one for the thing that monitors my light bulb's status (TP-Link LED dimmable bulbs, some RGB ones, and some AC switches) and another which watches for MQTT updates and sends commands to the bulbs.

"it works" so far :)

@andreimaxim
Copy link

andreimaxim commented Dec 20, 2016

Might I suggest the Observable module from the concurrent-ruby gem?

The concurrent-ruby gem is mature enough to be a requirement for Rails 5.0 (especially for thread safety features as thread_safe gem was moved into this one) and the Observable module is thread safe, as opposed to the standard library version. It could be interesting to do even more, like use actors (I'm currently working on a fork of this gem that does that and also automatically handles any connection issues but it's pre-pre-pre-alpha quality).

@njh
Copy link
Owner Author

njh commented Dec 20, 2016

Good suggestion. I have not looked at concurrent-ruby. Thanks @andreimaxim.

@skandragon
Copy link

I use RxScala at work -- Observables are handy.

@njh
Copy link
Owner Author

njh commented Jan 13, 2017

Or could go the libuv route:

Which provides asynchronous callbacks, promises and all kinds of other fancy stuff, similar to node.js.

@jsaak
Copy link

jsaak commented Feb 25, 2021

Since in ruby 3.0 we have non-blocking fibers with a scheduler interface, it will be relatively easy to use that in this gem. I will do the changes for myself, to see how it works. Are you interested to merge it when i am done, or shall i fork?

@njh
Copy link
Owner Author

njh commented Mar 4, 2021

@jsaak yes, I would be very interested. Do you think it can be done without changing the API?
It may make sense to fork, it it requires having code for both pre-ruby 3.0 and post-ruby 3.0.

I really need to get some PRs merged and a release made.
After that I think the priority is the separate out the packet parsing/generating code, so that core can be used by other gems.

@jsaak
Copy link

jsaak commented Mar 4, 2021

Well, i decided to rewrite it from scratch, it is rewritten in different style which suits me better. Still maybe we can work something out. Have a look: https://github.com/jsaak/ruby-mqtt3 (it is a work in progress: QoS 1 and reconnect is implemented, today i plan to do QoS2)

@jsaak
Copy link

jsaak commented Mar 4, 2021

I have copy-pasted some functions from you, I hope you do not mind.

EDIT: i figured it out, so you can pass a string in any encoding, and it converts it to utf-8

there is one thing I do not understand: in the function encode_string you do:

def encode_string(str)
  str = str.to_s.encode('UTF-8')

  # Force to binary, when assembling the packet
  str.force_encoding('ASCII-8BIT')
  encode_short(str.bytesize) + str
end

https://github.com/njh/ruby-mqtt/blob/master/lib/mqtt/packet.rb#L248

What is the reason for this? i think this would be enough:

encode_short(str.bytesize) + str

or maybe

encode_short(str.bytesize) + str.force_encoding('ASCII-8BIT')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants