diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bus.py | 83 | ||||
-rw-r--r-- | src/native_bus.pyx | 160 |
2 files changed, 237 insertions, 6 deletions
@@ -57,7 +57,7 @@ class Bus: NOWAIT = 1 ''' - Function shall fail with errno set to `EAGAIN` + Function shall fail with `os.errno.EAGAIN` if the it would block and this flag is used ''' @@ -141,9 +141,10 @@ class Bus: ''' Broadcast a message a bus - @param message:str The message to write, may not be longer than 2047 bytes after UTF-8 encoding - @param flags:int `Bus.NOWAIT` if the function shall fail if there is another process attempting - to broadcast on the bus + @param message:str The message to write, may not be longer than 2047 bytes + after UTF-8 encoding + @param flags:int `Bus.NOWAIT` if the function shall fail with `os.errno.EAGAIN` + if there is another process attempting to broadcast on the bus ''' from native_bus import bus_write_wrapped if bus_write_wrapped(self.bus, message, flags) == -1: @@ -178,6 +179,80 @@ class Bus: raise self.__oserror() + def poll_start(self, flags : int = 0): + ''' + Announce that the thread is listening on the bus. + This is required so the will does not miss any + messages due to race conditions. Additionally, + not calling this function will cause the bus the + misbehave, is `Bus.poll` is written to expect + this function to have been called. + + @param flags:int `Bus.NOWAIT` if the bus should fail with `os.errno.EAGAIN` + if there isn't already a message available on the bus when + `Bus.poll` is called + ''' + from native_bus import bus_poll_start_wrapped + if bus_poll_start_wrapped(self.bus, flags) == -1: + raise self.__oserror() + + + def poll_stop(self): + ''' + Announce that the thread has stopped listening on the bus. + This is required so that the thread does not cause others + to wait indefinitely. + ''' + from native_bus import bus_poll_stop_wrapped + if bus_poll_stop_wrapped(self.bus) == -1: + raise self.__oserror() + + + def poll(self) -> str: + ''' + Wait for a message to be broadcasted on the bus. + The caller should make a copy of the received message, + without freeing the original copy, and parse it in a + separate thread. When the new thread has started be + started, the caller of this function should then + either call `Bus.poll` again or `Bus.poll_stop`. + + @return :str The received message + ''' + from native_bus import bus_poll_wrapped + if bus_poll_wrapped(self.bus) == None: + raise self.__oserror() + + + def chown(self, owner : int, group : int): + ''' + Change the ownership of a bus + + `os.stat` can be used of the bus's associated file to get the bus's ownership + + @param owner:int The user ID of the bus's new owner + @param group:int The group ID of the bus's new group + ''' + from native_bus import bus_chown_wrapped + if bus_chown_wrapped(self.pathname, owner, group) == -1: + raise self.__oserror() + + + def chmod(self, mode : int): + ''' + Change the permissions for a bus + + `os.stat` can be used of the bus's associated file to get the bus's permissions + + @param mode:int The permissions of the bus, any permission for a user implies + full permissions for that user, except only the owner may + edit the bus's associated file + ''' + from native_bus import bus_chmod_wrapped + if bus_chmod_wrapped(self.pathname, mode) == -1: + raise self.__oserror() + + def __oserror(self): ''' Create an OSError diff --git a/src/native_bus.pyx b/src/native_bus.pyx index fdcf341..c3c4039 100644 --- a/src/native_bus.pyx +++ b/src/native_bus.pyx @@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE. cimport cython from libc.stdlib cimport malloc, free +from posix.types cimport uid_t, gid_t, mode_t cdef extern int bus_create(const char *, int, char **) @@ -98,6 +99,71 @@ Listen (in a loop, forever) for new message on a bus @return 0 on success, -1 on error ''' +cdef extern int bus_poll_start(long, int) +''' +Announce that the thread is listening on the bus. +This is required so the will does not miss any +messages due to race conditions. Additionally, +not calling this function will cause the bus the +misbehave, is `bus_poll` is written to expect +this function to have been called. + +@param bus Bus information +@param flags `BUS_NOWAIT` if the bus should fail and set `errno` to + `EAGAIN` if there isn't already a message available on + the bus when `bus_poll` is called +@return 0 on success, -1 on error +''' + +cdef extern int bus_poll_stop(long) +''' +Announce that the thread has stopped listening on the bus. +This is required so that the thread does not cause others +to wait indefinitely. + +@param bus Bus information +@return 0 on success, -1 on error +''' + +cdef extern const char *bus_poll(long) +''' +Wait for a message to be broadcasted on the bus. +The caller should make a copy of the received message, +without freeing the original copy, and parse it in a +separate thread. When the new thread has started be +started, the caller of this function should then +either call `bus_poll` again or `bus_poll_stop`. + +@param bus Bus information +@return The received message, `NULL` on error +''' + +cdef extern int bus_chown(const char *, uid_t, gid_t) +''' +Change the ownership of a bus + +`stat(2)` can be used of the bus's associated file to get the bus's ownership + +@param file The pathname of the bus +@param owner The user ID of the bus's new owner +@param group The group ID of the bus's new group +@return 0 on success, -1 on error +''' + +cdef extern int bus_chmod(const char *, mode_t) +''' +Change the permissions for a bus + +`stat(2)` can be used of the bus's associated file to get the bus's permissions + +@param file The pathname of the bus +@param mode The permissions of the bus, any permission for a user implies + full permissions for that user, except only the owner may + edit the bus's associated file +@return 0 on success, -1 on error +''' + + def bus_allocate() -> int: ''' @@ -193,8 +259,8 @@ def bus_write_wrapped(bus : int, message : str, flags : int) -> int: @param bus Bus information @param message The message to write, may not be longer than `BUS_MEMORY_SIZE` including the NUL-termination - @param flags `BUS_NOWAIT` fail if other process is attempting - to write + @param flags `BUS_NOWAIT` fail with errno set to `os.errno.EAGAIN` + if other process is attempting to write @return 0 on success, -1 on error ''' cdef const char* cmessage @@ -234,3 +300,93 @@ def bus_read_wrapped(bus : int, callback : callable, user_data) -> int: user = (callback, user_data) return bus_read(<long>bus, <int (*)(const char *, void *)>&bus_callback_wrapper, <void *>user) + +def bus_poll_start_wrapped(bus : int, flags : int) -> int: + ''' + Announce that the thread is listening on the bus. + This is required so the will does not miss any + messages due to race conditions. Additionally, + not calling this function will cause the bus the + misbehave, is `bus_poll_wrapped` is written to expect + this function to have been called. + + @param bus Bus information + @param flags `BUS_NOWAIT` if the bus should fail and set `errno` to + `os.errno.EAGAIN` if there isn't already a message + available on + the bus when `bus_poll` is called + @return 0 on success, -1 on error + ''' + return bus_poll_start(<long>bus, <int>flags) + + +def bus_poll_stop_wrapped(bus : int) -> int: + ''' + Announce that the thread has stopped listening on the bus. + This is required so that the thread does not cause others + to wait indefinitely. + + @param bus Bus information + @return 0 on success, -1 on error + ''' + return bus_poll_stop(<long>bus) + + +def bus_poll_wrapped(bus : int) -> str: + ''' + Wait for a message to be broadcasted on the bus. + The caller should make a copy of the received message, + without freeing the original copy, and parse it in a + separate thread. When the new thread has started be + started, the caller of this function should then + either call `bus_poll_wrapped` again or + `bus_poll_stop_wrapped`. + + @param bus Bus information + @return The received message, `None` on error + ''' + cdef const char* msg + cdef bytes bs + msg = bus_poll(<long>bus) + if msg is NULL: + return None + bs = msg + return bs.decode('utf-8', 'strict') + + +def bus_chown_wrapped(file : str, owner : int, group : int) -> int: + ''' + Change the ownership of a bus + + `os.stat` can be used of the bus's associated file to get the bus's ownership + + @param file The pathname of the bus + @param owner The user ID of the bus's new owner + @param group The group ID of the bus's new group + @return 0 on success, -1 on error + ''' + cdef const char* cfile + cdef bytes bs + bs = file.encode('utf-8') + bytes([0]) + cfile = bs + return bus_chown(cfile, <uid_t>owner, <gid_t>group) + + +def bus_chmod_wrapped(file : str, mode : int) -> int: + ''' + Change the permissions for a bus + + `os.stat` can be used of the bus's associated file to get the bus's permissions + + @param file The pathname of the bus + @param mode The permissions of the bus, any permission for a user implies + full permissions for that user, except only the owner may + edit the bus's associated file + @return 0 on success, -1 on error + ''' + cdef const char* cfile + cdef bytes bs + bs = file.encode('utf-8') + bytes([0]) + cfile = bs + return bus_chmod(cfile, <mode_t>mode) + |