Initial commit
This commit is contained in:
commit
c86a245309
3 changed files with 152 additions and 0 deletions
25
.gitlab-ci.yml
Normal file
25
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- docker build -t atomaka/punaday-api .
|
||||||
|
except:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
deploy:
|
||||||
|
stage: deploy
|
||||||
|
script:
|
||||||
|
- VERSION=$(git describe --tags)
|
||||||
|
- docker build -t atomaka/punaday-api .
|
||||||
|
- docker tag atomaka/punaday-api:latest docker.atomaka.com/atomaka/punaday-api:$VERSION
|
||||||
|
- docker tag atomaka/punaday-api:latest docker.atomaka.com/atomaka/punaday-api:latest
|
||||||
|
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD -e me@atomaka.com docker.atomaka.com
|
||||||
|
- docker push docker.atomaka.com/atomaka/punaday-api
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
tags:
|
||||||
|
- docker
|
12
Dockerfile
Normal file
12
Dockerfile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
FROM alpine:latest
|
||||||
|
COPY . /go/src/github.com/atomaka/punaday-api
|
||||||
|
RUN apk update \
|
||||||
|
&& apk add --no-cache go git \
|
||||||
|
&& cd /go/src/github.com/atomaka/punaday-api \
|
||||||
|
&& export GOPATH=/go \
|
||||||
|
&& go get \
|
||||||
|
&& go build -o /bin/punaday-api \
|
||||||
|
&& rm -rf /go \
|
||||||
|
&& apk del --purge git go \
|
||||||
|
&& rm -rf /var/cache/apk*
|
||||||
|
ENTRYPOINT ["/bin/punaday-api"]
|
115
main.go
Normal file
115
main.go
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
const PUN_BASE = "http://www.punoftheday.com"
|
||||||
|
const RANDOM_PUN = PUN_BASE + "/cgi-bin/randompun.pl"
|
||||||
|
const SELECT_PUN = PUN_BASE + "/pun"
|
||||||
|
|
||||||
|
type Pun struct {
|
||||||
|
Id int `json:"-"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Status int `json:"-"`
|
||||||
|
Detail string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("/puns/random", RandomPun)
|
||||||
|
http.HandleFunc("/puns/", ShowPun)
|
||||||
|
http.HandleFunc("/", NotFound)
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotFound(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("404 Not Found: %v\n", r.URL.Path)
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
err := &Error{404, "not_found"}
|
||||||
|
w.WriteHeader(err.Status)
|
||||||
|
json.NewEncoder(w).Encode(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WritePun(w http.ResponseWriter, r *http.Request, pun Pun) {
|
||||||
|
log.Printf("200 OK: %v\n", r.URL.Path)
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
json.NewEncoder(w).Encode(pun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShowPun(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := r.URL.Path[len("/puns/"):]
|
||||||
|
|
||||||
|
pun := getPun(SELECT_PUN + "/" + id)
|
||||||
|
|
||||||
|
if id != strconv.Itoa(pun.Id) {
|
||||||
|
NotFound(w, r)
|
||||||
|
} else {
|
||||||
|
WritePun(w, r, pun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandomPun(w http.ResponseWriter, r *http.Request) {
|
||||||
|
pun := getPun(RANDOM_PUN)
|
||||||
|
|
||||||
|
WritePun(w, r, pun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPun(url string) Pun {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("ERROR: Unable to access " + url)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := resp.Body
|
||||||
|
defer b.Close()
|
||||||
|
|
||||||
|
pun := Pun{}
|
||||||
|
|
||||||
|
z := html.NewTokenizer(b)
|
||||||
|
|
||||||
|
for {
|
||||||
|
tt := z.Next()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case tt == html.ErrorToken:
|
||||||
|
return pun
|
||||||
|
case tt == html.StartTagToken:
|
||||||
|
t := z.Token()
|
||||||
|
|
||||||
|
isParagraph := t.Data == "p"
|
||||||
|
isInput := t.Data == "input"
|
||||||
|
|
||||||
|
if isParagraph && pun.Text == "" {
|
||||||
|
z.Next()
|
||||||
|
t := z.Token()
|
||||||
|
pun.Text = t.Data
|
||||||
|
}
|
||||||
|
if isInput {
|
||||||
|
if getAttr("name", t) == "PunID" {
|
||||||
|
pun.Id, _ = strconv.Atoi(getAttr("value", t))
|
||||||
|
pun.Url = SELECT_PUN + "/" + strconv.Itoa(pun.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAttr(at string, t html.Token) string {
|
||||||
|
var val string
|
||||||
|
for _, a := range t.Attr {
|
||||||
|
if a.Key == at {
|
||||||
|
val = a.Val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
Loading…
Reference in a new issue