/ webapp.py
webapp.py
  1  #!/usr/bin/python
  2  # -*- coding: utf-8 -*-
  3  # 
  4  # Copyright © 2013 Jeff Epler <jepler@unpythonic.net>
  5  # 
  6  # This program is free software; you can redistribute it and/or modify
  7  # it under the terms of the GNU General Public License as published by
  8  # the Free Software Foundation; either version 2 of the License, or
  9  # (at your option) any later version.
 10  # 
 11  # This program is distributed in the hope that it will be useful,
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  # GNU General Public License for more details.
 15  # 
 16  # You should have received a copy of the GNU General Public License
 17  # along with this program; if not, write to the Free Software
 18  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  # 
 20  import subprocess
 21  import threading
 22  import sys
 23  import os
 24  import cgi
 25  import traceback
 26  import errno
 27  import ana
 28  
 29  d = ana.from_binary('dict.bin')
 30  
 31  def query(pi):
 32      return d.run(pi)
 33  
 34         
 35  # Every WSGI application must have an application object - a callable
 36  # object that accepts two arguments. For that purpose, we're going to
 37  # use a function (note that you're not limited to a function, you can
 38  # use a class for example). The first argument passed to the function
 39  # is a dictionary containing CGI-style envrironment variables and the
 40  # second variable is the callable object (see PEP 333).
 41  def anagram_app(environ, start_response):
 42      status = '200 OK' # HTTP Status
 43  
 44      pi = environ['QUERY_STRING']
 45      pi = cgi.parse_qs(pi)
 46      plain = pi.get('p', False)
 47      if pi:
 48          pi = pi.get('q', [''])[-1]
 49      else:
 50          pi = ''
 51  
 52      if plain:
 53          headers = [('Content-type', 'application/octet-stream')] # HTTP Headers
 54      else:
 55          headers = [('Content-type', 'text/html')] # HTTP Headers
 56      start_response(status, headers)
 57  
 58      if not plain:
 59          yield '''<!DOCTYPE html>
 60  <html>
 61  <meta charset="UTF-8">
 62  <meta name="viewport" content="width=device-width">
 63  <head>
 64  <title>Surly Anagram Server</title>
 65  <style>
 66  @media screen and (min-width: 680px) { #cheatsheet { float: right; } }
 67  #cheatsheet { font-size: 71%%; cursor: pointer; }
 68  #cheatsheet table, #cheatsheet caption { background: #d9d9d9; color: #000; }
 69  #cheatsheet.hidden { cursor: zoom-in; }
 70  #cheatsheet caption:after { content: "\\a0«" }
 71  #cheatsheet.hidden caption:after { content: "\\a0»" }
 72  #cheatsheet.hidden tbody { display: none; }
 73  //#cheatsheet { float: right; }
 74  #cheatsheet th { text-align: left }
 75  #cheatsheet caption { font-weight: bold; }
 76  </style>
 77  </head>
 78  <body>
 79  <div id="cheatsheet">
 80  <table>
 81  <caption>Cheatsheet</caption>
 82  <tr><th>letters... <td> Letters available to anagram
 83  <tr><th>=word <td> word must be in result
 84  <tr><th>&gt;n <td> words must contain at least n letters
 85  <tr><th>&lt;n <td> words must contain at most n letters
 86  <tr><th>' <td> words with apostrophes are considered
 87  <tr><th>n <td> choose a word with exactly n letters
 88  <tr><th>-n <td> display at most n results (limit 1000)
 89  <tr><th>? <td> display candidate words, not whole phrases
 90  <tr><td colspan=2>In ajax mode, hit enter or click "anagram" to do get full results
 91  <tr><td colspan=2>Source (web app and unix commandline program) on
 92   <a href="https://github.com/jepler/anagram">github</a>
 93  </table>
 94  </div>
 95              
 96  <form id="f"><input type="text" id="query" name="q" value="%s">
 97  <input type="submit" value="anagram">
 98  <script>document.getElementById("query").focus()</script>
 99  </form>
100  <pre id="results">''' % cgi.escape(pi, True)
101  
102      if pi:
103  	if plain: e = lambda x: x
104  	else: e = cgi.escape
105  	yield '# Query: ' + e(repr(pi)) + '\n'
106  
107          for row in query(pi):
108              yield e(row) + '\n'
109  
110      if not plain:
111          yield '''
112  </pre>
113  <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
114  <script src="anagram.js"></script>
115  <script>
116  $("#cheatsheet").click(function() { $(this).toggleClass("hidden"); })
117  </script>
118  </body></html>'''
119  
120  from flup.server.fcgi import WSGIServer
121  WSGIServer(anagram_app).run()