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

[php]
# 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 <http://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 httpserver...'
url = 'http://localhost:8036/'
url = 'http://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)
[/php]

Python
CH01 python 簡介ch100 Dev OperationCH29 System 系統CH30 Internet