summaryrefslogtreecommitdiff
path: root/src/leap/common/events/service.py
blob: fda45b2fe4d3ba290e7f14c5122e2cf5d3a7309e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# -*- coding: utf-8 -*-
# service.py
# Copyright (C) 2013 LEAP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
import threading
from protobuf.socketrpc.server import (
    SocketRpcServer,
    ThreadedTCPServer,
    SocketHandler,
)
from leap.common.events import (
    signal_pb2 as proto,
    registered_callbacks,
)


logger = logging.getLogger(__name__)


class SignalRpcServer(SocketRpcServer):

    def __init__(self, port, host='localhost'):
        '''port - Port this server is started on'''
        self.port = port
        self.host = host
        self.serviceMap = {}
        self.server = None

    def run(self):
        '''Activate the server.'''
        logger.info('Running server on port %d' % self.port)
        self.server = ThreadedTCPServer((self.host, self.port),
                                        SocketHandler, self)
        self.server.serve_forever()

    def stop(self):
        self.server.shutdown()


class SignalService(proto.SignalService):
    '''
    Handles signaling for LEAP components.
    '''

    def signal(self, controller, request, done):
        logger.info('Received signal.')

        # Run registered callbacks
        if registered_callbacks.has_key(request.signal):
            for (_, cbk) in registered_callbacks[request.signal]:
                cbk(request)

        # Create response message
        response = proto.SignalResponse()
        # TODO: change id for something meaningful
        response.id = 1
        response.status = proto.SignalResponse.OK

        # Call provided callback with response message
        done.run(response)


class SignalServiceThread(threading.Thread):
    """
    Singleton class for starting a server thread
    """

    # Singleton instance
    _instance = None

    def __init__(self, port):
        super(SignalServiceThread, self).__init__()
        self._service = SignalService()
        self._port = port
        self._server = SignalRpcServer(self._port)
        self._server.registerService(self._service)
        self.setDaemon(True)

    @staticmethod
    def start_service(port):
        """
        Start the singleton instance if not already running
        Will not exit until the process ends
        """
        if SignalServiceThread._instance == None:
            SignalServiceThread._instance = SignalServiceThread(port)
            SignalServiceThread._instance.start()
        elif port != SignalServiceThread._instance._port:
            # TODO: make this exception more self-explanatory
            raise Exception()
        return SignalServiceThread._instance

    def get_instance(self):
        return self._instance

    def run(self):
        self._server.run()

    def stop(self):
        self._server.stop()