예제 #1
0
 def _transaction(self, bert_request):
     try:
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         if self.service.timeout is not None:
             sock.settimeout(self.service.timeout)
         sock.connect((self.service.host, self.service.port))
         if self.request.options is not None:
             if self.request.options.get('cache', None) is not None:
                 if self.request.options['cache'][0] == 'validation':
                     token = self.request.options['cache'][1]
                     info_bert = Encoder().encode(
                         (bert.Atom('info'), bert.Atom('cache'),
                          [bert.Atom('validation'),
                           bert.Atom(token)]))
                     info_header = struct.pack(">l", len(info_bert))
                     sock.sendall(info_header)
                     sock.sendall(info_bert)
         header = struct.pack(">l", len(bert_request))
         sock.sendall(header)
         sock.sendall(bert_request)
         lenheader = sock.recv(4)
         if lenheader is None:
             raise error.ProtocolError(error.ProtocolError.NO_HEADER)
         length = struct.unpack(">l", lenheader)[0]
         bert_response = sock.recv(length)
         if bert_response is None or len(bert_response) == 0:
             raise error.ProtocolError(error.ProtocolError.NO_DATA)
         sock.close()
         return bert_response
     except socket.timeout, e:
         raise error.ReadTimeoutError(
             'No response from %s:%s in %ss' %
             (self.service.host, self.service.port, self.service.timeout))
예제 #2
0
 def decode(self, bert_response):
     python_response = bert.decode(bert_response)
     if python_response[0] == bert.Atom('reply'):
         return python_response[1]
     elif python_response[0] == bert.Atom('noreply'):
         return None
     elif python_response[0] == bert.Atom('error'):
         return self._error(python_response[1])
     else:
         raise error.BERTRPCError('invalid response received from server')
예제 #3
0
 def _error(self, err):
     level, code, klass, message, backtrace = err
     exception_map = {
         bert.Atom('protocol'): error.ProtocolError,
         bert.Atom('server'): error.ServerError,
         bert.Atom('user'): error.UserError,
         bert.Atom('proxy'): error.ProxyError
     }
     exception = exception_map.get(level, None)
     if level is not None:
         raise exception([code, message], klass, backtrace)
     else:
         raise error.BERTRPCError('invalid error code received from server')
예제 #4
0
 def request(self, kind, options=None):
     if kind in ['call', 'cast']:
         self._verify_options(options)
         return Request(self, bert.Atom(kind), options)
     else:
         raise error.InvalidRequest('unsupported request of kind: "%s"' %
                                    kind)
예제 #5
0
    def start(self):
        Ernie.log("Starting")
        # On windows nouse_stdio is ignored by Erlang at the port creation,
        # so we cannot use file descriptor 3 and 4 for communication.
        # We must use file descriptors 0 and 1.
        fdi, fdo = (0, 1) if os.name is 'nt' else (3, 4)
        input = os.fdopen(fdi)
        output = os.fdopen(fdo, "w")

        while (True):
            ipy = self.read_berp(input)
            if ipy == None:
                print 'Could not read BERP length header. Ernie server may have gone away. Exiting now.'
                exit()

            if len(ipy) == 4 and ipy[0] == bert.Atom('call'):
                mod, fun, args = ipy[1:4]
                self.log("-> " + ipy.__str__())
                try:
                    res = self.dispatch(mod, fun, args)
                    opy = (bert.Atom('reply'), res)
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
                except ServerError, e:
                    opy = (bert.Atom('error'), (bert.Atom('server'), 0,
                                                str(type(e)), str(e), ''))
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
                except Exception, e:
                    opy = (bert.Atom('error'), (bert.Atom('user'), 0,
                                                str(type(e)), str(e), ''))
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
예제 #6
0
def generate_error(etype, value, backtrace):
    error_type = bert.Atom(getattr(etype, 'error_type', 'user'))
    error_code = getattr(etype, 'error_code', 100)
    return (
        error_atom,
        (
            error_type,
            error_code,
            etype.__name__,
            str(value.args[0]
                ),  # We can only assume the first exception argument
            # is the message
            traceback.format_tb(backtrace),
        ))
예제 #7
0
import eventlet
import struct
import bert
import logging
import sys
import traceback
import zlib
from types import ModuleType
from bertlet.exceptions import (InvalidFunction, ProtocolError, InvalidModule,
                                InvalidFunction, InvalidInfo, CloseSession)

bert_decode = bert.BERTDecoder().decode
bert_encode = bert.BERTEncoder().encode

call_atom = bert.Atom('call')
cast_atom = bert.Atom('cast')
reply_atom = bert.Atom('reply')
noreply_atom = bert.Atom('noreply')
error_atom = bert.Atom('error')
info_atom = bert.Atom('info')
encode_atom = bert.Atom('encoding')
gzip_atom = bert.Atom('gzip')
accept_encoding_atom = bert.Atom('accept_encoding')

GZIP_INFO_BERT = (info_atom, encode_atom, [(gzip_atom, )])
GZIP_ACCEPT_BERT = (info_atom, accept_encoding_atom, [(gzip_atom, )])


def create_berp(bert):
    return '%s%s' % (struct.pack('>I', len(bert)), bert)
예제 #8
0
class Ernie(object):
    mods = {}
    logger = None

    @classmethod
    def mod(cls, name):
        if cls.mods.has_key(name) == False:
            cls.mods[name] = Mod(name)
        return cls.mods[name]

    @classmethod
    def logfile(cls, file):
        logging.basicConfig(filename=file, level=logging.DEBUG)
        cls.logger = logging.getLogger('ernie')

    @classmethod
    def log(cls, text):
        if cls.logger != None:
            cls.logger.debug(text)

    def dispatch(self, mod, fun, args):
        if Ernie.mods.has_key(mod) == False:
            raise ServerError("No such module '" + mod + "'")
        if Ernie.mods[mod].funs.has_key(fun) == False:
            raise ServerError("No such function '" + mod + ":" + fun + "'")
        return Ernie.mods[mod].funs[fun](*args)

    def read_4(self, input):
        raw = input.read(4)
        if len(raw) == 0:
            return None
        return struct.unpack('!L', raw)[0]

    def read_berp(self, input):
        packet_size = self.read_4(input)
        if packet_size == None:
            return None
        ber = input.read(packet_size)
        return bert.decode(ber)

    def write_berp(self, output, obj):
        data = bert.encode(obj)
        output.write(struct.pack("!L", len(data)))
        output.write(data)
        output.flush()

    def start(self):
        Ernie.log("Starting")
        # On windows nouse_stdio is ignored by Erlang at the port creation,
        # so we cannot use file descriptor 3 and 4 for communication.
        # We must use file descriptors 0 and 1.
        fdi, fdo = (0, 1) if os.name is 'nt' else (3, 4)
        input = os.fdopen(fdi)
        output = os.fdopen(fdo, "w")

        while (True):
            ipy = self.read_berp(input)
            if ipy == None:
                print 'Could not read BERP length header. Ernie server may have gone away. Exiting now.'
                exit()

            if len(ipy) == 4 and ipy[0] == bert.Atom('call'):
                mod, fun, args = ipy[1:4]
                self.log("-> " + ipy.__str__())
                try:
                    res = self.dispatch(mod, fun, args)
                    opy = (bert.Atom('reply'), res)
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
                except ServerError, e:
                    opy = (bert.Atom('error'), (bert.Atom('server'), 0,
                                                str(type(e)), str(e), ''))
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
                except Exception, e:
                    opy = (bert.Atom('error'), (bert.Atom('user'), 0,
                                                str(type(e)), str(e), ''))
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
            elif len(ipy) == 4 and ipy[0] == bert.Atom('cast'):
                mod, fun, args = ipy[1:4]
                self.log("-> " + ipy.__str__())
                try:
                    res = self.dispatch(mod, fun, args)
                except:
                    pass
                self.write_berp(output, (bert.Atom('noreply')))
예제 #9
0
                except Exception, e:
                    opy = (bert.Atom('error'), (bert.Atom('user'), 0,
                                                str(type(e)), str(e), ''))
                    self.log("<- " + opy.__str__())
                    self.write_berp(output, opy)
            elif len(ipy) == 4 and ipy[0] == bert.Atom('cast'):
                mod, fun, args = ipy[1:4]
                self.log("-> " + ipy.__str__())
                try:
                    res = self.dispatch(mod, fun, args)
                except:
                    pass
                self.write_berp(output, (bert.Atom('noreply')))
            else:
                self.log("-> " + ipy.__str__())
                opy = (bert.Atom('error'),
                       (bert.Atom('server'), 0,
                        "Invalid request: " + ipy.__str__()))
                self.log("<- " + opy.__str__())
                self.write_berp(output, opy)


class ServerError(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)


class Mod:
예제 #10
0
 def method_missing(self, *args, **kwargs):
     return Action(self.service, self.request, self.module,
                   bert.Atom(args[0]), list(args[1:])).execute()
예제 #11
0
 def __getattr__(self, attr):
     return Module(self.service, self, bert.Atom(attr))
예제 #12
0
 def testRequestEncoder(self):
     bert_encoded = "\203h\004d\000\004calld\000\005mymodd\000\005myfunl\000\000\000\003a\001a\002a\003j"
     request = (bert.Atom('call'), bert.Atom('mymod'), bert.Atom('myfun'),
                [1, 2, 3])
     self.assertEqual(bert_encoded,
                      bertrpc.client.Encoder().encode(request))