Merge pull request #2 from Xe/ref/nim-rewrite

Rewrite the server side in Nim
This commit is contained in:
Christine Dodrill 2015-08-13 21:06:32 -07:00
commit 97dbe29bca
7 changed files with 164 additions and 117 deletions

2
.gitignore vendored
View File

@ -59,3 +59,5 @@ docs/_build/
# PyBuilder
target/
ponyapi
nimcache

View File

@ -1,14 +1,15 @@
FROM python:2.7.10
FROM coopernurse/docker-nim
RUN adduser --disabled-password --gecos '' r
ADD ./requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip install -r ./requirements.txt
EXPOSE 5000
RUN adduser -D -g '' r
RUN chmod a+x /root/.nimble/bin/nimble
ADD . /app
EXPOSE 5000
WORKDIR /app
RUN nimble update &&\
yes | nimble install &&\
nim c -d:release --deadCodeElim:on ponyapi
USER r
CMD gunicorn ponyapi:app --log-file=- -b 0.0.0.0:5000 -w 4
CMD ./ponyapi

5
Makefile Normal file
View File

@ -0,0 +1,5 @@
build:
nim c --deadcodeElim:on --hints:off ponyapi
run: build
./ponyapi

View File

@ -1 +0,0 @@
web: gunicorn ponyapi:app --log-file=-

145
ponyapi.nim Normal file
View File

@ -0,0 +1,145 @@
import asyncdispatch
import future
import jester
import json
import random
import strutils
import times
type
Episode* = object of RootObj
## An episode of My Little Pony: Friendship is Magic
name*: string ## Episode name
air_date*: int ## Air date in unix time
season*: int ## season number of the episode
episode*: int ## the episode number in the season
is_movie*: bool ## does this record represent a movie?
var
episodes: seq[Episode]
for line in lines "./fim.list":
var
ep: Episode
splitLine = line.split " "
timestr = splitLine[1]
seasonstr = splitLine[2]
episodestr = splitLine[3]
is_movie = seasonstr == "99"
name = splitLine[4 .. ^1].join " "
ep = Episode(name: name,
air_date: timestr.parseInt,
season: seasonstr.parseInt,
episode: episodestr.parseInt,
is_movie: is_movie)
episodes = episodes & ep
proc `%`(ep: Episode): JsonNode =
%*
{
"name": ep.name,
"air_date": ep.air_date,
"season": ep.season,
"episode": ep.episode,
"is_movie": ep.is_movie,
}
proc `%`(eps: seq[Episode]): JsonNode =
var ret = newJArray()
for ep in eps:
add ret, %ep
ret
proc `%%`(ep: Episode): JsonNode =
%*
{
"episode": ep,
}
proc `%%`(eps: seq[Episode]): JsonNode =
%*
{
"episodes": eps,
}
let myHeaders = {
"Content-Type": "application/json",
"X-Powered-By": "Nim and Jester",
}
settings:
port = 5000.Port
bindAddr = "0.0.0.0"
routes:
get "/":
"http://github.com/Xe/PonyAPI".uri.redirect
get "/all":
resp Http200, myHeaders, pretty(%%episodes, 4)
get "/newest":
var
now = getTime()
ep: Episode
for episode in episodes:
var then = times.fromSeconds(episode.air_date)
if now < then:
ep = episode
break
resp Http200, myHeaders, pretty(%%ep, 4)
get "/random":
resp Http200, myHeaders, pretty(%%episodes.randomChoice(), 4)
get "/season/@snumber":
var
season: int = @"snumber".parseInt
eps: seq[Episode] = lc[x | (x <- episodes, x.season == season), Episode]
if eps.len == 0:
resp Http404, myHeaders, $ %* { "error": "No episodes found" }
else:
resp Http200, myHeaders, pretty(%%eps, 4)
get "/season/@snumber/episode/@epnumber":
var
season: int = @"snumber".parseInt
enumber: int = @"epnumber".parseInt
ep: Episode
for episode in episodes:
if episode.season == season:
if episode.episode == enumber:
ep = episode
if ep.air_date == 0:
resp Http404, myHeaders, $ %* {"error": "No such episode"}
else:
resp Http200, myHeaders, pretty(%%ep, 4)
get "/search":
var
query = @"q".toLower
eps: seq[Episode]
if query == "":
halt Http406, myHeaders, $ %* { "error": "Need to specify query" }
for episode in episodes:
if episode.name.toLower.contains query:
eps = eps & episode
if eps.len == 0:
resp Http404, myHeaders, $ %* { "error": "No episodes found" }
else:
resp Http200, myHeaders, pretty(%%eps, 4)
runForever()

View File

@ -2,9 +2,9 @@
name = "ponyapi"
version = "0.1.0"
author = "Christine Dodrill <xena@yolo-swag.com>"
description = "PonyAPI client https://github.com/Xe/PonyAPI"
description = "PonyAPI server https://github.com/Xe/PonyAPI"
license = "MIT"
srcDir = "client/nim"
bin = "ponyapi"
[Deps]
Requires: "nim >= 0.10.0"
Requires: "nim >= 0.10.0, jester#head, random#head"

View File

@ -1,105 +0,0 @@
import datetime
import os
import random
from flask import Flask, abort, jsonify, request, redirect
# An Episode is constructed as such:
# data Episode = Episode
# { name :: String
# , air_date :: Int
# , season :: Int
# , episode :: Int
# , is_movie :: Bool
# }
#
# Any instance of season 99 should be interpreted as a movie.
episodes = []
# First, open the input file and read in episodes
with open("./fim.list", "r") as f:
for line in f:
airdate, s, e, name = line.split(' ', 4)[1:]
episode = {
"name": name[:-1],
"air_date": int(airdate),
"season": int(s),
"episode": int(e),
"is_movie": s == "99"
}
episodes.append(episode)
# Now, initialize Flask
app = Flask(__name__)
@app.route("/")
def hello():
return redirect("https://github.com/Xe/PonyAPI#ponyapi", code=302)
@app.route("/all")
def all_episodes():
return jsonify(episodes=episodes)
@app.route("/newest")
def newest_episode():
now = datetime.datetime(2006, 1, 4)
now = now.now()
for episode in episodes:
if now.fromtimestamp(episode["air_date"]) > now:
return jsonify(episode=episode)
abort(500)
@app.route("/season/<number>")
def season(number):
retEpisodes = []
for episode in episodes:
if str(episode["season"]) == number:
retEpisodes.append(episode)
try:
assert len(retEpisodes) > 0
except:
abort(404)
return jsonify(episodes=retEpisodes)
@app.route("/season/<snumber>/episode/<epnumber>")
def show_episode(snumber, epnumber):
for episode in episodes:
if str(episode["season"]) == snumber and str(episode["episode"]) == epnumber:
return jsonify(episode=episode)
abort(404)
@app.route("/random")
def show_random_ep():
return jsonify(episode=random.choice(episodes))
@app.route("/search")
def search():
retEpisodes = []
term = request.args.get("q", "").lower()
try:
assert term != ""
except:
abort(406)
for episode in episodes:
if term in episode["name"].lower():
retEpisodes.append(episode)
try:
assert len(retEpisodes) > 0
except:
abort(404)
return jsonify(episodes=retEpisodes)
if __name__ == '__main__':
app.run(host="0.0.0.0", debug=True)