# 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)