Commit graph

82 commits

Author SHA1 Message Date
Yian Chen
78dd54e641 address flake8 format check 2024-04-11 19:01:59 -07:00
Lasse Blaauwbroek
e13a0c9254
Experiment: Wrap all capnp code in a context-manager to avoid segfaults (#317)
* Experiment: Wrap all capnp code in a context-manager

* Fix segfault in on_disconnect
2023-10-03 09:04:51 -07:00
Lasse Blaauwbroek
0d160fc81d Fix forgotten async server method 2023-06-09 22:04:39 +02:00
Lasse Blaauwbroek
84d0f365ad Fix formatting 2023-06-08 08:18:50 +02:00
Lasse Blaauwbroek
770be41b6d Bugfix: Attach server to on_disconnect to prevent early closing 2023-06-08 08:11:23 +02:00
Lasse Blaauwbroek
4b5c4211f1 Force server methods to be async and client calls to use await 2023-06-08 03:56:57 +02:00
Lasse Blaauwbroek
854d910bee Make tests run faster by reducing timeouts 2023-06-08 02:31:06 +02:00
Lasse Blaauwbroek
b29f18ed64 Cleanup 2023-06-08 02:29:24 +02:00
Lasse Blaauwbroek
97bdeaea12 Disable option to run capnp without asyncio 2023-06-08 02:27:38 +02:00
Lasse Blaauwbroek
6e011cfe78 Get rid of capnp timer functionality.
The asyncio timer should now be used
2023-06-07 20:55:43 +02:00
Lasse Blaauwbroek
8feb377217 Allow reading and writing messages from sockets in async mode 2023-06-07 11:24:43 -07:00
Lasse Blaauwbroek
d53aa24733 Allow async capability implementation methods to return a tuple 2023-06-07 10:51:53 -07:00
Lasse Blaauwbroek
c037342615 Allow capability implementation methods to be async 2023-06-07 10:51:53 -07:00
Lasse Blaauwbroek
d32854eb00
Integrate the KJ event loop into Python's asyncio event loop (#310)
* Integrate the KJ event loop into Python's asyncio event loop

Fix #256

This PR attempts to remove the slow and expensive polling behavior for asyncio
in favor of proper linking of the KJ event loop to the asyncio event loop.

* Don't memcopy buffer

* Improve promise cancellation and prepare for timer implementation

* Add attribution for asyncProvider.cpp

* Implement timeout

* Cleanup

* First round of simplifications

* Add more a_wait functions and a shutdown function

* Fix edge-cases with loop shutdown

* Clean up calculator examples

* Cleanup

* Cleanup

* Reformat

* Fix warnings

* Reformat again

* Compatibility with macos

* Inline the asyncio loop in some places where this is feasible

* Add todo

* Fix

* Remove synchronous wait

* Wrap fd listening callbacks in a class

* Remove poll_forever

* Remove the thread-local/thread-global optimization

This will not matter much soon anyway, and simplifies things

* Share promise code by using fused types

* Improve refcounting of python objects in promises

We replace many instances of PyObject* by Own<PyRefCounter> for more automatic
reference management.

* Code wrapPyFunc in a similar way to wrapPyFuncNoArg

* Refactor capabilityHelper, fix several memory bugs for promises and add __await__

* Improve promise ownership, reduce memory leaks

Promise wrappers now hold a Own<Promise<Own<PyRefCounter>>> object. This might
seem like excessive nesting of objects (which to some degree it is, but with
good reason):
- The outer Own is needed because Cython cannot allocate objects without a
  nullary constructor on the stack (Promise doesn't have a nullary constructor).
  Additionally, I believe it would be difficult or impossible to detect when a
  promise is cancelled/moved if we use a bare Promise.
- Every promise returns a Owned PyRefCounter. PyRefCounter makes sure that a
  reference to the returned object keeps existing until the promise is fulfilled
  or cancelled. Previously, this was attempted using attach, which is redundant
  and makes reasoning about PyINCREF and PyDECREF very difficult.
- Because a promise holds a Own<Promise<...>>, when we perform any kind of
  action on that promise (a_wait, then, ...), we have to explicitly move() the
  ownership around. This will leave the original promise with a NULL-pointer,
  which we can easily detect as a cancelled promise.

Promises now only hold references to their 'parents' when strictly needed. This
should reduce memory pressure.

* Simplify and test the promise joining functionality

* Attach forgotten parent

* Catch exceptions in add_reader and friends

* Further cleanup of memory leaks

* Get rid of a_wait() in examples

* Cancel all fd read operations when the python asyncio loop is closed

* Formatting

* Remove support for capnp < 7000

* Bring asyncProvider.cpp more in line with upstream async-io-unix.c++

It was originally copied from the nodejs implementation, which in turn copied
from async-io-unix.c++. But that copy is pretty old.

* Fix a bug that caused file descriptors to never be closed

* Implement AsyncIoStream based on Python transports and protocols

* Get rid of asyncProvider

All asyncio now goes through _AsyncIoStream

* Formatting

* Add __dict__ to  PyAsyncIoStreamProtocol for python 3.7

* Reintroduce strange ipv4/ipv6 selection code to make ci happy

* Extra pause_reading()

* Work around more python bugs

* Be careful to only close transport when this is still possible

* Move pause_reading() workaround
2023-06-06 11:08:15 -07:00
Jacob Alexander
5061cdd1ee Fix black formatting 2023-03-12 11:33:41 -07:00
Madhava Jay
ea70dac5cb Fixed black issues
- Disabled flake8 checks from blocking CI
- Added python 3.10 to packaging and manylinux
2022-04-06 13:32:52 +10:00
Jacob Alexander
6e7fffd7de
Applying black formatting
- Fixing flake8 configuration to agree with black
- Adding black validation check to github actions
2021-10-01 11:12:21 -07:00
Jacob Alexander
a4ef16e831
Fixing flake8 linting errors
- Enabling builds to fail on simple lint failures now
2020-11-20 23:38:13 -08:00
Jacob Alexander
3de13c3718
Updating simple example servers to not use run_forever (can't Ctrl+c)
- Adding xfail to simple servers as they tend to not like certain
  versions of python when called repeated for testing
2020-11-20 00:17:52 -08:00
Jacob Alexander
5e8ccba536
Updating docs for v1.0.0b2
- Full cleanup of all the docs
- General sphinx housekeeping
- Updated all the old/bad links
- More reliable tests
- Updated Changelog
- Removed dead/deprecated code
- Added documentation generation test
2020-06-14 17:05:45 -07:00
Jacob Alexander
6532ca571d Adding SSL version of the calculator example
- Used to test asyncio SSL on Windows mainly
- Skipping asyncio thread tests on Windows (due to getTimer wrapper bug
  on Windows)
2020-06-10 14:33:45 -07:00
Jacob Alexander
745887cee0 Typo from earlier commit (capnproto-0.8.0 update) 2020-06-09 00:27:43 -07:00
Jacob Alexander
49fd4854d8 Minor code cleanup
- Reducing linter errors
- Removing old Python 2-only code (__future__ print)
2020-06-08 23:51:07 -07:00
Jacob Alexander
255119b838 Updating to capnproto v0.8.0
- Includes some test stabilization
- Fixes manylinux2010 build issues (linker flag order due to old gcc)
- More rigorous python setup.py clean
- Requires capnproto v0.8.0 or greater
- Including system libcapnp include path for import (e.g. import
  stream_capnp)
- Bundle libcapnp .capnp files when not using system libcapnp
- Removing more distutils usage. Now using pkg-config to determine the
  system version of libcapnp (mainly for Linux, but should work on macOS
  with brew)
- Removed dead code

Resolves issues #215 #216 #217
Lots of fixes for Issue #218 (all sorts of retry methods needed for
GitHub Actions)
2020-06-08 11:49:17 -07:00
Jacob Alexander
dd3551f978
Adding poll_once() to TwoPartyServer API
- poll_forever() doesn't allow for checking socket connection to client
  * Need to check for client, if eof received then we can close the
  connection and cleanup pycapnp cpu resources (async tasks)
- Updated async examples to fix bugs
  * Add checking code for socket connection to the client and gracefully
  cleanup resources once the client socket connection closes
  * Instanciate a new TwoPartyServer per connection (allows for multiple
  connections)
- Should resolve Issue #198
2020-01-08 18:06:26 -08:00
Jacob Alexander
fc75e4083d
Fixing remaining flake8 lint warnings 2019-12-11 22:44:44 -08:00
Jacob Alexander
362cce345b Fixing Windows tests
- Adding import path filter to exclude non-directories
  Otherwise kj will through exceptions
- Skipped AF_UNIX socket test
- Use default socket configuration when it doesn't matter the type of
socket used
- Open files with utf8 encoding (needed for text validation)
- Explictly call python executable when running external scripts
- Fix path creation to always use os.path.join
- Added timeout to client wait in some tests

- Some broken tests still remain (most likely asyncio related)
2019-10-19 00:26:55 -07:00
Jacob Alexander
7789ebbf96
Fixing flake8 linting errors 2019-10-15 01:08:11 -07:00
Jacob Alexander
940ab9916d
Adding reconnecting async ssl example
- async_reconnecting_ssl_client.py will automatically close and
reconnect to a server when it becomes available (rather than hanging or
dying when the server disappears)
2019-10-05 14:50:56 -07:00
Jacob Alexander
78776de647
Adding examples as pytest tests
- This way they will be included in CI checks
- Decreased the delay time in the thread-like examples to speed up tests
(probably could decrease the time some more)
- Added an async version of the calculator test
- Forcing python3 support for example scripts
2019-09-27 14:40:54 -07:00
Jacob Alexander
b3021e4f6b
Fixing flake8 warnings and errors
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude benchmark

Excluding the benchmark directory (due to protobuf generated files)
Also removing some Python2 specific code
2019-09-27 00:15:13 -07:00
Jacob Alexander
1a127bec6f
Adding pure python SSL test using asyncio
- Uses thread.capnp
- Follows same format as thread_client.py/thread_server.py and
async_client.py/async_server.py
- Including a basic self signed certificate for testing convenience
- Python 3.7 has a bug cleaning up SSL when using asyncio.run
  https://bugs.python.org/issue36709
  Have a slightly more verbose workaround to do proper cleanup
2019-09-26 21:42:54 -07:00
Jacob Alexander
8915ef79f1
TwoWayPipe and basic asyncio support
Note: I've tried not to break any behaviour of the previously working APIs

Python API Changes / Additions
- capnp/lib/capnp.pyx
  * class _RemotePromise
    + [Added] cpdef _wait(self)
      = Exception raising code that used to be inside of wait(self)
    + [Modified] def wait(self)
      = Same functionality as before
    + [Added] async def a_wait(self)
      = Cannot use await as that's a reserved keyword
      = Uses pollRemote and asyncio.sleep(0) to make call asynchronous
  * class _TwoPartyVatNetwork
    + [Added] cdef _init_pipe(self, _TwoWayPipe pipe, Side side,
    schema_cpp.ReaderOptions opts)
      = Instanciates a TwoPartyVatNetwork using a TwoWayPipe (instead of
      using a file handle or connection as before)
  * class TwoPartyClient
    + [Modified] def __init__(self, socket=None, restorer=None,
    traversal_limit_in_words=None, nesting_limit=None)
      = Changes the socket parameter to be optional
      = If socket is not specified, default to using a TwoWayPipe
    + [Added] async def read(self, bufsize)
      = awaitable function that blocks until data has been read
      = bufsize defines the maximum amount of data to be read back
        (e.g. 4096 bytes)
      = Reads data from TwoWayPipe
    + [Added] def write(self, data)
      = Write data to TwoWayPipe
      = Not awaitable as the write interface of the TwoWayPipe doesn't
      have poll functionality
  * class TwoPartyServer
    + [Modified] def __init__(self, socket=None, restorer=None,
    server_socket=None, bootstrap=None, traversal_limit_in_words=None,
    nesting_limit=None)
      = Changes the socket parameter to be optional
      = If socket is not specified, default to using a TwoWayPipe
      = Simplified code by removing an else (self._connect)
    + [Added] async def read(self, bufsize)
      = awaitable function that blocks until data has been read
      = bufsize defines the maximum amount of data to be read back
        (e.g. 4096 bytes)
      = Reads data from TwoWayPipe
    + [Added] def write(self, data)
      = Write data to TwoWayPipe
      = Not awaitable as the write interface of the TwoWayPipe doesn't
      have poll functionality
    + [Added] async def poll_forever(self)
      = asyncio equivalent of run_forever()
  * class _TwoWayPipe
    + Wrapper class for TwoWayPipe

Other Additions
- capnp/helpers/asyncHelper.h
  * pollWaitScope
    + Pumps the kj event handler
    + Used for the TwoWayServer
  * pollRemote
    + Polls a remote promise
    + i.e. a capnp RPC call
- capnp/helpers/asyncIoHelper.h
  * AsyncIoStreamReadHelper
    + I wasn't able to figure out Promise[size_t] using Cython so this was
    the next best thing I could think of doing
    + Was needed to handle read polling from a read promise
      = Polling is used for asyncio as kj waits need a wrapper to be
      compatible
- capnp/lib/capnp.pyx
  * makeTwoWayPipe
    + Wrapper for kj newTwoWayPipe function
  * poll_once
    + Single pump of the kj event handler (used with pollWaitScope)

TwoWayClient Usage - TwoWayPipe
- See examples/async_client.py

TwoWayServer Usage - TwoWayPipe
- See examples/async_server.py

capnp/helpers/asyncIoHelper.h

Misc Changes
- Fixed thread_server.py and thread_client.py to use bootstrap instead
of ez_restore
- async_client.py and async_server.py examples
  * Uses the same thread.capnp as thread_client.py and thread_server.py
  * They are compatible, so you can mix and match client and server for
  compatibility testing
  * async_client.py and async_server.py require <address>:<port>
  formatting (unlike autodetection from thread_client.py and
  thread_server.py)
2019-09-26 21:42:48 -07:00
Jason Paryani
e00bff6ef8 Fix problems with TwoPartyServer
Fixes #61

It turns out I messed up the Server initialization code for the case
where a string is passed in as the address. The tests only cover the
cases where a raw socket is passed in. This will be rectified in a
following commit.
2015-04-13 14:14:40 -07:00
Jason Paryani
64e80e06bf Get code generator plugin to a decently working state.
Still a few outstanding performance issues, and imports inside .capnp
files may not be working
2014-10-19 20:06:00 -07:00
Jason Paryani
95e706f2f9 Add thread examples 2014-08-26 15:21:46 -07:00
Jason Paryani
b0af30ebe6 Fix up syntax a bit 2014-01-13 17:00:05 -08:00
Jason Paryani
0930a9fd1b Change calculator example to use new dict syntax for a typeless struct 2014-01-13 16:50:02 -08:00
Jason Paryani
f9bb12bff9 Update RPC with simpler methods for connecting 2013-12-12 11:55:50 -08:00
Jason Paryani
81388f82f6 Change rpc server example to use simple restore function 2013-12-11 22:48:59 -08:00
Jason Paryani
2f0f03d1a8 Add TCP_NODELAY 2013-12-11 22:25:43 -08:00
Jason Paryani
4d8a27844f Fix allowing RemotePromises to be returned directly 2013-12-11 11:24:27 -08:00
Jason Paryani
03bac73120 Fix examples formatting issues and make them pep8 compliant 2013-12-11 01:59:52 -08:00
Jason Paryani
117a3c7eac Add examples back in 2013-12-11 00:27:01 -08:00
Jason Paryani
db2247e883 Add calculator to tests 2013-12-11 00:15:08 -08:00
Jason Paryani
0e178de136 Fix segfault by making TwoPartyClient's members immortal 2013-12-10 23:29:21 -08:00
Jason Paryani
a17c76f593 Add server example 2013-12-10 23:05:57 -08:00
Jason Paryani
e92f7b56c6 Various fixups to the RPC api.
* change how restorer works
* fix join_promises
* add incref's all around to make sure we aren't freeing objects early
* make it so we return PyPromises everywhere and make chains collapsible
2013-12-10 22:57:21 -08:00
Jason Paryani
bba1918566 Add ez_restore function to Client. Also add c++.capnp and rpc.capnp 2013-12-09 21:30:27 -08:00
Jason Paryani
8cc214fb7b Add semi-functional rpc example 2013-12-09 19:49:48 -08:00