status_handler.py :  » Web-Frameworks » Zope » Zope-2.6.0 » ZServer » medusa » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Zope 
Zope » Zope 2.6.0 » ZServer » medusa » status_handler.py
# -*- Mode: Python; tab-width: 4 -*-

VERSION_STRING = "$Id: status_handler.py,v 1.7 2001/05/01 11:44:49 andreas Exp $"

#      
# medusa status extension
#

import string
import time
import re

import asyncore
import http_server
import medusa_gif
import producers
from counter import counter

START_TIME = long(time.time())

class status_extension:
    hit_counter = counter()
    
    def __init__ (self, objects, statusdir='/status', allow_emergency_debug=0):
        self.objects = objects
        self.statusdir = statusdir
        self.allow_emergency_debug = allow_emergency_debug
        # We use /status instead of statusdir here because it's too
        # hard to pass statusdir to the logger, who makes the HREF
        # to the object dir.  We don't need the security-through-
        # obscurity here in any case, because the id is obscurity enough
        self.hyper_regex = re.compile('/status/object/([0-9]+)/.*')
        self.hyper_objects = []
        for object in objects:
            self.register_hyper_object (object)
            
    def __repr__ (self):
        return '<Status Extension (%s hits) at %x>' % (
                self.hit_counter,
                id(self)
                )
        
    def match (self, request):
        path, params, query, fragment = request.split_uri()
        # For reasons explained above, we don't use statusdir for /object
        return (path[:len(self.statusdir)] == self.statusdir or
                        path[:len("/status/object/")] == '/status/object/')
        
        # Possible Targets:
        # /status
        # /status/channel_list
        # /status/medusa.gif
        
        # can we have 'clickable' objects?
        # [yes, we can use id(x) and do a linear search]
        
        # Dynamic producers:
        # HTTP/1.0: we must close the channel, because it's dynamic output
        # HTTP/1.1: we can use the chunked transfer-encoding, and leave
        #   it open.
        
    def handle_request (self, request):
        [path, params, query, fragment] = split_path (request.uri)
        self.hit_counter.increment()
        if path == self.statusdir:          # and not a subdirectory
            up_time = string.join (english_time (long(time.time()) - START_TIME))
            request['Content-Type'] = 'text/html'
            request.push (
                    '<html>'
                    '<title>Medusa Status Reports</title>'
                    '<body bgcolor="#ffffff">'
                    '<h1>Medusa Status Reports</h1>'
                    '<b>Up:</b> %s' % up_time
                    )
            for i in range(len(self.objects)):
                request.push (self.objects[i].status())
                request.push ('<hr>\r\n')
            request.push (
                    '<p><a href="%s/channel_list">Channel List</a>'
                    '<hr>'
                    '<img src="%s/medusa.gif" align=right width=%d height=%d>'
                    '</body></html>' % (
                            self.statusdir,
                            self.statusdir,
                            medusa_gif.width,
                            medusa_gif.height
                            )
                    )
            request.done()
        elif path == self.statusdir + '/channel_list':
            request['Content-Type'] = 'text/html'
            request.push ('<html><body>')
            request.push(channel_list_producer(self.statusdir))
            request.push (
                    '<hr>'
                    '<img src="%s/medusa.gif" align=right width=%d height=%d>' % (
                            self.statusdir,
                            medusa_gif.width, 
                            medusa_gif.height
                            ) +
                    '</body></html>'
                    )
            request.done()
            
        elif path == self.statusdir + '/medusa.gif':
            request['Content-Type'] = 'image/gif'
            request['Content-Length'] = len(medusa_gif.data)
            request.push (medusa_gif.data)
            request.done()
            
        elif path == self.statusdir + '/close_zombies':
            message = (
                    '<h2>Closing all zombie http client connections...</h2>'
                    '<p><a href="%s">Back to the status page</a>' % self.statusdir
                    )
            request['Content-Type'] = 'text/html'
            request['Content-Length'] = len (message)
            request.push (message)
            now = int (time.time())
            for channel in asyncore.socket_map.keys():
                if channel.__class__ == http_server.http_channel:
                    if channel != request.channel:
                        if (now - channel.creation_time) > channel.zombie_timeout:
                            channel.close()
            request.done()
            
            # Emergency Debug Mode
            # If a server is running away from you, don't KILL it!
            # Move all the AF_INET server ports and perform an autopsy...
            # [disabled by default to protect the innocent]
        elif self.allow_emergency_debug and path == self.statusdir + '/emergency_debug':
            request.push ('<html>Moving All Servers...</html>')
            request.done()
            for channel in asyncore.socket_map.keys():
                if channel.accepting:
                    if type(channel.addr) is type(()):
                        ip, port = channel.addr
                        channel.socket.close()
                        channel.del_channel()
                        channel.addr = (ip, port+10000)
                        fam, typ = channel.family_and_type
                        channel.create_socket (fam, typ)
                        channel.set_reuse_addr()
                        channel.bind (channel.addr)
                        channel.listen(5)
                        
        else:
            m = self.hyper_regex.match (path)
            if m:
                oid = string.atoi (m.group (1))
                for object in self.hyper_objects:
                    if id (object) == oid:
                        if hasattr (object, 'hyper_respond'):
                            object.hyper_respond (self, path, request)
            else:
                request.error (404)
                return
                
    def status (self):
        return producers.simple_producer (
                '<li>Status Extension <b>Hits</b> : %s' % self.hit_counter
                )
        
    def register_hyper_object (self, object):
        if not object in self.hyper_objects:
            self.hyper_objects.append (object)
            
import logger

class logger_for_status (logger.tail_logger):

    def status (self):
        return 'Last %d log entries for: %s' % (
                len (self.messages),
                html_repr (self)
                )
        
    def hyper_respond (self, sh, path, request):
        request['Content-Type'] = 'text/plain'
        messages = self.messages[:]
        messages.reverse()
        request.push (lines_producer (messages))
        request.done()
        
class lines_producer:
    def __init__ (self, lines):
        self.lines = lines
        
    def ready (self):
        return len(self.lines)
        
    def more (self):
        if self.lines:
            chunk = self.lines[:50]
            self.lines = self.lines[50:]
            return string.join (chunk, '\r\n') + '\r\n'
        else:
            return ''
            
class channel_list_producer (lines_producer):
    def __init__ (self, statusdir):
        channel_reprs = map (
                lambda x: '&lt;' + repr(x)[1:-1] + '&gt;',
                asyncore.socket_map.values()
                )
        channel_reprs.sort()
        lines_producer.__init__ (
                self,
                ['<h1>Active Channel List</h1>',
                 '<pre>'
                 ] + channel_reprs + [
                         '</pre>',
                         '<p><a href="%s">Status Report</a>' % statusdir
                         ]
                )
        
        
        # this really needs a full-blown quoter...
def sanitize (s):
    if '<' in s:
        s = string.join (string.split (s, '<'), '&lt;')
    if '>' in s:
        s = string.join (string.split (s, '>'), '&gt;')
    return s
    
def html_repr (object):
    so = sanitize (repr (object))
    if hasattr (object, 'hyper_respond'):
        return '<a href="/status/object/%d/">%s</a>' % (id (object), so)
    else:
        return so
        
def html_reprs (list, front='', back=''):
    reprs = map (
            lambda x,f=front,b=back: '%s%s%s' % (f,x,b),
            map (lambda x: sanitize (html_repr(x)), list)
            )
    reprs.sort()
    return reprs
    
    # for example, tera, giga, mega, kilo
    # p_d (n, (1024, 1024, 1024, 1024))
    # smallest divider goes first - for example
    # minutes, hours, days
    # p_d (n, (60, 60, 24))
    
def progressive_divide (n, parts):
    result = []
    for part in parts:
        n, rem = divmod (n, part)
        result.append (rem)
    result.append (n)
    return result
    
    # b,k,m,g,t
def split_by_units (n, units, dividers, format_string):
    divs = progressive_divide (n, dividers)
    result = []
    for i in range(len(units)):
        if divs[i]:
            result.append (format_string % (divs[i], units[i]))
    result.reverse()
    if not result:
        return [format_string % (0, units[0])]
    else:
        return result
        
def english_bytes (n):
    return split_by_units (
            n,
            ('','K','M','G','T'),
            (1024, 1024, 1024, 1024, 1024),
            '%d %sB'
            )
    
def english_time (n):
    return split_by_units (
            n,
            ('secs', 'mins', 'hours', 'days', 'weeks', 'years'),
            (         60,     60,      24,     7,       52),
            '%d %s'
            )
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.