| @@ -3,16 +3,23 @@ from flask_redis import FlaskRedis | |||||
| import json, abp, markdown | import json, abp, markdown | ||||
| from pprint import pprint | from pprint import pprint | ||||
| import raussendorf | import raussendorf | ||||
| import humanhash | |||||
| DAY = 60*60*24 | |||||
| app = Flask(__name__) | app = Flask(__name__) | ||||
| redis = FlaskRedis(app) | redis = FlaskRedis(app) | ||||
| @app.route("/") | @app.route("/") | ||||
| def index(): | def index(): | ||||
| return render_template("index.html") | |||||
| secret, uuid = humanhash.uuid() | |||||
| return redirect("/{}".format(secret)) | |||||
| @app.route("/graph", methods=["GET", "POST"]) | |||||
| def graph(): | |||||
| @app.route("/<uuid>") | |||||
| def main(uuid): | |||||
| return render_template("index.html", uuid=uuid) | |||||
| @app.route("/<uuid>/graph", methods=["GET", "POST"]) | |||||
| def graph(uuid): | |||||
| if request.method == 'POST': | if request.method == 'POST': | ||||
| # Convert the data to a graph state | # Convert the data to a graph state | ||||
| g = abp.GraphState() | g = abp.GraphState() | ||||
| @@ -22,21 +29,24 @@ def graph(): | |||||
| data = json.dumps(g.to_json(stringify=True)) | data = json.dumps(g.to_json(stringify=True)) | ||||
| # Insert into the database | # Insert into the database | ||||
| redis.execute_command("SET", "graph", data) | |||||
| redis.setex(uuid, data, DAY) | |||||
| # Return success | # Return success | ||||
| return "Posted {} bytes OK".format(len(data)) | return "Posted {} bytes OK".format(len(data)) | ||||
| elif redis.exists(uuid): | |||||
| return redis.get(uuid) | |||||
| else: | else: | ||||
| # Get from the database | |||||
| return redis.get("graph") | |||||
| g = abp.GraphState() | |||||
| data = json.dumps(g.to_json(stringify=True)) | |||||
| redis.setex(uuid, DAY, data) | |||||
| return data | |||||
| @app.route("/edit", methods=["POST"]) | |||||
| def edit(): | |||||
| @app.route("/<uuid>/edit", methods=["POST"]) | |||||
| def edit(uuid): | |||||
| # Load the graph from the database | # Load the graph from the database | ||||
| g = abp.GraphState() | g = abp.GraphState() | ||||
| g.from_json(json.loads(redis.get("graph"))) | |||||
| g.from_json(json.loads(redis.get(uuid))) | |||||
| # Apply the edit to the graph | # Apply the edit to the graph | ||||
| edit = json.loads(request.data) | edit = json.loads(request.data) | ||||
| @@ -66,7 +76,7 @@ def edit(): | |||||
| # New state into JSON and database | # New state into JSON and database | ||||
| data = json.dumps(g.to_json(stringify=True)) | data = json.dumps(g.to_json(stringify=True)) | ||||
| redis.execute_command("SET", "graph", data) | |||||
| redis.setex(uuid, DAY, data) | |||||
| return data | return data | ||||
| @@ -1,4 +1,5 @@ | |||||
| html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-family: monospace; } | |||||
| html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; | |||||
| font-family: monospace; } | |||||
| #node_info { | #node_info { | ||||
| background: rgba(0, 0, 0, .8); | background: rgba(0, 0, 0, .8); | ||||
| color:white; | color:white; | ||||
| @@ -7,23 +8,20 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam | |||||
| position: absolute; | position: absolute; | ||||
| top:5px; | top:5px; | ||||
| left:5px; | left:5px; | ||||
| font-family: monospace; | |||||
| /*font-family: monospace;*/ | |||||
| text-align: center; | text-align: center; | ||||
| font-size:9pt; | |||||
| /*height:15px;*/ | /*height:15px;*/ | ||||
| border-radius:3px; | border-radius:3px; | ||||
| pointer-events: none; | pointer-events: none; | ||||
| } | } | ||||
| #server_info { | #server_info { | ||||
| background-color: black; | |||||
| background-color: rgba(0, 0, 0, .8); | |||||
| color:white; | color:white; | ||||
| padding: 10px; | padding: 10px; | ||||
| font-family: monospace; | |||||
| position: absolute; | position: absolute; | ||||
| top: 10px; | top: 10px; | ||||
| right: 10px; | right: 10px; | ||||
| font-size: 9pt; | |||||
| } | } | ||||
| #node_name { | #node_name { | ||||
| @@ -31,25 +29,21 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam | |||||
| } | } | ||||
| #node_data { | #node_data { | ||||
| background-color: black; | |||||
| background-color: rgba(0, 0, 0, .8); | |||||
| color:white; | color:white; | ||||
| padding: 10px; | padding: 10px; | ||||
| font-family: monospace; | |||||
| position: absolute; | position: absolute; | ||||
| top: 10px; | top: 10px; | ||||
| left: 10px; | left: 10px; | ||||
| font-size: 9pt; | |||||
| } | } | ||||
| #controls { | #controls { | ||||
| background-color: black; | |||||
| background-color: rgba(0, 0, 0, .8); | |||||
| color:white; | color:white; | ||||
| padding: 10px; | padding: 10px; | ||||
| font-family: monospace; | |||||
| position: absolute; | position: absolute; | ||||
| bottom: 10px; | bottom: 10px; | ||||
| left: 10px; | left: 10px; | ||||
| font-size: 9pt; | |||||
| } | } | ||||
| #controls a { | #controls a { | ||||
| @@ -60,6 +54,7 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam | |||||
| margin: 1px; | margin: 1px; | ||||
| display: inline-block; | display: inline-block; | ||||
| text-decoration: none; | text-decoration: none; | ||||
| cursor: pointer; | |||||
| } | } | ||||
| #node_data a { | #node_data a { | ||||
| @@ -70,31 +65,29 @@ html, body { margin: 0; padding: 0; overflow: hidden; font-size: 10pt; font-fam | |||||
| margin: 1px; | margin: 1px; | ||||
| display: inline-block; | display: inline-block; | ||||
| text-decoration: none; | text-decoration: none; | ||||
| cursor: pointer; | |||||
| } | } | ||||
| #version { | #version { | ||||
| color:black; | color:black; | ||||
| padding: 10px; | padding: 10px; | ||||
| font-family: monospace; | |||||
| position: absolute; | position: absolute; | ||||
| bottom: 10px; | bottom: 10px; | ||||
| left: 10px; | left: 10px; | ||||
| font-size: 9pt; | |||||
| } | } | ||||
| #help { | #help { | ||||
| color:black; | |||||
| background-color: rgba(0, 0, 0, .8); | |||||
| color:white; | |||||
| padding: 10px; | padding: 10px; | ||||
| font-family: monospace; | |||||
| position: absolute; | position: absolute; | ||||
| bottom: 10px; | bottom: 10px; | ||||
| right: 10px; | right: 10px; | ||||
| font-size: 9pt; | |||||
| } | } | ||||
| #help a{ | #help a{ | ||||
| color: black; | |||||
| color: white; | |||||
| } | } | ||||
| @@ -11,7 +11,7 @@ api.poll = function() { | |||||
| }; | }; | ||||
| // Send the request | // Send the request | ||||
| xmlhttp.open("GET", "/graph", true); | |||||
| xmlhttp.open("GET", window.location.href+"/graph", true); | |||||
| xmlhttp.send(); | xmlhttp.send(); | ||||
| }; | }; | ||||
| @@ -32,7 +32,7 @@ api.edit = function(edit) { | |||||
| }; | }; | ||||
| // Send the request | // Send the request | ||||
| xmlhttp.open("POST", "/edit", true); | |||||
| xmlhttp.open("POST", window.location.href+"/edit", true); | |||||
| xmlhttp.setRequestHeader("Content-Type", "application/json"); | xmlhttp.setRequestHeader("Content-Type", "application/json"); | ||||
| xmlhttp.send(JSON.stringify(edit)); | xmlhttp.send(JSON.stringify(edit)); | ||||
| } | } | ||||
| @@ -6,5 +6,6 @@ window.onload = function() { | |||||
| gui.prepare(); | gui.prepare(); | ||||
| mouse.prepare(); | mouse.prepare(); | ||||
| editor.prepare(); | editor.prepare(); | ||||
| api.poll(); | |||||
| gui.loop(); | gui.loop(); | ||||
| }; | }; | ||||
| @@ -24,45 +24,33 @@ | |||||
| <div id=node_info class=hidden> </div> | <div id=node_info class=hidden> </div> | ||||
| <div id=server_info class=hidden> </div> | <div id=server_info class=hidden> </div> | ||||
| <!--<div id=version>ABP version 0.4.27</div>--> | |||||
| <div id=node_data class=hidden> | <div id=node_data class=hidden> | ||||
| <div id=node_name></div> | <div id=node_name></div> | ||||
| <ul> | <ul> | ||||
| <li id=node_vop></li> | <li id=node_vop></li> | ||||
| <li>Measure in | <li>Measure in | ||||
| <a href="#" onclick="editor.measureX()">X</a> / | |||||
| <a href="#" onclick="editor.measureY()">Y</a> / | |||||
| <a href="#" onclick="editor.measureZ()">Z</a></li> | |||||
| <a onclick="editor.measureX()">X</a> / | |||||
| <a onclick="editor.measureY()">Y</a> / | |||||
| <a onclick="editor.measureZ()">Z</a></li> | |||||
| <li>Act | <li>Act | ||||
| <a href="#" onclick="editor.hadamard()">Hadamard</a> / | |||||
| <a href="#" onclick="editor.phase()">Phase</a></li> | |||||
| <li><a href="#" onclick="editor.localComplementation()">Invert neighbourhood</a></li> | |||||
| <li><a href="#" onclick="editor.deleteNode()">Delete</a></li> | |||||
| <a onclick="editor.hadamard()">Hadamard</a> / | |||||
| <a onclick="editor.phase()">Phase</a></li> | |||||
| <li><a onclick="editor.localComplementation()">Invert neighbourhood</a></li> | |||||
| <li><a onclick="editor.deleteNode()">Delete</a></li> | |||||
| </ul> | </ul> | ||||
| </div> | </div> | ||||
| <div id=controls> | <div id=controls> | ||||
| <ul> | <ul> | ||||
| <li><a href="#" onclick="editor.clear()">Clear graph</a></li> | |||||
| <li><a href="#" onclick="editor.raussendorf()">Replace with Raussendorf</a></li> | |||||
| <li><a onclick="editor.clear()">Clear graph</a></li> | |||||
| <li><a onclick="editor.raussendorf()">Raussendorf</a></li> | |||||
| <li><a onclick="editor.raussendorf()">Share</a></li> | |||||
| </ul> | </ul> | ||||
| </div> | </div> | ||||
| <div id=help> | <div id=help> | ||||
| <h3>Usage:</h3> | |||||
| Click on the grid to make a new node<br/> | |||||
| Ctrl-click a node to do a Hadamard<br/> | |||||
| Select a node, then shift-click another node to do a CZ<br/> | |||||
| Press space to rotate the grid<br/> | |||||
| <h3>API usage:</h3> | |||||
| GET https://abv.peteshadbolt.co.uk/graph -> JSON<br/> | |||||
| POST JSON -> https://abv.peteshadbolt.co.uk/graph<br/> | |||||
| POST JSON -> https://abv.peteshadbolt.co.uk/edit | |||||
| <p>See <a href="/doc">here</a> for docs.</p> | |||||
| <a href="/doc">Help</a> | |||||
| </div> | </div> | ||||
| </body> | </body> | ||||