DoorPiWeb   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 68
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 68
rs 10
c 1
b 1
f 0
wmc 15

9 Methods

Rating   Name   Duplication   Size   Complexity  
A sessions() 0 6 3
A inform_own_url() 0 1 1
A own_url() 0 6 2
A fake_request() 0 5 2
A config_status() 0 2 1
A config() 0 2 1
A start() 0 18 1
A handle_while_not_shutdown() 0 2 2
A init_shutdown() 0 7 2
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
import logging
5
logger = logging.getLogger(__name__)
6
logger.debug("%s loaded", __name__)
7
8
from BaseHTTPServer import HTTPServer
9
from SocketServer import ThreadingMixIn
10
11
from random import randrange
0 ignored issues
show
Unused Code introduced by
Unused randrange imported from random
Loading history...
12
13
import doorpi
14
from doorpi.action.base import SingleAction
15
16
from doorpi.status.webserver_lib.session_handler import SessionHandler
17
from doorpi.status.webserver_lib.request_handler import DoorPiWebRequestHandler
18
19
class WebServerStartupAction(SingleAction): pass
20
class WebServerFakeRequestAction(SingleAction): pass
21
class WebServerShutdownAction(SingleAction): pass
22
class WebServerInformUrl(SingleAction): pass
23
24
DOORPIWEB_SECTION = 'DoorPiWeb'
25
CONF_AREA_PREFIX = 'AREA_'
26
27
def load_webserver():
28
    ip = doorpi.DoorPi().config.get(DOORPIWEB_SECTION, 'ip', '')
29
    port = doorpi.DoorPi().config.get_int(DOORPIWEB_SECTION, 'port', 80)
30
31
    doorpiweb_object = False
32
33
    possible_ports = [port, 80, 8080, 0]
34
    for single_port in possible_ports:
35
        try:
36
            server_address = (ip, single_port)
37
            doorpiweb_object = DoorPiWeb(server_address, DoorPiWebRequestHandler)
38
            logger.info('Initiating WebService at ip %s and port %s', ip, single_port)
39
            doorpiweb_object.start()
40
            if single_port is not port:
41
                doorpi.DoorPi().event_handler.register_action('OnTimeSecondEvenNumber', doorpiweb_object.inform_own_url)
42
            return doorpiweb_object
43
        except Exception as exp:
44
            logger.warning('failed to initiating WebService at ip %s and port %s (%s)', ip, single_port, exp)
45
46
    return doorpiweb_object
47
48
def check_config(config):
49
    errors = []
50
    warnings = []
51
    infos = []
52
53
    groups_with_write_permissions = config.get_keys('WritePermission')
54
    groups_with_read_permissions = config.get_keys('ReadPermission')
55
    groups = config.get_keys('Group')
56
    users = config.get_keys('User')
57
58
    if len(groups) == 0:
59
        errors.append('no groups in configfile!')
60
61
    if len(groups_with_write_permissions) == 0:
62
        errors.append("no WritePermission found")
63
64
    for group in groups_with_write_permissions:
65
        if group not in groups: warnings.append("group %s doesn't exist but is assigned to WritePermission" % group)
66
67
    if len(groups_with_read_permissions) == 0:
68
        warnings.append("no ReadPermission found")
69
70
    for group in groups_with_read_permissions:
71
        if group not in groups: warnings.append("group %s doesn't exist but is assigned to ReadPermission" % group)
72
73
    for group in groups:
74
        users_in_group = config.get_list('Group', group)
75
        for user_in_group in users_in_group:
76
            if user_in_group not in users:
77
                warnings.append("user %s is assigned to group %s but doesn't exist as user" % (user_in_group, group))
78
79
    config_section = config.get_sections()
80
81
    for group in groups_with_write_permissions:
82
        modules = config.get_list('WritePermission', group)
83
        for module in modules:
84
            if CONF_AREA_PREFIX+module not in config_section:
85
                warnings.append("module %s doesn't exist but is assigned to group %s in WritePermission" % (module, group))
86
87
    for group in groups_with_read_permissions:
88
        modules = config.get_list('ReadPermission', group)
89
        for module in modules:
90
            if CONF_AREA_PREFIX+module not in config_section:
91
                warnings.append("module %s doesn't exist but is assigned to group %s in ReadPermission" % (module, group))
92
93
    for info in infos: logger.info(info)
94
    for warning in warnings: logger.error(warning)
95
    for error in errors: logger.error(error)
96
97
    return {'infos': infos, 'warnings': warnings, 'errors': errors}
98
99
class DoorPiWeb(ThreadingMixIn, HTTPServer):
100
    keep_running = True
101
102
    www = None
103
    indexfile = None
104
    loginfile = None
105
    base_url = None
106
    area_public_name = None
107
    online_fallback = None
108
109
    @property
110
    def config_status(self): return check_config(self.config)
111
112
    @property
113
    def own_url(self):
114
        if self.server_port is 80:
115
            return "http://%s/"%self.server_name
116
        else:
117
            return "http://%s:%s/"%(self.server_name, self.server_port)
118
119
    def inform_own_url(self): logger.info('DoorPiWeb URL is %s', self.own_url)
120
121
    @property
122
    def sessions(self):
123
        if not self._session_handler and self.keep_running:
124
            logger.debug('no session handler - creating it now')
125
            self._session_handler = SessionHandler()
126
        return self._session_handler
127
    _session_handler = None
128
129
    @property
130
    def config(self): return doorpi.DoorPi().config
131
132
    def start(self):
133
        doorpi.DoorPi().event_handler.register_event('OnWebServerStart', __name__)
134
        doorpi.DoorPi().event_handler.register_event('OnWebServerStop', __name__)
135
136
        self.www = doorpi.DoorPi().config.get_string_parsed(DOORPIWEB_SECTION, 'www', '!BASEPATH!/../DoorPiWeb')
137
        self.indexfile = doorpi.DoorPi().config.get_string_parsed(DOORPIWEB_SECTION, 'indexfile', 'index.html')
138
        self.loginfile = doorpi.DoorPi().config.get_string_parsed(DOORPIWEB_SECTION, 'loginfile', 'login.html')
139
        self.area_public_name = doorpi.DoorPi().config.get_string_parsed(DOORPIWEB_SECTION, 'public', 'AREA_public')
140
        # https://raw.githubusercontent.com/motom001/DoorPiWeb/master/ or http://motom001.github.io/DoorPiWeb/
141
        self.online_fallback = doorpi.DoorPi().config.get_string_parsed(DOORPIWEB_SECTION, 'online_fallback', 'http://motom001.github.io/DoorPiWeb')
142
        check_config(self.config)
143
144
        doorpi.DoorPi().event_handler.register_action('OnWebServerStart', WebServerStartupAction(self.handle_while_not_shutdown))
145
        doorpi.DoorPi().event_handler.register_action('OnShutdown', WebServerShutdownAction(self.init_shutdown))
146
        doorpi.DoorPi().event_handler('OnWebServerStart', __name__)
147
148
        DoorPiWebRequestHandler.prepare()
149
        return self
150
151
    def handle_while_not_shutdown(self):
152
        while self.keep_running: self.handle_request()
153
154
    def fake_request(self):
155
        try:
156
            from urllib2 import urlopen as fake_request
157
            fake_request("http://%s:%s/"%(self.server_name, self.server_port), timeout = 0)
158
        except: pass
159
160
    def init_shutdown(self):
161
        doorpi.DoorPi().event_handler('OnWebServerStop', __name__)
162
        self.keep_running = False
163
        if self.sessions: self.sessions.destroy()
164
        DoorPiWebRequestHandler.destroy()
165
        self.fake_request()
166
        doorpi.DoorPi().event_handler.unregister_source(__name__, True)
167