From 95bf161345ca29269094a51713c60d950c4a887b Mon Sep 17 00:00:00 2001 From: Lukas Puehringer Date: Thu, 16 Mar 2017 15:00:35 -0400 Subject: [PATCH] Removes trailing whitespaces, replaces tabs --- readme.txt | 16 +-- restrictions.tryrepy | 48 ++++----- tr_sandbox.r2py | 144 +++++++++++++------------- tr_webcontroller.r2py | 156 ++++++++++++++-------------- web/css/main.css | 32 +++--- web/index.html | 192 +++++++++++++++++----------------- web/js/tr_repy.js | 234 +++++++++++++++++++++--------------------- 7 files changed, 411 insertions(+), 411 deletions(-) diff --git a/readme.txt b/readme.txt index d802512..b42a2ab 100644 --- a/readme.txt +++ b/readme.txt @@ -29,24 +29,24 @@ Known Issues - Thread Exceptions: A thread exception in one thread does not exit the entire evaluation in a Virutal Namespace. So far exceptions in a thread are caught and logged but the execution of other healthy threads continues. - TCP/UDP listeners are not isolated -A listener registered on one IP:PORT will override another listener previously registered on this IP:PORT - -############ +A listener registered on one IP:PORT will override another listener previously registered on this IP:PORT + +############ Links https://seattle.cs.washington.edu/wiki https://seattle.cs.washington.edu/wiki/ProgrammersPage https://seattle.cs.washington.edu/wiki/RepyApi -############ +############ Description - Editor The editor is always displayed on the left side. You can write Repy code to it and evaluate it on the server. To submit the code press cmd + return (mac), ctrl + return (win), or the submit button beneath the editor window. Until the code has been evaluated, codesubmission is locked. - + - Callargs You can append space separated callarguments in the input line beneath the editor window, when submitting code. - + - Standard Output This displays the output of the program. It gives "real time" feedback. @@ -54,7 +54,7 @@ This displays the output of the program. It gives "real time" feedback. This retrieves and displays the entire log for every submitted and evaluated code of a session - Insert Files -Insert files to the editor window, whether at cursor position or at the top of the editor window. +Insert files to the editor window, whether at cursor position or at the top of the editor window. - Special Characters Insert special characters at cursor position. @@ -67,7 +67,7 @@ Options to customize the editor window. - Read Me this. - + Todo - Network Ressource scheduling diff --git a/restrictions.tryrepy b/restrictions.tryrepy index 1a150b0..ef9c12f 100644 --- a/restrictions.tryrepy +++ b/restrictions.tryrepy @@ -27,38 +27,38 @@ resource connport 63134 call gethostbyname_ex allow call sendmess allow -call stopcomm allow # it doesn't make sense to restrict +call stopcomm allow # it doesn't make sense to restrict call recvmess allow call openconn allow call waitforconn allow -call socket.close allow # let's not restrict -call socket.send allow # let's not restrict -call socket.recv allow # let's not restrict +call socket.close allow # let's not restrict +call socket.send allow # let's not restrict +call socket.recv allow # let's not restrict # open and file.__init__ both have built in restrictions... -call open allow # can write to junk_test.out +call open allow # can write to junk_test.out call file.__init__ allow # can write to junk_test.out -call file.close allow # shouldn't restrict -call file.flush allow # they are free to use -call file.next allow # free to use as well... -call file.read allow # allow read -call file.readline allow # shouldn't restrict -call file.readlines allow # shouldn't restrict -call file.seek allow # seek doesn't restrict -call file.write allow # shouldn't restrict (open restricts) -call file.writelines allow # shouldn't restrict (open restricts) -call sleep allow # harmless -call settimer allow # we can't really do anything smart -call canceltimer allow # should be okay -call exitall allow # should be harmless +call file.close allow # shouldn't restrict +call file.flush allow # they are free to use +call file.next allow # free to use as well... +call file.read allow # allow read +call file.readline allow # shouldn't restrict +call file.readlines allow # shouldn't restrict +call file.seek allow # seek doesn't restrict +call file.write allow # shouldn't restrict (open restricts) +call file.writelines allow # shouldn't restrict (open restricts) +call sleep allow # harmless +call settimer allow # we can't really do anything smart +call canceltimer allow # should be okay +call exitall allow # should be harmless call log.write allow call log.writelines allow -call getmyip allow # They can get the external IP address -call listdir allow # They can list the files they created -call removefile allow # They can remove the files they create -call randomfloat allow # can get random numbers -call getruntime allow # can get the elapsed time -call getlock allow # can get a mutex +call getmyip allow # They can get the external IP address +call listdir allow # They can list the files they created +call removefile allow # They can remove the files they create +call randomfloat allow # can get random numbers +call getruntime allow # can get the elapsed time +call getlock allow # can get a mutex call get_thread_name allow # Allow getting the thread name call VirtualNamespace allow # Allow using VirtualNamespace's diff --git a/tr_sandbox.r2py b/tr_sandbox.r2py index bd4483f..183fe6e 100644 --- a/tr_sandbox.r2py +++ b/tr_sandbox.r2py @@ -19,10 +19,10 @@ class Sandbox: A Sandbox is an isolated space that each user receives when requesting the Try Repy webinterface. Each Sandbox has its own context to evaluate Repy code using VitualNamespaces and some logging facilities. - + Additionally the Sandbox wraps used Repy functions, mainly in order to isolate it from other Sandboxes. - + Creation Sandbox(user_id, context_dictionary, global_runtime) @@ -31,33 +31,33 @@ class Sandbox: Retrieve Current Log Buffer Sandbox.getLog() ... - """ - + """ + def __init__(self, user_id, context, global_runtime): """ Sandbox Constructor It wraps the Sandboxes Context Functions and instantiates variables and locks for logging and thread accounting. - - + + user_id (string) context (dict) A copy of a clean context, in which global functions dedicated to the webcontroller are not included. global_runtime (float) Used to wrap the Sandboxes runtime. - - """ + + """ self.user = user_id self.context = context - + # Prepare the sandbox context self.context_wrap() self.start_time = getruntime() - global_runtime - + self.log = {} self.log_lock = createlock() @@ -65,25 +65,25 @@ class Sandbox: self.tmp_output_buffer = "" self.lock_output_buffer = createlock() - + # Used for thread accounting self.thread_count = 0 self.thread_lock = createlock() self.thread_accounting_lock = createlock() - - - + + + def my_log(self, *args): """ Override The Repy log function to safe the evaluation output to a log dictionary and a current log buffer. - + *args The output which would be normally written to stdout. - """ + """ self.log_lock.acquire(True) for arg in args: if arg != self: @@ -91,8 +91,8 @@ class Sandbox: self.write_output_buffer( (str(arg) + " ") ) self.log[self.tmp_logtime]["output"] += "\n" self.write_output_buffer("\n") - self.log_lock.release() - + self.log_lock.release() + def context_wrap(self): """ @@ -104,85 +104,85 @@ class Sandbox: Additionally we wrap most of the repy functions to perform according to our custom needs. - """ + """ #Initialize clean mycontext dict and callargs list self.context["mycontext"] = {} self.context["callargs"] = [] - + ## # General wrappers - + def wrapped_log(*args): self.my_log(*args) self.context["log"] = wrapped_log - + def wrapped_getruntime(): return (getruntime() - self.start_time) self.context["getruntime"] = wrapped_getruntime - - # This prevents user from kill the entire Application. + + # This prevents user from kill the entire Application. def wrapped_exitall(): pass self.context["exitall"] = wrapped_exitall ## # File wrappers - + def wrapped_listdir(): return tr_listdir(self.user) self.context["listdir"] = wrapped_listdir - + def wrapped_open(*args): return tr_open(self.user, *args) self.context["open"] = wrapped_open - + def wrapped_removefile(*args): return tr_removefile(self.user, *args) self.context["removefile"] = wrapped_removefile - + ## # Timer wrappers - + def wrapped_settimer(time, callbackfunction, args): self.thread_register() - + def wrapped_callbackfunction(*args): try: callbackfunction(*args[0]) except Exception, e: # What do I do with this exception? # A caught exception should bring the programm down. - # But for the moment it is only printed to the Shell + # But for the moment it is only printed to the Shell # were the webcontroller is called. error_message = "ThreadException: " + str(e) + \ "\nCaution: Other threads could still be running!" self.my_log(error_message) self.thread_deregister() - + return settimer(time, wrapped_callbackfunction, [args]) self.context['settimer'] = wrapped_settimer - + def wrapped_canceltimer(timerhandle): ret = canceltimer(timerhandle) if ret: self.thread_deregister() return ret self.context['canceltimer'] = wrapped_canceltimer - + ## # Network wrappers - + def wrapped_stopcomm(commhandle): ret = stopcomm(commhandle) if ret: self.thread_deregister() return ret self.context['stopcomm'] = wrapped_stopcomm - - + + def wrapped_recvmess(localip, localport, function): - self.thread_register() # This registers the listening thread - + self.thread_register() # This registers the listening thread + def wrapped_callback_udp(remIP, remport, message, commhandle): self.thread_register() try: @@ -190,20 +190,20 @@ class Sandbox: except Exception, e: # What do I do with this exception? # A caught exception should bring the programm down. - # But for the moment it is only printed to the Shell + # But for the moment it is only printed to the Shell # were the webcontroller is called. error_message = "ThreadException: " + str(e) + \ "\nCaution: Other threads could still be running!" self.my_log(error_message) self.thread_deregister() - + return recvmess(localip, localport, wrapped_callback_udp) self.context['recvmess'] = wrapped_recvmess - - + + def wrapped_waitforconn(ip, port, callbackfunction): self.thread_register() - + def wrapped_callback_tcp(remip, remport, so, thishandle, listenhandle): self.thread_register() try: @@ -211,90 +211,90 @@ class Sandbox: except Exception, e: # What do I do with this exception? # A caught exception should bring the programm down. - # But for the moment it is only printed to the Shell + # But for the moment it is only printed to the Shell # were the webcontroller is called. error_message = "ThreadException: " + str(e) + \ "\nCaution: Other threads could still be running!" self.my_log(error_message) log("Exception: " + str(e)) self.thread_deregister() - + return waitforconn(ip, port, wrapped_callback_tcp) self.context['waitforconn'] = wrapped_waitforconn - + # This makes sure, that the _context dict Sandboxes context # is not a reference shared with other Sandboxes contexti self.context["_context"] = self.context def evaluate_repy(self, user_code, user_callargs): - + # Reset the current outputbuffer self.tmp_output_buffer = "" - + # Ceate new logentry with a timestamp as key - # This thimestamp is temporarily stored as attribute to access it + # This thimestamp is temporarily stored as attribute to access it # in the loggin wrapper. self.tmp_logtime = self.context["getruntime"]() self.log[self.tmp_logtime] = {} self.log[self.tmp_logtime]["code"] = user_code self.log[self.tmp_logtime]["output"] = "" self.context["callargs"] = user_callargs - + try: # Create a new VirtualNamespace for the code # and evaluate it in the Sandboxes context. tmp_virt = createvirtualnamespace(user_code, "tryrepy") tmp_virt.evaluate(self.context) - + except Exception, e: - + # This message is written to the log and the output buffer. error_message = "MainThreadException: " + str(e) + \ "\nCaution: Other threads could still be running!" - + self.my_log(error_message) - - + + # Wait, maybe a thread is about to register. - sleep(0.5) + sleep(0.5) # The last active not-main thread will release this lock. # Until then, the main (this) thread is blocked. if self.thread_count: self.thread_lock.acquire(True) self.thread_lock.release() - + # Read the remaining output buffer. - # Nothing should be written to the buffer afterwards. + # Nothing should be written to the buffer afterwards. output = self.read_output_buffer() - + # Return what is left of the output buffer. return output - - + + def read_output_buffer(self): """ Safely empty the output buffer. - + output (string) The current output buffer. - """ + """ self.lock_output_buffer.acquire(True) output = self.tmp_output_buffer self.tmp_output_buffer = "" self.lock_output_buffer.release() return output - - + + def write_output_buffer(self, data): """ Safely write to the output buffer. - + data (string) The output that would be usually written to stdout. @@ -311,7 +311,7 @@ class Sandbox: Return the entire current Sandbox log. XXX: Is this problematic? If it is only read. XXX: There should be no race condition?? - + log_dict (dict) @@ -325,7 +325,7 @@ class Sandbox: If it is the first thread a lock is acquired. The lock makes sure that the main thread waits until all threads are terminated and not till then signals - that the entire evaluation has terminated. + that the entire evaluation has terminated. """ self.thread_accounting_lock.acquire(True) @@ -333,15 +333,15 @@ class Sandbox: self.thread_lock.acquire(True) self.thread_count = self.thread_count + 1 self.thread_accounting_lock.release() - - + + def thread_deregister(self): """ Safely account that a thread of the current evaluation has terminated. If it was the last thread besides the main thread, the lock is released which means, the main - thread can signal terminated of the entire evaluation. + thread can signal terminated of the entire evaluation. """ self.thread_accounting_lock.acquire(True) diff --git a/tr_webcontroller.r2py b/tr_webcontroller.r2py index e2289b4..c11bc49 100644 --- a/tr_webcontroller.r2py +++ b/tr_webcontroller.r2py @@ -13,7 +13,7 @@ This component is the dispatcher for the Try Repy webinterface. It handels HTTP requests from the webfronted, does user handling and instantiates per user sandboxes. - + Requests can be: HTTP Filerequests responds with HTML, CSS, JS files @@ -47,16 +47,16 @@ dy_import_module_symbols("random.r2py") def read_and_decode_form_data(datastream): """ - Reads the url-encoded Ajax posted Repy code + optional + Reads the url-encoded Ajax posted Repy code + optional callarguments and decodes it. - + datastream (string) Url-encoded HTTP datastream. - + data_dictionary (dict) - contains entries for callarguments and code. + contains entries for callarguments and code. """ data_urlencoded = "" @@ -65,13 +65,13 @@ def read_and_decode_form_data(datastream): data_urlencoded += new_chunk if len(new_chunk) == 0: break - + # Actually this is the urllib_unquote_parameters method, # but unlike the original one, mine does not call urllib_unquote_plus. - + keyvalpairs = data_urlencoded.split("&") data_dict = {} - + for quotedkeyval in keyvalpairs: # Throw ValueError if there is more or less than one "=". quotedkey, quotedval = quotedkeyval.split("=") @@ -80,24 +80,24 @@ def read_and_decode_form_data(datastream): val = val.strip() if key == "user_callargs": val = val.split(" ") - data_dict[key] = val - + data_dict[key] = val + return data_dict - - + + def exist_user(http_request_dict): """ - Checks if the http_request_dict contains a querystring that is + Checks if the http_request_dict contains a querystring that is an existing user id, with an according sandbox. - + http_request_dict (dict) - + True/False """ - + if http_request_dict["querystr"] in mycontext["user_dict"].keys(): return True else: @@ -114,13 +114,13 @@ def serve_user(): JavaScript Code (string) """ - + user_id = str(random_randint(0, 2**30)) mycontext["lock_user_dict"].acquire(True) mycontext["user_dict"][user_id] = \ Sandbox(user_id, mycontext['clean_user_context'].copy(), getruntime()) mycontext["lock_user_dict"].release() - + return "var g_user_id = " + user_id + ";" @@ -128,23 +128,23 @@ def make_response(status, message): """ Generates a http_response_dict with variable message and statuscode. - + status (int) HTTP status message. message (string) HTTP payload - + http_response_dict (dict) - """ - - http_response_dict = {"version": "1.1", + """ + + http_response_dict = {"version": "1.1", "statuscode": int(status), "statusmsg": "OK", "headers": {"Server": "TryREPY"}, "message" : message} - + return http_response_dict @@ -155,39 +155,39 @@ def serve_log(user_id): Since the sandbox log dict is not chronologically orderd, the sorting is done here. The code and the output elements in the JSON string are urllib_quoted. - + user_id (string) - + log_string (string) Urllib_quoted JSON String, containing the user's entire sandbox log. - """ + """ log_dict = {} log_time_list = [] log_string = "" log_html = "" - + mycontext["lock_user_dict"].acquire(True) - + # log_dict format # log { "" : { code" : "", "output" : "" }, .. } log_dict = mycontext["user_dict"][user_id].get_log() - + mycontext["lock_user_dict"].release() - + # The log_dicts keys are timestamps. The log_time_list is used to sort # the unorderd dictionary. log_time_list = log_dict.keys() log_time_list.sort() - + # Create a JSON object - this is awesome :) - + log_string = "{'entire_log' : [ " for log_time in log_time_list: - + log_string += "{" + \ "'logtime':'" + str(log_time) + "', " + \ "'repycode':'" + urllib_quote(str(log_dict[log_time]["code"]) ) + "', " + \ @@ -195,7 +195,7 @@ def serve_log(user_id): "}," log_string += " ] }" - + return log_string @@ -204,116 +204,116 @@ def serve_code(data_dict, user_id): Passes the user posted Repy code + optional callarguments to the sandbox where it is evaluated. It returns the remaining part of the outputbuffer. - + data_dict (dict) A dictionary with user_code and user_callargs user_id - + output (string) A urllib_quoted string of the remaining part of the outputbuffer. - """ - - # Calls sandbox's evaluate_repy method and receives the ouput. + """ + + # Calls sandbox's evaluate_repy method and receives the ouput. output = mycontext["user_dict"][user_id].evaluate_repy \ (data_dict["user_code"], data_dict["user_callargs"]) - + return urllib_quote(output) - + def serve_output_buffer(user_id): """ Calls sandbox's read_output_buffer for the specified user. - If the ouputbuffer is empty, it waits a second and retries + If the ouputbuffer is empty, it waits a second and retries reading 5 times. This reduces ajax polling frequency. - If the buffer stays empty it returns an empty string, + If the buffer stays empty it returns an empty string, else the output_buffer's content. - + user_id - + output (string) A urllib_quoted string of the current outputbuffer. - """ - + """ + for count in range(0,5): # This could be parameterized when the webcontroller is called. sleep(1) output = mycontext["user_dict"][user_id].read_output_buffer() - + if output: return urllib_quote(output) - + return urllib_quote("") - + def serve_file(virtual_path): """ Reads web files (HTML, CSS, JS) form the vessel and returns it to the HTTP requester. - + It explicitly uses the tr_fileabstraction functions/methods for filename translation. See tr_fileabstraction for further information. - + virtual_path(string) The path of a file, how it is known to the web application. - + content_file(string) - - """ - + + """ + # If root is requestd, index.html is used instead. if virtual_path == "/": virtual_path = "/index.html" if virtual_path.startswith("/"): virtual_path = virtual_path.lstrip("/") - + # Calling functions in tr_fileabstraction.repy tmp_file = tr_open("system", virtual_path) content_file = tmp_file.readat(None, 0) tmp_file.close() - + return content_file def serve(http_request_dict): """ - The serve dispatcher calls, checks for the type of request + The serve dispatcher calls, checks for the type of request and forwards it to the according function. It expects the message's content as return value. - + Possible requests are: POST request containing repy code, requesting code evaluation GET request with prefix "/getOutput", requesting output buffer GET request with prefix "/getLog", requesting sandbox log GET request with prefix "/js/tr_repy_user.js", requesting for new user_id GET request web files - + http_request_dict - + http_response_dict - """ + """ # Print the http_request_dict to the console. # log(http_request_dict) - + # The message that will be responded. message = "" - - # Serve Code if user exists. + + # Serve Code if user exists. if (http_request_dict["verb"].upper() == "POST"): if exist_user(http_request_dict): data_dict = read_and_decode_form_data(http_request_dict["datastream"]) message = serve_code(data_dict, http_request_dict['querystr']) else: message = "You currently have no sandbox. Reload website!" - + # Serve current output buffer if user exists elif (http_request_dict["verb"].upper() == "GET") and \ http_request_dict["path"].startswith("/getOutput"): @@ -321,7 +321,7 @@ def serve(http_request_dict): message = serve_output_buffer(http_request_dict['querystr']) else: message = "" - + # Serve log if user exists elif (http_request_dict["verb"].upper() == "GET") and \ http_request_dict["path"].startswith("/getLog"): @@ -330,39 +330,39 @@ def serve(http_request_dict): message = serve_log(http_request_dict['querystr']) else: message = "" - + # Called in index.html, instantiates new user id and returns a js variable elif (http_request_dict["verb"].upper() == "GET") and \ http_request_dict["path"].startswith("/js/tr_repy_user.js"): message = serve_user() - + # This looks for the requested file in the vessel elif (http_request_dict["verb"].upper() == "GET"): message = serve_file(http_request_dict["path"]) - - # Is this case even possible? + + # Is this case even possible? else: message = "Get Lost!" http_response_dict = make_response(200, message) - + return http_response_dict if callfunc == "initialize": - + # These are currently the only two global variables. # The user_dict contains all existing sandboxes with their user_id # as key. - + try: port = int(callargs[0]) except: log("Needs argument !") - + else: #port = 63134 - + mycontext["user_dict"] = {} # The locks handles race conditions when the user_dict is accessed. mycontext["lock_user_dict"] = createlock() diff --git a/web/css/main.css b/web/css/main.css index e9ea027..3865593 100644 --- a/web/css/main.css +++ b/web/css/main.css @@ -42,20 +42,20 @@ body { #header { text-align: center; - + width: 100%; height: 70px; - + border: 1px solid white; border-bottom: 2px solid black; - + background-image: -moz-linear-gradient(top, #FFFFFF, #ECECED); background: -webkit-gradient(linear, 0 50%, 0 100%, from(#FFFFFF), to(#ECECED)); } /*********************** * NAVIGATION -* Navigation table with JavaScript support to toggle appropriate elements +* Navigation table with JavaScript support to toggle appropriate elements * when clicked. ************************/ @@ -65,10 +65,10 @@ body { #toggle_bar td { text-align: center; - + width: 135px; height: 40px; - + border: 2px solid black; border-top: 0px; } @@ -78,10 +78,10 @@ body { * In this DIV ace (java script) displays the text editor. ************************/ -#editor { +#editor { /* Position property is required in order to use the ACE editor */ - position: absolute; - + position: absolute; + width: 50%; top: 130px; bottom: 60px; @@ -97,18 +97,18 @@ body { * snippet_container: repy code snippets (insert on click) * option_container: Editor View Options * readme_container: Usage Information - + ************************/ #right_box { /* Absolute, to stay consistent with the required editor positioning. */ position: absolute; overflow: auto; - + width: 48%; top: 130px; bottom: 60px; - + left: 51%; } @@ -158,7 +158,7 @@ body { #snippets td { padding: 20px; } - + #snippets td:hover { font-size: larger; @@ -181,13 +181,13 @@ body { #footer { /* Absolute, to stay consistent with the required editor positioning. */ position: absolute; - + width: 99%; height: 58px; bottom: 0px; - + border-top: 2px solid black; - + background-image: -moz-linear-gradient(bottom, #FFFFFF, #ECECED); background: -webkit-gradient(linear, 0 50%, 0 100%, from(#ECECED), to(#FFFFFF)); } diff --git a/web/index.html b/web/index.html index bdb3fc7..b968a41 100644 --- a/web/index.html +++ b/web/index.html @@ -18,11 +18,11 @@ - + TryRepy - + - - - - - - - -
Standard Output Session Log Insert Files Special Characters Code Snippets Editor Options Read Me
- -
for count in range (0, 10): @@ -125,34 +125,34 @@

Try Repy!

readme_container: usage information -->
- -

Standard Output

(here comes the output)
-
+
- + - - - - - - - + + +
-