# Path: kitty/remote/rpc.py
# class RpcClient(object):
# 
#     def __init__(self, host, port):
#         '''
#         :param url: URL of the RPC server
#         '''
#         self.cache = {}
#         self.url = 'http://%s:%d' % (host, port)
#         self.headers = {'content-type': 'application/json'}
#         self.uid = 0
# 
#     def __getattr__(self, key):
#         '''
#         Return a function with that name, which performs json rpc request
# 
#         :param key: name of the function
#         :return: function with that name
#         '''
#         if key in self.cache:
#             func = self.cache[key]
#         else:
#             func = self._generate_rpc_method(key)
#             self.cache[key] = func
#         return func
# 
#     def get_unique_msg_id(self):
#         '''
#         :return: a unique message id
#         '''
#         uid = self.uid
#         self.uid += 1
#         return uid
# 
#     def _generate_rpc_method(self, method):
#         '''
#         Generate a function that performs rpc call
# 
#         :param method: method name
#         :return: rpc function
#         '''
#         def _(**kwargs):
#             '''
#             always use named arguments
#             '''
#             msg_id = self.get_unique_msg_id()
#             params = encode_data(kwargs)
#             payload = {
#                 'method': method,
#                 'params': params,
#                 'jsonrpc': '2.0',
#                 'id': msg_id
#             }
#             response = requests.post(self.url, data=json.dumps(payload), headers=self.headers).json()
#             if ('error' in response):
#                 if response['error']['code'] == JSONRPC_NO_RESULT:
#                     return None
#                 raise Exception('Got error from RPC server when called "%s" error: %s' % (method, response['error']))
#             if 'result' in response:
#                 result = decode_data(response['result'])
#                 return result
#         return _
# 
#     def stop_remote_server(self):
#         '''
#         Stop the remote server (after responding to this message)
#         '''
#         self._meta_stop_server()
# 
# class RpcServer(object):
# 
#     _STATE_IDLE = 1
#     _STATE_RUN = 2
#     _STATE_SHOULD_STOP = 3
# 
#     def __init__(self, host, port, impl):
#         '''
#         :param host: listening address
#         :param port: listening port
#         :param impl: implementation class
#         '''
#         self.host = host
#         self.port = port
#         self.server = RpcHttpServer((host, port), RpcHandler, impl, self)
#         self.impl = impl
#         self.running = True
#         self.state = RpcServer._STATE_IDLE
# 
#     def start(self):
#         '''
#         Serving loop
#         '''
#         print('Waiting for a client to connect to url http://%s:%d/' % (self.host, self.port))
#         self.state = RpcServer._STATE_RUN
#         while self.state == RpcServer._STATE_RUN:
#             self.server.handle_request()
#         self.server.server_close()
#         self.state = RpcServer._STATE_IDLE
# 
#     def stop_server(self):
#         '''
#         Mark the server state to be stopped.
#         No further action needed when called from remote RPC client (stop_remote_server),
#         but requires another request if called directly
#         '''
#         self.state = RpcServer._STATE_SHOULD_STOP
# 
#     def is_running(self):
#         '''
#         Check if the server is currently running
# 
#         :return: whether the server is currently running
#         '''
#         return self.state != RpcServer._STATE_IDLE


import unittest
import time
from threading import Thread
from common import get_test_logger
from kitty.remote.rpc import RpcClient, RpcServer
#
# You should have received a copy of the GNU General Public License
# along with Kitty.  If not, see <http://www.gnu.org/licenses/>.


class RemoteServerImpl(object):

    def __init__(self, testcase):
        self.testcase = testcase

    def func_without_args(self):
        self.testcase.mark_called('func_without_args')
        return 1

    def func_with_args(self, **kwargs):
        self.testcase.mark_called('func_with_args', **kwargs)
        return 1

    def func_with_no_retval(self):
        self.testcase.mark_called('func_with_no_retval')

    def raises_exception(self):
        self.testcase.mark_called('raises_exception')
        raise Exception('Boom')


class RpcServerTestCase(unittest.TestCase):

    def setUp(self):
        self.logger = get_test_logger()

# Path: kitty/remote/rpc.py
# class RpcClient(object):
# 
#     def __init__(self, host, port):
#         '''
#         :param url: URL of the RPC server
#         '''
#         self.cache = {}
#         self.url = 'http://%s:%d' % (host, port)
#         self.headers = {'content-type': 'application/json'}
#         self.uid = 0
# 
#     def __getattr__(self, key):
#         '''
#         Return a function with that name, which performs json rpc request
# 
#         :param key: name of the function
#         :return: function with that name
#         '''
#         if key in self.cache:
#             func = self.cache[key]
#         else:
#             func = self._generate_rpc_method(key)
#             self.cache[key] = func
#         return func
# 
#     def get_unique_msg_id(self):
#         '''
#         :return: a unique message id
#         '''
#         uid = self.uid
#         self.uid += 1
#         return uid
# 
#     def _generate_rpc_method(self, method):
#         '''
#         Generate a function that performs rpc call
# 
#         :param method: method name
#         :return: rpc function
#         '''
#         def _(**kwargs):
#             '''
#             always use named arguments
#             '''
#             msg_id = self.get_unique_msg_id()
#             params = encode_data(kwargs)
#             payload = {
#                 'method': method,
#                 'params': params,
#                 'jsonrpc': '2.0',
#                 'id': msg_id
#             }
#             response = requests.post(self.url, data=json.dumps(payload), headers=self.headers).json()
#             if ('error' in response):
#                 if response['error']['code'] == JSONRPC_NO_RESULT:
#                     return None
#                 raise Exception('Got error from RPC server when called "%s" error: %s' % (method, response['error']))
#             if 'result' in response:
#                 result = decode_data(response['result'])
#                 return result
#         return _
# 
#     def stop_remote_server(self):
#         '''
#         Stop the remote server (after responding to this message)
#         '''
#         self._meta_stop_server()
# 
# class RpcServer(object):
# 
#     _STATE_IDLE = 1
#     _STATE_RUN = 2
#     _STATE_SHOULD_STOP = 3
# 
#     def __init__(self, host, port, impl):
#         '''
#         :param host: listening address
#         :param port: listening port
#         :param impl: implementation class
#         '''
#         self.host = host
#         self.port = port
#         self.server = RpcHttpServer((host, port), RpcHandler, impl, self)
#         self.impl = impl
#         self.running = True
#         self.state = RpcServer._STATE_IDLE
# 
#     def start(self):
#         '''
#         Serving loop
#         '''
#         print('Waiting for a client to connect to url http://%s:%d/' % (self.host, self.port))
#         self.state = RpcServer._STATE_RUN
#         while self.state == RpcServer._STATE_RUN:
#             self.server.handle_request()
#         self.server.server_close()
#         self.state = RpcServer._STATE_IDLE
# 
#     def stop_server(self):
#         '''
#         Mark the server state to be stopped.
#         No further action needed when called from remote RPC client (stop_remote_server),
#         but requires another request if called directly
#         '''
#         self.state = RpcServer._STATE_SHOULD_STOP
# 
#     def is_running(self):
#         '''
#         Check if the server is currently running
# 
#         :return: whether the server is currently running
#         '''
#         return self.state != RpcServer._STATE_IDLE


# Path: tests/test_remote_rpc.py
import unittest
import time
from threading import Thread
from common import get_test_logger
from kitty.remote.rpc import RpcClient, RpcServer

#
# You should have received a copy of the GNU General Public License
# along with Kitty.  If not, see <http://www.gnu.org/licenses/>.


class RemoteServerImpl(object):

    def __init__(self, testcase):
        self.testcase = testcase

    def func_without_args(self):
        self.testcase.mark_called('func_without_args')
        return 1

    def func_with_args(self, **kwargs):
        self.testcase.mark_called('func_with_args', **kwargs)
        return 1

    def func_with_no_retval(self):
        self.testcase.mark_called('func_with_no_retval')

    def raises_exception(self):
        self.testcase.mark_called('raises_exception')
        raise Exception('Boom')


class RpcServerTestCase(unittest.TestCase):

    def setUp(self):
        self.logger = get_test_logger()

        self.our_class = RemoteServerImpl(self)