summaryrefslogtreecommitdiff
path: root/plinth.py
blob: 79d96748cb5036902f3c18110d25398c9b6063ee (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
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
#!/usr/bin/env python

import os, sys, argparse
#import logging
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
from util import *
from logger import Logger
#from modules.auth import AuthController, require, member_of, name_is

import socket

__version__ = "0.2.14"
__author__ = "James Vasile"
__copyright__ = "Copyright 2011, James Vasile"
__license__ = "GPLv3 or later"
__maintainer__ = "James Vasile"
__email__ = "james@jamesvasile.com"
__status__ = "Development"

def error_page(status, dynamic_msg, stock_msg):
   return 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 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/seandiggity/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):
      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:
      if not cfg.pidfile:
            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:
      from exmachina import ExMachinaClient
   except ImportError:
      cfg.exmachina = None
   else:
      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/data/cherrypy_sessions" % cfg.file_root,
        })

   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()