This fixes a segfault in the reply handling code, where the destructor
of a `py::function` wasn't necessarily happening with the GIL held,
which could make Python segfault.
The solution that was here to address this didn't work because it was
relying on std::optionals, but it is possible (and apparently sometimes
happens) that the std::function this lambda gets stuffed into gets moved
(or maybe copied?), which then results in *two* lambda destructions: we
were correctly dealing with the one that eventually gets called by
clearing things properly when it gets called, but the temporary
destructor also fires, and that is the one that broke.
This changes it to instead leak bare pointers into the lambda and then
recapture them inside when we get called; since we are guaranteed to be
called exactly once, this recaptures them without losing them but
doesn't incur destruction of a py::function deep in oxenmq (outside of
GIL scope).
The default references, which breaks because Message gets reused, so
storing `.conn` gives you something that changes the next time a worker
gets a message.
Avoids a utf-8 decoding error when accepting a connection with an allow
function by properly wrapping the function in a version that passes
pubkey as a `bytes`.
- timeout in the syncronous connect_remote wasn't being passed through
- callback and syncronous connect_remote had some deviation in args;
unified them to both take keyword-only timeout and
ephemeral_routing_id, and to take timeout as a timedelta with a
default (rather than an optional in the callback-based one).
- removed unused "noopt". I forget what it was for, but it didn't end
up being used.
- make extract data parts always flatten to arbitrary depth. We were
only flattening once (and only sometimes), but arbitrary flattening is
nicer (as long as we don't ultimately encouter anything that isn't
str/bytes).
- fix Message.data()/.dataview() pre-loading nulls into the list. The
py::list constructor argument here is pre-fill, not a reservation.
- fix add_command: it was broken because when the wrapped callback gets
invoked it tries casting the Message via copying, but that breaks
(Message isn't copyable). Fix it by adding a wrapper that does a
referencing cast to a Python object.
- Add missing docs for add_command
- Doc typo fixes
- Remove OxenMQ default and loglevel constructors, and make the
remaining constructor take everything by keyword arguments. (Default
constructor remains equivalent, and the log-level constructor now has
to have the log level named).
- Fix OxenMQ keyword constructor: invoking it was failing because the
annotation default on sn_lookup wasn't properly castable to the
required types (it should be py::none() rather than nullptr). Also
fix the defaults for pubkey/privkey to be py::bytes() (the empty
string worked fine, but using bytes makes it show up as bytes defaults
in the generated signature doc string).
- Further document connect_inproc with a description of why you might
want it.
- Fix send not actually including the message data parts
- Work around segfault in the reply callback: because we have lambdas
with python object captures, we'd segfault in the proxy thread when it
frees them after calling them because that freeing invokes python
destructor but it doesn't hold the gil. Fixed by making the lambda
consume its own callbacks (which is fine because oxenmq will invoke
the callback exactly once).
- Fix request_future invocation which raised an error on invocation:
straight lambdas aren't castable to python objects, so stuff the
lambda inside std::functions, which are.
setup.py works fine, and we don't need two separate build systems.
Remove the submodules as well because we aren't using them and don't
need them; you should install pybind11 and oxenmq outside this project.