# Path: pylm/servers.py
# class Server(object):
#     """
#     Standalone and minimal server that replies single requests.
# 
#     :param str name: Name of the server
#     :param str db_address: ZeroMQ address of the cache service.
#     :param str pull_address: Address of the pull socket
#     :param str pub_address: Address of the pub socket
#     :param pipelined: True if the server is chained to another server.
#     :param log_level: Minimum output log level.
#     :param int messages: Total number of messages that the server processes.
#         Useful for debugging.
#     """
#     def __init__(self, name, db_address,
#                  pull_address, pub_address, pipelined=False,
#                  log_level=logging.INFO, messages=sys.maxsize):
#         self.name = name
#         self.cache = DictDB()
#         self.db_address = db_address
#         self.pull_address = pull_address
#         self.pub_address = pub_address
#         self.pipelined = pipelined
#         self.message = None
# 
#         self.cache.set('name', name.encode('utf-8'))
#         self.cache.set('pull_address', pull_address.encode('utf-8'))
#         self.cache.set('pub_address', pub_address.encode('utf-8'))
# 
#         self.logger = logging.getLogger(name=name)
#         handler = logging.StreamHandler(sys.stdout)
#         handler.setFormatter(
#             logging.Formatter(
#                 '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
#             )
#         )
#         self.logger.addHandler(handler)
#         self.logger.setLevel(log_level)
# 
#         self.messages = messages
# 
#         self.pull_socket = zmq_context.socket(zmq.PULL)
#         self.pull_socket.bind(self.pull_address)
# 
#         self.pub_socket = zmq_context.socket(zmq.PUB)
#         self.pub_socket.bind(self.pub_address)
# 
#     def handle_stream(self, message):
#         """
#         Handle the stream of messages.
# 
#         :param message: The message about to be sent to the next step in the
#             cluster
#         :return: topic (str) and message (PalmMessage)
# 
#         The default behaviour is the following. If you leave this function
#         unchanged and pipeline is set to False, the topic is the ID of the
#         client, which makes the message return to the client. If the pipeline
#         parameter is set to True, the topic is set as the name of the server and
#         the step of the message is incremented by one.
# 
#         You can alter this default behaviour by overriding this function.
#         Take into account that the message is also available in this function,
#         and you can change other parameters like the stage or the function.
#         """
#         if self.pipelined:
#             topic = self.name
#             message.stage += 1
#         else:
#             topic = message.client
# 
#         return topic, message
# 
#     def echo(self, payload):
#         """
#         Echo utility function that returns the unchanged payload. This
#         function is useful when the server is there as just to modify the
#         stream of messages.
# 
#         :return: payload (bytes)
#         """
#         return payload
# 
#     def _execution_handler(self):
#         for i in range(self.messages):
#             self.logger.debug('Server waiting for messages')
#             message_data = self.pull_socket.recv()
#             self.logger.debug('Got message {}'.format(i + 1))
#             result = b'0'
#             self.message = PalmMessage()
#             try:
#                 self.message.ParseFromString(message_data)
# 
#                 # Handle the fact that the message may be a complete pipeline
#                 try:
#                     if ' ' in self.message.function:
#                         [server, function] = self.message.function.split()[
#                             self.message.stage].split('.')
#                     else:
#                         [server, function] = self.message.function.split('.')
#                 except IndexError:
#                     raise ValueError('Pipeline call not correct. Review the '
#                                      'config in your client')
#                         
#                 if not self.name == server:
#                     self.logger.error('You called {}, instead of {}'.format(
#                         server, self.name))
#                 else:
#                     try:
#                         user_function = getattr(self, function)
#                         self.logger.debug('Looking for {}'.format(function))
#                         try:
#                             result = user_function(self.message.payload)
#                         except:
#                             self.logger.error('User function gave an error')
#                             exc_type, exc_value, exc_traceback = sys.exc_info()
#                             lines = traceback.format_exception(
#                                 exc_type, exc_value, exc_traceback)
#                             for l in lines:
#                                 self.logger.exception(l)
# 
#                     except KeyError:
#                         self.logger.error(
#                             'Function {} was not found'.format(function)
#                         )
#             except DecodeError:
#                 self.logger.error('Message could not be decoded')
# 
#             self.message.payload = result
# 
#             topic, self.message = self.handle_stream(self.message)
# 
#             self.pub_socket.send_multipart(
#                 [topic.encode('utf-8'), self.message.SerializeToString()]
#             )
# 
#     def start(self, cache_messages=sys.maxsize):
#         """
#         Start the server
# 
#         :param cache_messages: Number of messages the cache service handles
#             before it shuts down. Useful for debugging
# 
#         """
#         threads = []
# 
#         cache = CacheService('cache', self.db_address, logger=self.logger,
#                              cache=self.cache, messages=cache_messages)
# 
#         threads.append(cache.start)
#         threads.append(self._execution_handler)
# 
#         with concurrent.futures.ThreadPoolExecutor(max_workers=len(threads)) as executor:
#             results = [executor.submit(thread) for thread in threads]
#             for future in concurrent.futures.as_completed(results):
#                 try:
#                     future.result()
#                 except Exception as exc:
#                     self.logger.error(
#                         'This is critical, one of the components of the '
#                         'server died')
#                     lines = traceback.format_exception(*sys.exc_info())
#                     for line in lines:
#                         self.logger.error(line.strip('\n'))
# 
#         return self.name.encode('utf-8')


from pylm.servers import Server
import logging


class MyServer(Server):
    def foo(self, message):
        self.logger.warning('Got a message')
        return b'you sent me ' + message



# Path: pylm/servers.py
# class Server(object):
#     """
#     Standalone and minimal server that replies single requests.
# 
#     :param str name: Name of the server
#     :param str db_address: ZeroMQ address of the cache service.
#     :param str pull_address: Address of the pull socket
#     :param str pub_address: Address of the pub socket
#     :param pipelined: True if the server is chained to another server.
#     :param log_level: Minimum output log level.
#     :param int messages: Total number of messages that the server processes.
#         Useful for debugging.
#     """
#     def __init__(self, name, db_address,
#                  pull_address, pub_address, pipelined=False,
#                  log_level=logging.INFO, messages=sys.maxsize):
#         self.name = name
#         self.cache = DictDB()
#         self.db_address = db_address
#         self.pull_address = pull_address
#         self.pub_address = pub_address
#         self.pipelined = pipelined
#         self.message = None
# 
#         self.cache.set('name', name.encode('utf-8'))
#         self.cache.set('pull_address', pull_address.encode('utf-8'))
#         self.cache.set('pub_address', pub_address.encode('utf-8'))
# 
#         self.logger = logging.getLogger(name=name)
#         handler = logging.StreamHandler(sys.stdout)
#         handler.setFormatter(
#             logging.Formatter(
#                 '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
#             )
#         )
#         self.logger.addHandler(handler)
#         self.logger.setLevel(log_level)
# 
#         self.messages = messages
# 
#         self.pull_socket = zmq_context.socket(zmq.PULL)
#         self.pull_socket.bind(self.pull_address)
# 
#         self.pub_socket = zmq_context.socket(zmq.PUB)
#         self.pub_socket.bind(self.pub_address)
# 
#     def handle_stream(self, message):
#         """
#         Handle the stream of messages.
# 
#         :param message: The message about to be sent to the next step in the
#             cluster
#         :return: topic (str) and message (PalmMessage)
# 
#         The default behaviour is the following. If you leave this function
#         unchanged and pipeline is set to False, the topic is the ID of the
#         client, which makes the message return to the client. If the pipeline
#         parameter is set to True, the topic is set as the name of the server and
#         the step of the message is incremented by one.
# 
#         You can alter this default behaviour by overriding this function.
#         Take into account that the message is also available in this function,
#         and you can change other parameters like the stage or the function.
#         """
#         if self.pipelined:
#             topic = self.name
#             message.stage += 1
#         else:
#             topic = message.client
# 
#         return topic, message
# 
#     def echo(self, payload):
#         """
#         Echo utility function that returns the unchanged payload. This
#         function is useful when the server is there as just to modify the
#         stream of messages.
# 
#         :return: payload (bytes)
#         """
#         return payload
# 
#     def _execution_handler(self):
#         for i in range(self.messages):
#             self.logger.debug('Server waiting for messages')
#             message_data = self.pull_socket.recv()
#             self.logger.debug('Got message {}'.format(i + 1))
#             result = b'0'
#             self.message = PalmMessage()
#             try:
#                 self.message.ParseFromString(message_data)
# 
#                 # Handle the fact that the message may be a complete pipeline
#                 try:
#                     if ' ' in self.message.function:
#                         [server, function] = self.message.function.split()[
#                             self.message.stage].split('.')
#                     else:
#                         [server, function] = self.message.function.split('.')
#                 except IndexError:
#                     raise ValueError('Pipeline call not correct. Review the '
#                                      'config in your client')
#                         
#                 if not self.name == server:
#                     self.logger.error('You called {}, instead of {}'.format(
#                         server, self.name))
#                 else:
#                     try:
#                         user_function = getattr(self, function)
#                         self.logger.debug('Looking for {}'.format(function))
#                         try:
#                             result = user_function(self.message.payload)
#                         except:
#                             self.logger.error('User function gave an error')
#                             exc_type, exc_value, exc_traceback = sys.exc_info()
#                             lines = traceback.format_exception(
#                                 exc_type, exc_value, exc_traceback)
#                             for l in lines:
#                                 self.logger.exception(l)
# 
#                     except KeyError:
#                         self.logger.error(
#                             'Function {} was not found'.format(function)
#                         )
#             except DecodeError:
#                 self.logger.error('Message could not be decoded')
# 
#             self.message.payload = result
# 
#             topic, self.message = self.handle_stream(self.message)
# 
#             self.pub_socket.send_multipart(
#                 [topic.encode('utf-8'), self.message.SerializeToString()]
#             )
# 
#     def start(self, cache_messages=sys.maxsize):
#         """
#         Start the server
# 
#         :param cache_messages: Number of messages the cache service handles
#             before it shuts down. Useful for debugging
# 
#         """
#         threads = []
# 
#         cache = CacheService('cache', self.db_address, logger=self.logger,
#                              cache=self.cache, messages=cache_messages)
# 
#         threads.append(cache.start)
#         threads.append(self._execution_handler)
# 
#         with concurrent.futures.ThreadPoolExecutor(max_workers=len(threads)) as executor:
#             results = [executor.submit(thread) for thread in threads]
#             for future in concurrent.futures.as_completed(results):
#                 try:
#                     future.result()
#                 except Exception as exc:
#                     self.logger.error(
#                         'This is critical, one of the components of the '
#                         'server died')
#                     lines = traceback.format_exception(*sys.exc_info())
#                     for line in lines:
#                         self.logger.error(line.strip('\n'))
# 
#         return self.name.encode('utf-8')


# Path: examples/tee/server.py
from pylm.servers import Server
import logging



class MyServer(Server):
    def foo(self, message):
        self.logger.warning('Got a message')
        return b'you sent me ' + message



if __name__ == '__main__':