Update storage.py to use ndb instead of db.

Back-ports from Blockly Games:
* db is old and busted, ndb is the new hotness (there’s no known
difference, just pointless API churn).
* Use SHA1 which is consistent, rather than Python’s hash() which has
started changing between executions.  This stops duplicate programs
from being stored.
* Restructure so that storage.py can be used as a library, with
xmlToKey and keyToXml being callable by external programs.
* Use print function compatible with Python 3.
This commit is contained in:
Neil Fraser
2018-04-19 14:36:54 -07:00
committed by Neil Fraser
parent 42e229fb4c
commit 488539f636
2 changed files with 28 additions and 25 deletions

View File

@@ -1,2 +1,3 @@
print("Status: 302")
print("Status: 301")
print("Location: /static/demos/index.html")
print("")

View File

@@ -22,35 +22,32 @@ limitations under the License.
__author__ = "q.neutron@gmail.com (Quynh Neutron)"
import cgi
import hashlib
from random import randint
from google.appengine.ext import db
from google.appengine.api import memcache
import logging
from google.appengine.ext import ndb
print "Content-Type: text/plain\n"
def keyGen():
# Generate a random string of length KEY_LEN.
KEY_LEN = 6
CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1.
CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1.
max_index = len(CHARS) - 1
return "".join([CHARS[randint(0, max_index)] for x in range(KEY_LEN)])
class Xml(db.Model):
class Xml(ndb.Model):
# A row in the database.
xml_hash = db.IntegerProperty()
xml_content = db.TextProperty()
xml_hash = ndb.IntegerProperty()
xml_content = ndb.TextProperty()
forms = cgi.FieldStorage()
if "xml" in forms:
def xmlToKey(xml_content):
# Store XML and return a generated key.
xml_content = forms["xml"].value
xml_hash = hash(xml_content)
lookup_query = db.Query(Xml)
lookup_query.filter("xml_hash =", xml_hash)
xml_hash = long(hashlib.sha1(xml_content).hexdigest(), 16)
xml_hash = int(xml_hash % (2 ** 64) - (2 ** 63))
lookup_query = Xml.query(Xml.xml_hash == xml_hash)
lookup_result = lookup_query.get()
if lookup_result:
xml_key = lookup_result.key().name()
xml_key = lookup_result.key.string_id()
else:
trials = 0
result = True
@@ -59,27 +56,32 @@ if "xml" in forms:
if trials == 100:
raise Exception("Sorry, the generator failed to get a key for you.")
xml_key = keyGen()
result = db.get(db.Key.from_path("Xml", xml_key))
xml = db.Text(xml_content, encoding="utf_8")
row = Xml(key_name = xml_key, xml_hash = xml_hash, xml_content = xml)
result = Xml.get_by_id(xml_key)
row = Xml(id = xml_key, xml_hash = xml_hash, xml_content = xml_content)
row.put()
print xml_key
return xml_key
if "key" in forms:
def keyToXml(key_provided):
# Retrieve stored XML based on the provided key.
key_provided = forms["key"].value
# Normalize the string.
key_provided = key_provided.lower().strip()
# Check memcache for a quick match.
xml = memcache.get("XML_" + key_provided)
if xml is None:
# Check datastore for a definitive match.
result = db.get(db.Key.from_path("Xml", key_provided))
result = Xml.get_by_id(key_provided)
if not result:
xml = ""
else:
xml = result.xml_content
# Save to memcache for next hit.
if not memcache.add("XML_" + key_provided, xml, 3600):
logging.error("Memcache set failed.")
print xml.encode("utf-8")
memcache.add("XML_" + key_provided, xml, 3600)
return xml.encode("utf-8")
if __name__ == "__main__":
print("Content-Type: text/plain\n")
forms = cgi.FieldStorage()
if "xml" in forms:
print(xmlToKey(forms["xml"].value))
if "key" in forms:
print(keyToXml(forms["key"].value))