-
Notifications
You must be signed in to change notification settings - Fork 17
/
plinth.py
executable file
·172 lines (146 loc) · 6.23 KB
/
plinth.py
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env python
import os, sys, argparse
from gettext import gettext as _
import cfg
if not os.path.join(cfg.file_root, "vendor") in sys.path:
sys.path.append(os.path.join(cfg.file_root, "vendor"))
import cherrypy
from cherrypy import _cpserver
from cherrypy.process.plugins import Daemonizer
Daemonizer(cherrypy.engine).subscribe()
import plugin_mount
import util as u
from logger import Logger
#from modules.auth import AuthController, require, member_of, name_is
from vendor.withsqlite.withsqlite import sqlite_db
from vendor.exmachina.exmachina import ExMachinaClient
import socket
__version__ = "0.2.14"
__author__ = "James Vasile"
__copyright__ = "Copyright 2011-2013, James Vasile"
__license__ = "GPLv3 or later"
__maintainer__ = "James Vasile"
__email__ = "[email protected]"
__status__ = "Development"
def error_page(status, dynamic_msg, stock_msg):
return u.page_template(template="err", title=status, main="<p>%s</p>%s" % (dynamic_msg, stock_msg))
def error_page_404(status, message, traceback, version):
return error_page(status, message, """<p>If you believe this
missing page should exist, please file a bug with either the Plinth
project (<a href="https://github.com/jvasile/plinth/issues">it has
an issue tracker</a>) or the people responsible for the module you
are trying to access.</p>
<p>Sorry for the mistake.</p>
""")
def error_page_500(status, message, traceback, version):
cfg.log.error("500 Internal Server Error. Trackback is above.")
more="""<p>This is an internal error and not something you caused
or can fix. Please report the error on the <a
href="https://github.com/jvasile/Plinth/issues">bug tracker</a> so
we can fix it.</p>"""
return error_page(status, message, "<p>%s</p><pre>%s</pre>" % (more, "\n".join(traceback.split("\n"))))
class Root(plugin_mount.PagePlugin):
@cherrypy.expose
def index(self):
## TODO: firstboot hijacking root should probably be in the firstboot module with a hook in plinth.py
with sqlite_db(cfg.store_file, table="firstboot") as db:
if not 'state' in db:
raise cherrypy.InternalRedirect('/firstboot')
elif db['state'] < 5:
cfg.log("First Boot state = %d" % db['state'])
raise cherrypy.InternalRedirect('/firstboot/state%d' % db['state'])
if cherrypy.session.get(cfg.session_key, None):
raise cherrypy.InternalRedirect('/router')
else:
raise cherrypy.InternalRedirect('/help/about')
def load_modules():
"""Import all the symlinked .py files in the modules directory and
all the .py files in directories linked in the modules directory
(but don't dive deeper than that). Also, ignore the installed
directory."""
for name in os.listdir("modules"):
if name.endswith(".py") and not name.startswith('.'):
cfg.log.info("importing modules/%s" % name)
try:
__import__("modules.%s" % (name[:-3]))
except ImportError, e:
cfg.log.error(_("Couldn't import modules/%s: %s") % (name, e))
else:
cfg.log("skipping %s" % name)
def parse_arguments():
parser = argparse.ArgumentParser(description='Plinth web interface for the FreedomBox.')
parser.add_argument('--pidfile', default="",
help='specify a file in which the server may write its pid')
parser.add_argument('--listen-exmachina-key', default=False, action='store_true',
help='listen for JSON-RPC shared secret key on stdin at startup')
args=parser.parse_args()
if args.pidfile:
cfg.pidfile = args.pidfile
else:
try:
if not cfg.pidfile:
cfg.pidfile = "plinth.pid"
except AttributeError:
cfg.pidfile = "plinth.pid"
if args.listen_exmachina_key:
# this is where we optionally try to read in a shared secret key to
# authenticate connections to exmachina
cfg.exmachina_secret_key = sys.stdin.readline().strip()
else:
cfg.exmachina_secret_key = None
def setup():
parse_arguments()
try:
if cfg.pidfile:
from cherrypy.process.plugins import PIDFile
PIDFile(cherrypy.engine, cfg.pidfile).subscribe()
except AttributeError:
pass
try:
cfg.exmachina = ExMachinaClient(
secret_key=cfg.exmachina_secret_key or None)
except socket.error:
cfg.exmachina = None
print "couldn't connect to exmachina daemon, but continuing anyways..."
os.chdir(cfg.file_root)
cherrypy.config.update({'error_page.404': error_page_404})
cherrypy.config.update({'error_page.500': error_page_500})
cfg.log = Logger()
load_modules()
cfg.html_root = Root()
cfg.users = plugin_mount.UserStoreModule.get_plugins()[0]
cfg.page_plugins = plugin_mount.PagePlugin.get_plugins()
cfg.log("Loaded %d page plugins" % len(cfg.page_plugins))
cfg.forms = plugin_mount.FormPlugin.get_plugins()
# Add an extra server
server = _cpserver.Server()
server.socket_host = '127.0.0.1'
server.socket_port = 52854
server.subscribe()
# Configure default server
cherrypy.config.update({'server.socket_host': cfg.host,
'server.socket_port': cfg.port,
'server.thread_pool':10,
'tools.staticdir.root': cfg.file_root,
'tools.sessions.on':True,
'tools.auth.on':True,
'tools.sessions.storage_type':"file",
'tools.sessions.timeout':90,
'tools.sessions.storage_path':"%s/cherrypy_sessions" % cfg.data_dir,
})
config = {'/': {'tools.staticdir.root': '%s/static' % cfg.file_root,
'tools.proxy.on':True,},
'/static': {'tools.staticdir.on': True,
'tools.staticdir.dir':"."},
'/favicon.ico':{'tools.staticfile.on':True,
'tools.staticfile.filename': "%s/static/theme/favicon.ico" % cfg.file_root}
}
cherrypy.tree.mount(cfg.html_root, '/', config=config)
cherrypy.engine.signal_handler.subscribe()
def main():
setup()
print "%s %d" % (cfg.host, cfg.port)
cherrypy.engine.start()
cherrypy.engine.block()
if __name__ == '__main__':
main()