Files
huso/ober.go
2022-04-17 15:43:16 +02:00

358 lines
8.5 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"strconv"
"strings"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
"github.com/xujiajun/nutsdb"
)
func RunWebserv() {
r := router.New()
r.GET("/", Headers(Start))
r.GET("/api/season", Headers(Season))
r.GET("/api/anime/{id}", Headers(AnimeGet))
r.GET("/api/watch/{user?}", Headers(WatchGet))
r.POST("/api/register", Headers(Register))
r.POST("/api/watch/{user}", Headers(WatchPost))
r.DELETE("/api/register", Headers(UnRegister))
r.DELETE("/api/watch/{user}", Headers(WatchDelete))
log.Fatal(fasthttp.ListenAndServe(":"+strconv.Itoa(*webServerPort), r.Handler))
}
func Start(ctx *fasthttp.RequestCtx) {
season, err := GetSeasonCache()
if err != nil {
addErrorToCtx(ctx, err)
return
}
WriteIndex(ctx, season)
ctx.SetContentType("text/html; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func Season(ctx *fasthttp.RequestCtx) {
data, err := cache.Get(seasonApiJikan)
if err != nil {
addErrorToCtx(ctx, err)
return
}
err = writeResponseBody(ctx, data)
if err != nil {
addErrorToCtx(ctx, err)
return
}
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func AnimeGet(ctx *fasthttp.RequestCtx) {
idVal := ctx.UserValue("id")
if idVal == nil {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
// check user exists
malId, err := strconv.ParseInt(fmt.Sprintf("%s", idVal), 10, 64)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
// search season first
anime, err := SearchSeason(malId)
var bytes []byte
if err != nil {
_, bytes, err = GetAnimeDetailData(malId)
if err != nil {
addErrorToCtx(ctx, err)
return
}
} else {
bytes, err = json.Marshal(&anime)
if err != nil {
addErrorToCtx(ctx, err)
return
}
}
_, err = ctx.Write(bytes)
if err != nil {
addErrorToCtx(ctx, err)
return
}
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func WatchGet(ctx *fasthttp.RequestCtx) {
usrVal := ctx.UserValue("user")
var userId int64
if usrVal != nil {
// check user exists
user, err := ReadUser(fmt.Sprintf("%s", usrVal))
if err != nil {
ctx.WriteString("Dich gibts nicht")
ctx.SetStatusCode(fasthttp.StatusNotFound)
return
}
userId = user.MalID
}
animes, err := ReadAnimeUsers()
if err != nil {
// check if no anime were inserted
if err != nutsdb.ErrBucketEmpty {
addErrorToCtx(ctx, err)
return
}
animes = make([]AnimeUser, 0)
}
// apply single user logic
if usrVal != nil {
filteredAnimes := make([]AnimeUser, 0)
for _, a := range animes {
for _, u := range a.Users {
if u.MalID == userId {
filteredAnimes = append(filteredAnimes, a)
break
}
}
}
animes = filteredAnimes
}
bytes, err := json.Marshal(animes)
if err != nil {
addErrorToCtx(ctx, err)
return
}
_, err = ctx.Write(bytes)
if err != nil {
addErrorToCtx(ctx, err)
return
}
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func Register(ctx *fasthttp.RequestCtx) {
if string(ctx.Request.Header.ContentType()) != "application/json" {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
body := ctx.PostBody()
var register RegisterData
err := json.Unmarshal(body, &register)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
if register.MalID == 0 || register.Username == "" || register.Secret == "" || register.Sauce == "" {
ctx.WriteString("Sprich JSON du Hurensohn")
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
calcSauce := Sauce(register.MalID, register.Username)
if calcSauce != strings.ToLower(register.Sauce) {
ctx.WriteString("Möge die Sauce mit dir sein")
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
// check user exists
_, err = ReadUser(register.Username)
if err == nil {
ctx.WriteString("Nicht drängeln")
ctx.SetStatusCode(fasthttp.StatusConflict)
return
}
// check user legit
userData, _, err := GetUserData(register.Username)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
return
}
if userData.Data.MalID != register.MalID {
ctx.WriteString("Dich gibts nicht auf MAL")
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
return
}
// REGISTER
user := UserData{
Username: register.Username,
MalID: register.MalID,
Secret: register.Secret,
}
err = SaveUser(&user)
if err != nil {
addErrorToCtx(ctx, err)
return
}
ctx.SetBody(body)
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func WatchPost(ctx *fasthttp.RequestCtx) {
processUpdateReq(ctx, true)
}
func UnRegister(ctx *fasthttp.RequestCtx) {
if string(ctx.Request.Header.ContentType()) != "application/json" {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
body := ctx.PostBody()
var register RegisterData
err := json.Unmarshal(body, &register)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
if register.MalID == 0 || register.Username == "" || register.Secret == "" || register.Sauce == "" {
ctx.WriteString("Sprich JSON du Hurensohn")
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
calcSauce := Sauce(register.MalID, register.Username)
if calcSauce != strings.ToLower(register.Sauce) {
ctx.WriteString("Möge die Sauce mit dir sein")
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
// DELETE
err = DeleteUserFromAnimes(register.MalID)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusNotFound)
return
}
err = DbDelete(bucketUsers, register.Username)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusNotFound)
return
}
ctx.SetBody(body)
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
}
func WatchDelete(ctx *fasthttp.RequestCtx) {
processUpdateReq(ctx, false)
}
func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
auth := ctx.Request.Header.Peek("X-HUSO-AUTH")
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || string(ctx.Request.Header.ContentType()) != "application/json" {
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
username := fmt.Sprintf("%s", ctx.UserValue("user"))
legit, userId := GheddoAuth(username, string(auth))
if !legit {
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
return
}
body := ctx.PostBody()
var animes []AnimeUser
err := json.Unmarshal(body, &animes)
if err != nil || len(animes) == 0 {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusBadRequest)
return
}
// iterate sent animes
for i, anime := range animes {
// check if anime is in season
_, err = SearchSeason(anime.Anime)
if err != nil {
// anime not in season => holen sie diese
_, _, err := GetAnimeDetailData(anime.Anime)
if err != nil {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusNotFound)
return
}
}
var animeData *AnimeUser
// update or delete request
if update {
// anime exitsts => save
animeData, err = AddUserToAnime(username, userId, anime.Anime)
} else {
// anime exitsts => delete
animeData, err = DeleteUserFromAnime(username, userId, anime.Anime)
}
if err != nil {
addErrorToCtx(ctx, err)
return
}
animes[i].Users = animeData.Users
}
data, err := json.Marshal(animes)
if err != nil {
addErrorToCtx(ctx, err)
return
}
err = writeResponseBody(ctx, data)
if err != nil {
addErrorToCtx(ctx, err)
return
}
ctx.SetContentType("application/json; charset=utf-8")
}
func GheddoAuth(username, auth string) (bool, int64) {
user, err := ReadUser(username)
if err != nil {
return false, 0
}
return user.Secret == auth, user.MalID
}
func Headers(h fasthttp.RequestHandler) fasthttp.RequestHandler {
return fasthttp.RequestHandler(func(ctx *fasthttp.RequestCtx) {
if *localServer {
ctx.Response.Header.Set("Access-Control-Allow-Origin", "*")
ctx.Response.Header.Set("Access-Control-Allow-Headers", "*")
ctx.Response.Header.Set("Access-Control-Allow-Methods", "*")
}
h(ctx)
})
}
func writeResponseBody(ctx *fasthttp.RequestCtx, bytes []byte) error {
_, err := ctx.Write(bytes)
if err != nil {
return err
}
ctx.SetContentType("application/json; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
return err
}
func addErrorToCtx(ctx *fasthttp.RequestCtx, err error) {
ctx.WriteString(err.Error())
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
}