Add readme and colors.
This commit is contained in:
		
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
# Why?
 | 
			
		||||
 | 
			
		||||
Sometimes I run long scripts on a remote machine and I want to know when they finish. It's
 | 
			
		||||
not urgent enough that I need a text or toot, but being able to pull up a simple page that
 | 
			
		||||
shows what is done and not done makes it easy to check periodically.
 | 
			
		||||
 | 
			
		||||
# How?
 | 
			
		||||
 | 
			
		||||
This tiny Flask API runs on a server (Raspberry Pi, etc.). It has very basic authentication
 | 
			
		||||
and waits for a curl (or similar) GET request with some small amount of data. The data are
 | 
			
		||||
displayed on a simple web page.
 | 
			
		||||
 | 
			
		||||
The reason for a simple GET request is to make this as code-agnostic as possible. Drop a 
 | 
			
		||||
curl command into R or Python or Go or Ruby or whatever (I assume) and be able to watch 
 | 
			
		||||
whatever data you pass.
 | 
			
		||||
 | 
			
		||||
You can either run with the internal Flask development server or something like gunicorn.
 | 
			
		||||
 | 
			
		||||
# Other Use Cases?
 | 
			
		||||
 | 
			
		||||
I'm sure there are some.
 | 
			
		||||
 | 
			
		||||
# Security?
 | 
			
		||||
 | 
			
		||||
I'm sure this isn't very secure. It has basic data cleaning, string length limits, and
 | 
			
		||||
username/password protection. There is no database--all data are kept in memory and will 
 | 
			
		||||
disappear when the server is stopped. Use at your own risk, don't reuse passwords, and 
 | 
			
		||||
obviously don't pass data that can't be shared openly online. The last part includes things
 | 
			
		||||
like "front_door_unlocked"--use common sense.
 | 
			
		||||
							
								
								
									
										6
									
								
								app.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								app.py
									
									
									
									
									
								
							@@ -10,7 +10,8 @@ app = Flask(__name__)
 | 
			
		||||
 | 
			
		||||
statuses = [
 | 
			
		||||
    {
 | 
			
		||||
        'title': 'curl -u matt:python -i http://localhost:5000/log/api/v1.0/new?title="example_status_no_spaces"',
 | 
			
		||||
        'title': 'app_is_running',
 | 
			
		||||
        'color': "green",
 | 
			
		||||
        'timestamp': datetime.datetime.now().timestamp(),
 | 
			
		||||
        'timestamp_readable': datetime.datetime.now()  
 | 
			
		||||
    }
 | 
			
		||||
@@ -38,6 +39,7 @@ def create_status():
 | 
			
		||||
    
 | 
			
		||||
    status = {
 | 
			
		||||
        'title': safer_title,
 | 
			
		||||
        'color': request.args.get("color"),
 | 
			
		||||
        'timestamp': datetime.datetime.now().timestamp(),
 | 
			
		||||
        'timestamp_readable': datetime.datetime.now()
 | 
			
		||||
    }
 | 
			
		||||
@@ -57,7 +59,7 @@ def get_statuses_raw():
 | 
			
		||||
@app.route('/', methods=['GET'])
 | 
			
		||||
def get_statuses():
 | 
			
		||||
    long_agos = [humanfriendly.format_timespan(datetime.datetime.now().timestamp() - status['timestamp']) for status in statuses[::-1]]
 | 
			
		||||
    return render_template("list.html", 
 | 
			
		||||
    return render_template("index.html", 
 | 
			
		||||
                            statuses = statuses[::-1],
 | 
			
		||||
                            long_agos = long_agos)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
.statuses tr td {
 | 
			
		||||
  border: 1px solid black;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								templates/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<link href="/static/css/style.css" rel="stylesheet">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<div id="countdown"><span id="countdown_numbers"></span> seconds until refresh</div>
 | 
			
		||||
<script>
 | 
			
		||||
(function countdown(remaining) {
 | 
			
		||||
    if(remaining <= 0)
 | 
			
		||||
        location.reload(true);
 | 
			
		||||
    document.getElementById('countdown_numbers').innerHTML = remaining;
 | 
			
		||||
    setTimeout(function(){ countdown(remaining - 1); }, 1000);
 | 
			
		||||
})(15); // n seconds
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<table class = "statuses">
 | 
			
		||||
<tr><th>What Happened?</th><th>When Did It Happen?</th><th>How Long Has It Been?</th></tr>
 | 
			
		||||
  {% for status in statuses %}
 | 
			
		||||
  <tr>
 | 
			
		||||
  <td style="background-color: {{ status.color }}">{{ status.title }}</td><td>{{ status.timestamp_readable }}</td><td>{{ long_agos[loop.index0] }}</td>
 | 
			
		||||
  </tr>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<h2>How does this work?</h2>
 | 
			
		||||
 | 
			
		||||
<p>Send a curl (or similar) request from any script or code and include your username and 
 | 
			
		||||
password (see app.py, @auth.get_password).</p>
 | 
			
		||||
 | 
			
		||||
<code>
 | 
			
		||||
curl -u username:password -i "http://localhost:5000/new?title=a_status_without_spaces_goes_here"
 | 
			
		||||
</code>
 | 
			
		||||
 | 
			
		||||
<p>The entire list of statuses is kept in memory and limited to 1000 (or whatever you set
 | 
			
		||||
it to). If your service or server restarts, the list is wiped out.</p>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<link href="/static/css/style.css" rel="stylesheet">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<table class = "statuses">
 | 
			
		||||
<tr><th>What Happened?</th><th>When Did It Happen?</th><th>How Long Has It Been?</th></tr>
 | 
			
		||||
  {% for status in statuses %}
 | 
			
		||||
  <tr>
 | 
			
		||||
  <td>{{ status.title }}</td><td>{{ status.timestamp_readable }}</td><td>{{ long_agos[loop.index0] }}</td>
 | 
			
		||||
  </tr>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user