0xGA: Check-in [3f38ad2fef]

Yet another PHP framework, but made for org-mode and geeks.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add interruption mechanism to narv.py to allow devs to add custom actions to their apps
Timelines: family | ancestors | descendants | both | narv
Files: files | file ages | folders
SHA1:3f38ad2fef554b290b221e31d53a0519d58349ca
User & Date: milouse 2014-05-07 00:47:26
Context
2014-05-07
00:49
Add sqlite support and features to example app check-in: 66313b85fd user: milouse tags: narv
00:47
Add interruption mechanism to narv.py to allow devs to add custom actions to their apps check-in: 3f38ad2fef user: milouse tags: narv
2014-05-04
21:20
New installer version check-in: 19fd48004e user: milouse tags: narv
Changes

Changes to create_narv_installer.sh.

    48     48   This program will now exit to let you do all the necessary things before."
    49     49       exit 1
    50     50   fi
    51     51   
    52     52   mkdir $WORKINGREP
    53     53   
    54     54   echo ":: creating shared necessary directories structure"
           55  +install -dm 755 $WORKINGREP/var/db
    55     56   install -dm 755 $WORKINGREP/var/log
    56     57   install -dm 777 $WORKINGREP/var/tmp
    57     58   install -dm 755	$WORKINGREP/usr/bin
    58     59   install -dm 755	$WORKINGREP/etc
    59     60   
    60     61   install -Dm 755 narv.py $WORKINGREP/usr/bin
    61     62   install -Dm 755 narv    $WORKINGREP/usr/bin
    62     63   
    63     64   rm narv narv.py
    64     65   
    65     66   echo "General installation finished."
    66     67   echo "You may now want to create your first app by entering the command:"
    67     68   echo "$WORKINGREP/usr/bin/narv create [-d $WORKINGREP] <appname>"

Changes to narv.py.

    35     35           'woff': 'application/font-woff',
    36     36           'atom': 'application/atom+xml; charset=utf-8',
    37     37           'json': 'application/json; charset=utf-8',
    38     38           'js': 'text/javascript; charset=utf-8',
    39     39           'py': 'text/plain',
    40     40           'gpg': 'text/plain',
    41     41           'el': 'text/plain',
           42  +        'txt': 'text/plain',
    42     43           'org': 'text/plain; charset=utf-8',
    43     44           'pdf': 'application/pdf'
    44     45       }
    45     46   
    46     47       def __init__(self, request, App):
    47     48   
    48     49           self.routes = []
................................................................................
   196    197           if not self.current_domain in config:
   197    198               self.error = 'Domain is not reachable in configuration file'
   198    199   
   199    200           else:
   200    201               self.config = config[self.current_domain]
   201    202               logging.debug('Request is for App {0}'.format(self.appname))
   202    203   
          204  +            if self.server.should_interrupt:
          205  +                logging.info('Processing request after SIGUSR1')
          206  +                self.server.should_interrupt = False
          207  +                self.do_interrupt()
          208  +
   203    209   
   204    210       def log_message(self, message, *args):
   205    211           logging.info(message % args)
   206    212   
          213  +
          214  +    def do_interrupt(self):
          215  +        pass
          216  +
   207    217   
   208    218       def do_error_page(self, errno, reason):
   209    219           self.build_headers(int(errno), 'text/html; charset=utf-8')
   210    220   
   211    221           if errno in self.config:
   212    222               with open(self.config[errno], 'rb') as f:
   213    223                   shutil.copyfileobj(f, self.wfile)
................................................................................
   296    306           else:
   297    307               self.do_501(self.error)
   298    308   
   299    309   
   300    310   
   301    311   class NarvThreadedServer(ThreadingMixIn, HTTPServer):
   302    312       """Main threaded server"""
          313  +    should_interrupt = False
   303    314   
   304    315   
   305    316   class Narv:
   306    317       def __init__(self, server_infos=('', 8000), request_handler=IcanDoThat):
   307    318   
   308    319           config = ConfigParser()
   309    320           config.read('etc/rc.conf')
................................................................................
   329    340               format='%(asctime)s -- [%(levelname)s] %(message)s',
   330    341               datefmt='%Y-%m-%d %H:%M:%S',
   331    342               filename=os.path.join(narv_root_path, 'var/log/', log_file),
   332    343               level=getattr(logging, log_level.upper()))
   333    344   
   334    345           signal.signal(signal.SIGINT, self.shutdown)
   335    346           signal.signal(signal.SIGTERM, self.shutdown)
          347  +        signal.signal(signal.SIGUSR1, self.interrupt)
   336    348   
   337    349           self.server = NarvThreadedServer(server_infos, request_handler)
   338    350           server_thread = threading.Thread(target=self.server.serve_forever)
   339    351           server_thread.daemon = True
   340    352           server_thread.start()
   341    353   
   342    354           if os.getuid() == 0:
................................................................................
   352    364               os.setuid(pwd.getpwnam('nobody').pw_uid)
   353    365   
   354    366               # Ensure a very conservative umask
   355    367               os.umask(int('077', 8))
   356    368           else:
   357    369               os.chdir(narv_root_path)
   358    370   
          371  +
          372  +    def interrupt(self, signal, frame):
          373  +        logging.info('SIGUSR1 caught. Waiting for next request...')
          374  +        self.server.should_interrupt = True
          375  +
   359    376   
   360    377       def start(self):
   361    378           logging.info("Serving {0} at port {1}".format(self.server.server_name, self.server.server_port))
   362    379           self.server.serve_forever()
   363    380   
   364    381   
   365    382       def shutdown(self, signal, frame):