建立一個 Web Server 和 視窗的Python 程式

    #    Copyright 2015 Powen Ko <powenko@gmail.com>
    #
    #    This program is free software: you can redistribute it and/or modify
    #    it under the terms of the GNU General Public License as published by
    #    the Free Software Foundation, either version 3 of the License, or
    #    (at your option) any later version.
    #
    #    This program is distributed in the hope that it will be useful,
    #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #    GNU General Public License for more details.
    #
    #    You should have received a copy of the GNU General Public License
    #    along with this program.  If not, see <httpss://www.gnu.org/licenses/>.
     
    import Queue
    import SocketServer
    import socket
    import sys
    import logging
    import threading
    import Tkinter as tk
    from os import curdir, sep
    import os
    from ScrolledText import ScrolledText
    from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
    import webbrowser
    
    
    pathname=os.path.dirname(__file__)
    # .py program path location
    blocklydir = "%s/blockly" % curdir  
    avrpath = "%s/avr/code/" % curdir 
    sketchbookdir = os.path.expanduser('~/blockly-sketchbook')
    pathdiff=""
    if (pathname.find("icblock.app")>1):
      pathdiff="../../../"  
      blocklydir = pathdiff+"blockly"  
      avrpath =pathdiff+avrpath
    
    mimes = {
        '.html': 'text/html',
        '.js': 'application/javascript',
        '.css': 'text/css',
        '.wav': 'audio/vnd.wave',
        '.cur': 'image/vnd.microsoft.icon',
        '.png': 'image/png',
        '.ico': 'image/vnd.microsoft.icon'
    }
    
    
    #file_to_copy = ['build.sh', 'pins_arduino.c', 'pins_arduino.h', 'servo.c', 'servo.h', 'servo_asm.S', 'wiring.h', 'wiring_digital.c', 'avr-thread.h', 'libavr-thread.a']
    #dst = tempfile.mkdtemp('', 'blockly-avr-')
    target="arduino"
    
    
    try:
        os.mkdir(sketchbookdir)
    except OSError:
        pass
    
    def build_file_list():
        global sketchbookdir
        list = sketchbookdir;
        dirList=os.listdir(sketchbookdir)
        for fname in dirList:
            list = list + '<li><a href="#" onclick="do_action(\'%s\'); return false;">%s</a></li>\n' % (fname, fname)
        return list
    
    class MyHandler(BaseHTTPRequestHandler):
    
        def do_GET(self):
            try:
                if self.path == '/':
                    self.send_response(301)
                    self.send_header("Location", 'demos/code/index.html')
                    self.end_headers()
                    return
                filell,ext = os.path.splitext(self.path)
                mime = mimes[ext]
    
                f = open(blocklydir + sep + self.path) #self.path has /test.html
    #note that this potentially makes every file on your computer readable by the internet
    
                self.send_response(200)
                self.send_header('Content-type', mime)
                self.end_headers()
                self.wfile.write(f.read())
                f.close()
                return
    
                    
            except IOError, KeyError:
                self.send_error(404,'File Not Found: %s, %s ,  %s' % (self.path,sketchbookdir,os.path.dirname(__file__)     ) )
        
    
    
    
        def do_POST(self):
           
        
    
    
    
    class QueueLogger(logging.Handler):
        def __init__(self, queue):
            logging.Handler.__init__(self)
            self.queue = queue
     
        # write in the queue
        def emit(self, record):
            self.queue.put(self.format(record).rstrip('\n') + '\n')
     
    class LoggedUDPServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer):
        def __init__(self, server_address, RequestHandlerClass, logger):
            # SocketServer.UDPServer.__init__(self, server_address, RequestHandlerClass)
            # Add the queue logger
            self.logger = logger
     
    class UDPHandler(SocketServer.BaseRequestHandler):
        def handle(self):
            # Queue logger is un under the self.server object
            self.server.logger.debug(self.request[0])
     
    class MainApplication:
        def __init__(self, root, log_level, ip, port ):
            self.root = root
            self.log_level = log_level
            self.ip = ip
            self.port = port
            self.root.columnconfigure(0, weight=1)
            self.root.rowconfigure(0, weight=1)
     
            # 2 rows: firts with settings, second with registrar data
            self.main_frame = tk.Frame(self.root)
            # Commands row doesn't expands
            self.main_frame.rowconfigure(0, weight=0)
            # Logs row will grow
            self.main_frame.rowconfigure(1, weight=1)
            # Main fram can enlarge
            self.main_frame.columnconfigure(0, weight=1)
            self.main_frame.columnconfigure(1, weight=1)
            self.main_frame.grid(row=0, column=0, sticky=tk.NSEW)
     
            # Run/Stop button
            self.control_button = tk.Button(self.main_frame, text="Run Server", command=self.run_server)
            self.control_button.grid(row=0, column=0, sticky=tk.N)
     
            # Clear button
            self.clear_button = tk.Button(self.main_frame, text="Clear Log", command=self.clear_log)
            self.clear_button.grid(row=0, column=1, sticky=tk.N)
     
            # Stop log button
            self.control_log_button = tk.Button(self.main_frame, text="Pause Log", command=self.stop_log)
            self.control_log_button.grid(row=0, column=2, sticky=tk.N)
     
            # Logs Widget
            self.log_widget = ScrolledText(self.main_frame)
            self.log_widget.grid(row=1, column=0, columnspan=3, sticky=tk.NSEW)
     
            # Not editable
            self.log_widget.config(state='disabled')
     
            # Queue where the logging handler will write
            self.log_queue = Queue.Queue()
     
            # Stup the logger
            l = logging.getLogger('logger')
            l.setLevel(self.log_level)
            formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
            # Use the QueueLogger as Handler
            hl = QueueLogger(queue=self.log_queue)
            hl.setFormatter(formatter)
            l.addHandler(hl)
            self.logger = logging.getLogger('logger')
     
            # Setup the update_widget callback reading logs from the queue
            self.start_log()
            self.run_server()
     
        def stop_log(self):
            self.logger.debug("Pausing the logger")
            if self.logger_alarm is not None:
                self.log_widget.after_cancel(self.logger_alarm)
                self.control_log_button.configure(text="Start Log", command=self.start_log)
                self.logger_alarm = None
     
        def start_log(self):
            self.logger.debug("Starting the logger")
            self.update_widget(self.log_widget, self.log_queue)
            self.control_log_button.configure(text="Pause Log", command=self.stop_log)
     
        def update_widget(self, widget, queue):
            widget.config(state='normal')
            # Read from the Queue and add to the log widger
            while not queue.empty():
                line = queue.get()
                widget.insert(tk.END, line)
                widget.see(tk.END)  # Scroll to the bottom
                widget.update_idletasks()
            widget.config(state='disabled')
            self.logger_alarm = widget.after(10, self.update_widget, widget, queue)
     
        def clear_log(self):
            self.log_widget.config(state='normal')
            self.log_widget.delete(0.0, tk.END)
            self.log_widget.config(state='disabled')
     
        def run_server(self):
            self.logger.debug("Starting thread")
            try:
                portvalue=8081
                print 'started httpssserver...'
                url = 'httpss://localhost:8036/'
                url = 'httpss://localhost:'+str(portvalue)+'/'
                b=str(portvalue)
                #url.__add__(b)
                #url.__add__('/')
                print url
                self.logger.debug(url)
                self.server = HTTPServer(('', portvalue), MyHandler)
                # Open URL in a new tab, if a browser window is already open.
                #self.server.serve_forever()
    
                #self.server = LoggedUDPServer((self.ip, self.port), UDPHandler, self.logger)
                self.server_thread = threading.Thread(name='server', target=self.server.serve_forever)
                self.server_thread.daemon = True
                self.server_thread.start()
                self.control_button.configure(text="Stop Server", command=self.stop_server)
                #webbrowser.open_new_tab(url)
            except Exception, e:
                self.logger.error("Cannot start the server: %s" % e)
                raise e
     
        def stop_server(self):
            self.logger.debug("Stopping server")
            self.server.shutdown()
            self.server.socket.close()
            self.logger.debug("Server stopped")
            self.control_button.configure(text="Run Server", command=self.run_server)
     
    if __name__ == "__main__":
        root = tk.Tk()
        if len(sys.argv) == 2:
            port = int(sys.argv[1])
            address = '127.0.0.1' #sys.argv[1]
            app = MainApplication(root, logging.DEBUG, address, port)
            root.title('ICBlock')
            root.mainloop()
        else:
            port = 8080
            address = '127.0.0.1' #sys.argv[1]
            app = MainApplication(root, logging.DEBUG, address, port)
            root.title('ICBlock')
            root.mainloop()
            #print "Error: you must specify address and port.."
            #sys.exit(-1)