Source

crossroads / crossroads / message.py

# -*- coding: utf-8 -*-
'''Crossroads.IO messages.'''

from ctypes import sizeof, string_at, c_ubyte, byref, c_size_t, c_char, c_int

from stuf.base import norm
from stuf.six import PY3, tobytes, tounicode, u, b, isunicode

from . import lowest as xs
from .constants import MORE

SLOTS = 'msg rc more size last_rc'.split()


class Msg(object):

    def __init__(self):
        self.more = self.rc = self.msg = self.last_rc = None

    def __bytes__(self):
        if self.msg is None:
            return b('')
        return tobytes(string_at(byref(self.msg), self.size))

    def __unicode__(self):
        return u('') if self.msg is None else tounicode(norm(self.__bytes__()))

    def __len__(self):
        return self.size

    __str__ = __unicode__ if PY3 else __bytes__

    @property
    def array(self):
        return bytearray(self.__bytes__())


class RecvMsg(Msg):

    __slots__ = SLOTS

    def __init__(self, size, char=False):
        super(RecvMsg, self).__init__()
        self.msg = xs.array(c_char if char else c_ubyte, size)
        self.size = size


class SendMsg(Msg):

    __slots__ = SLOTS

    def __init__(self, size, source):
        super(SendMsg, self).__init__()
        if isinstance(source, Msg):
            self.msg = source = bytes(source)
        elif isunicode(source):
            self.msg = source = b(source)
        else:
            self.msg = source
        self.size = len(source) if size is None else size


class MsgXS(Msg):

    def close(self):
        self.rc = xs.msg_close(self.msg)


class RecvMsg32(MsgXS):

    __slots__ = SLOTS

    def __init__(self):
        super(RecvMsg32, self).__init__()
        self.msg = msg = xs.msg_t()
        self.rc = xs.msg_init(msg)

    @property
    def moremsg(self):
        more = c_int()
        more_size = c_size_t(sizeof(more))
        self.rc = xs.getmsgopt(self.msg, MORE, more, more_size)
        value = more.value
        del more_size, more
        return value


class SendMsg32(MsgXS):

    __slots__ = SLOTS

    def __init__(self, source):
        super(SendMsg32, self).__init__()
        if isinstance(source, Msg):
            self.msg = source.msg
        else:
            self.msg = xs.msg_t()
            source = b(source)
            length = len(source)
            self.rc = xs.msg_init_size(self.msg, length)
            xs.memmove(xs.msg_data(self.msg), source, length)