BaseReader.py :  » Network » Grail-Internet-Browser » grail-0.6 » 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 » Network » Grail Internet Browser 
Grail Internet Browser » grail 0.6 » BaseReader.py
"""Base reader class -- read from a URL in the background."""

import sys
import string
from Tkinter import *
import urlparse
import grailutil


# Default tuning parameters
# BUFSIZE = 8*1024                      # Buffer size for api.getdata()
BUFSIZE = 512                           # Smaller size for better response
SLEEPTIME = 100                         # Milliseconds between regular checks

class BaseReader:

    """Base reader class -- read from a URL in the background.

    Given an API object, poll it until it completes or an
    unrecoverable error occurs.

    Derived classes are supposed to override the handle_*() methods to
    do something meaningful.

    The sequence of calls made to the stop and handle_* functions can
    be expressed by a regular expression:

    (meta data* stop (eof | error) | stop handle_error)

    """

    # Tuning parameters
    sleeptime = SLEEPTIME

    def __init__(self, context, api):
        self.context = context
        self.api = api
        self.callback = self.checkmeta
        self.poller = self.api.pollmeta
        self.bufsize = BUFSIZE
        
        # Stuff for status reporting
        self.nbytes = 0
        self.maxbytes = 0
        self.shorturl = ""
        self.message = "waiting for socket"

        self.context.addreader(self)

        self.fno = None   # will be assigned by start
        self.killed = None

        # Only http_access has delayed startup property.
        # Second argument would allow implementation of persistent
        # connections.
        try:
            self.api.register_reader(self.start, self.checkapi)
        except AttributeError:
            # if the protocol doesn't do that
            ok = 0
            try:
                self.start()
                ok = 1
            finally:
                if not ok:
                    if self.context:
                        self.context.rmreader(self)

    def start(self):
        # when the protocol API is ready to go, it tells the reader
        # to get busy
        self.message = "awaiting server response"
        if self.killed:
            print "start() called after a kill"
            return
        self.fno = self.api.fileno()
        if TkVersion == 4.0 and sys.platform == 'irix5':
            if self.fno >= 20: self.fno = -1 # XXX for SGI Tk OPEN_MAX bug

        if self.fno >= 0:
            tkinter.createfilehandler(
                self.fno, tkinter.READABLE, self.checkapi)
        else:
            # No fileno() -- check every 100 ms
            self.checkapi_regularly()

        # Delete pervious context local protocol handlers
        # We've gotten far enough into the next page without errors
        if self.context:
            self.context.remove_local_api_handlers()

    def __str__(self):
        if self.maxbytes:
            percent = self.nbytes*100/self.maxbytes
            status = "%d%% of %s read" % (percent,
                                          grailutil.nicebytes(self.maxbytes))
        elif not self.nbytes:
            status = self.message
        else:
            status = "%s read" % grailutil.nicebytes(self.nbytes)
        if self.api and self.api.iscached():
            status = status + " (cached)"
        if self.api and not self.shorturl:
            tuple = urlparse.urlparse(self.api._url_)
            path = tuple[2]
            i = string.rfind(path[:-1], '/')
            if i >= 0:
                path = path[i+1:]
            self.shorturl = path or self.api._url_
        return "%s: %s" % (self.shorturl, status)

    def __repr__(self):
        return "%s(...%s)" % (self.__class__.__name__, self.api)

    def update_status(self):
        self.context.new_reader_status() # Will call our __str__() method

    def update_maxbytes(self, headers):
        self.maxbytes = 0
        if headers.has_key('content-length'):
            try:
                self.maxbytes = string.atoi(headers['content-length'])
            except string.atoi_error:
                pass
        self.update_status()

    def update_nbytes(self, data):
        self.nbytes = self.nbytes + len(data)
        self.update_status()

    def kill(self):
        self.killed = 1
        self.stop()
        self.handle_error(-1, "Killed", {})

    def stop(self):
        if self.fno >= 0:
            fno = self.fno
            self.fno = -1
            tkinter.deletefilehandler(fno)

        self.callback = None
        self.poller = None

        if self.api:
            self.api.close()
            self.api = None

        if self.context:
            self.context.rmreader(self)
            self.context = None

    def checkapi_regularly(self):
        if not self.callback:
##          print "*** checkapi_regularly -- too late ***"
            return
        self.callback()
        if self.callback:
            sleeptime = self.sleeptime
            if self.poller and self.poller()[1]: sleeptime = 0
            self.context.root.after(sleeptime, self.checkapi_regularly)

    def checkapi(self, *args):
        if not self.callback:
            print "*** checkapi -- too late ***"
            if self.fno >= 0:
                fno = self.fno
                self.fno = -1
                tkinter.deletefilehandler(fno)
            return
        try:
            self.callback()                     # Call via function pointer
        except:
            if self.context and self.context.app:
                app = self.context.app
            else:
                app = grailutil.get_grailapp()
            app.exception_dialog("in BaseReader")
            self.kill()

    def checkmeta(self):
        self.message, ready = self.api.pollmeta()
        if ready:
            self.getapimeta()

    def checkdata(self):
        self.message, ready = self.api.polldata()
        if ready:
            self.getapidata()

    def getapimeta(self):
        errcode, errmsg, headers = self.api.getmeta()
        self.callback = self.checkdata
        self.poller = self.api.polldata
        if headers.has_key('content-type'):
            content_type = headers['content-type']
        else:
            content_type = None
        if headers.has_key('content-encoding'):
            content_encoding = headers['content-encoding']
        else:
            content_encoding = None
        self.content_type = content_type
        self.content_encoding = content_encoding
        self.update_maxbytes(headers)
        self.handle_meta(errcode, errmsg, headers)
        if self.callback:
            self.callback()             # XXX Handle httpAPI readahead

    def getapidata(self):
        data = self.api.getdata(self.bufsize)
        if not data:
            self.handle_eof()
            self.stop()
            return
        self.update_nbytes(data)
        self.handle_data(data)

    def geteverything(self):
        if self.api:
            if self.callback == self.checkmeta:
                self.getapimeta()
            while self.api:
                self.getapidata()

    # Derived classes are expected to override the following methods

    def handle_meta(self, errcode, errmsg, headers):
        # May call self.stop()
        self.update_maxbytes(headers)
        if errcode != 200:
            self.stop()
            self.handle_error(errcode, errmsg, headers)

    def handle_data(self, data):
        # May call self.stop()
        pass

    def handle_error(self, errcode, errmsg, headers):
        # Called after self.stop() has been called
        pass

    def handle_eof(self):
        # Called after self.stop() has been called
        pass
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.