From e660b52bd4098a11d26327bfc759e2db776670e8 Mon Sep 17 00:00:00 2001 From: daru Date: Sat, 14 May 2022 18:31:58 +0200 Subject: [PATCH] Chat feature --- huso.go | 2 ++ nuss.go | 37 +++++++++++++++++++++++---- ober.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++-- schaffer.go | 8 ++++++ 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/huso.go b/huso.go index 5a679c0..ac6ab91 100644 --- a/huso.go +++ b/huso.go @@ -33,7 +33,9 @@ const ( bucketAnime = "anime" bucketMedia = "media" bucketAppoint = "appoint" + bucketChat = "chat" AppointSplit = "ยง" + chatLength = 10101 ) var ( diff --git a/nuss.go b/nuss.go index 6301a30..2fff860 100644 --- a/nuss.go +++ b/nuss.go @@ -10,7 +10,7 @@ import ( ) func ReadUser(username string) (*UserData, error) { - data, err := DbRead(bucketUsers, username) + data, err := DbRead(bucketUsers, []byte(username)) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func DeleteUserFromAnime(username string, userId, animeId int64) (*AnimeUser, er Users: users, } if len(users) == 0 { - return tx.Delete(bucketAnime, keyBytes) + return DeleteAnime(tx, keyBytes) } newData, err := json.Marshal(users) if err != nil { @@ -144,7 +144,7 @@ func DeleteUserFromAnimes(userId int64) error { users = users[:len(users)-1] // check if anime needs recycling if len(users) == 0 { - err = tx.Delete(bucketAnime, e.Key) + err = DeleteAnime(tx, e.Key) if err != nil { return err } @@ -167,6 +167,11 @@ func DeleteUserFromAnimes(userId int64) error { }) } +func DeleteAnime(tx *nutsdb.Tx, keyBytes []byte) error { + tx.Delete(bucketChat, keyBytes) + return tx.Delete(bucketAnime, keyBytes) +} + func UpdateUserAnimeProgress(animeId, userId int64, progress int, updated time.Time) error { return db.Update( func(tx *nutsdb.Tx) error { @@ -286,6 +291,29 @@ func ReadAppointments() ([]Appointment, error) { return appoints, err } +func ReadChat(animeId int64) (string, error) { + data, err := DbRead(bucketChat, Int64ToByte(animeId)) + return string(data), err +} + +func SaveChat(animeId int64, username, newMessage string) (string, error) { + var chat string + err := db.Update( + func(tx *nutsdb.Tx) error { + keyBytes := Int64ToByte(animeId) + e, err := tx.Get(bucketChat, keyBytes) + if err != nil { + chat = "" + } else { + chat = string(e.Value) + } + // add to chat message + chat = AddToChat(chat, newMessage, username) + return tx.Put(bucketChat, keyBytes, []byte(chat), nutsdb.Persistent) + }) + return chat, err +} + func DbClean() error { return db.Update( func(tx *nutsdb.Tx) error { @@ -301,11 +329,10 @@ func DbSave(bucket, key string, val []byte) error { }) } -func DbRead(bucket, key string) ([]byte, error) { +func DbRead(bucket string, keyBytes []byte) ([]byte, error) { var val []byte err := db.View( func(tx *nutsdb.Tx) error { - keyBytes := []byte(key) e, err := tx.Get(bucket, keyBytes) if err != nil { return err diff --git a/ober.go b/ober.go index 60f828d..06720af 100644 --- a/ober.go +++ b/ober.go @@ -20,10 +20,12 @@ func RunWebserv() { r.GET("/api/anime/{id}", Headers(AnimeGet)) r.GET("/api/animesearch", Headers(AnimeSearchGet)) r.GET("/api/appointment", Headers(AppointmentGet)) + r.GET("/api/chat/{id}", Headers(ChatGet)) r.GET("/api/log", Headers(LogGet)) r.GET("/api/user/{user?}", Headers(UserGet)) r.GET("/api/watch/{user?}", Headers(WatchGet)) r.GET("/api/watchext/{user?}", Headers(WatchExtendedGet)) + r.POST("/api/chat/{id}/{user}", Headers(ChatPost)) r.POST("/api/register", Headers(Register)) r.POST("/api/watch/{user}", Headers(WatchPost)) r.DELETE("/api/register", Headers(UnRegister)) @@ -82,7 +84,7 @@ func AnimeGet(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusBadRequest) return } - // check user exists + // check anime exists malId, err := strconv.ParseInt(fmt.Sprintf("%s", idVal), 10, 64) if err != nil { ctx.WriteString(err.Error()) @@ -141,11 +143,41 @@ func AppointmentGet(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusNotImplemented) } +func ChatGet(ctx *fasthttp.RequestCtx) { + idVal := ctx.UserValue("id") + if idVal == nil { + ctx.SetStatusCode(fasthttp.StatusBadRequest) + return + } + animeId, err := strconv.ParseInt(fmt.Sprintf("%s", idVal), 10, 64) + if err != nil { + ctx.WriteString(err.Error()) + ctx.SetStatusCode(fasthttp.StatusBadRequest) + return + } + text, err := ReadChat(animeId) + if err != nil { + if strings.Contains(err.Error(), "not found") { + ctx.WriteString(err.Error()) + ctx.SetStatusCode(fasthttp.StatusNotFound) + return + } + addErrorToCtx(ctx, err) + return + } + _, err = ctx.WriteString(text) + if err != nil { + addErrorToCtx(ctx, err) + return + } + ctx.SetContentType("text/plain; charset=utf-8") + ctx.SetStatusCode(fasthttp.StatusOK) +} + func LogGet(ctx *fasthttp.RequestCtx) { _, err := ctx.WriteString(logOut.String()) if err != nil { addErrorToCtx(ctx, err) - ctx.SetStatusCode(fasthttp.StatusInternalServerError) return } ctx.SetContentType("text/plain; charset=utf-8") @@ -317,6 +349,43 @@ func Register(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusOK) } +func ChatPost(ctx *fasthttp.RequestCtx) { + auth := ctx.Request.Header.Peek("X-HUSO-AUTH") + if ctx.UserValue("id") == nil || ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "text/plain") { + ctx.SetStatusCode(fasthttp.StatusBadRequest) + return + } + username := fmt.Sprintf("%s", ctx.UserValue("user")) + legit, _ := GheddoAuth(username, string(auth)) + if !legit { + ctx.SetStatusCode(fasthttp.StatusUnauthorized) + return + } + animeId, err := strconv.ParseInt(fmt.Sprintf("%s", ctx.UserValue("id")), 10, 64) + if err != nil { + ctx.WriteString(err.Error()) + ctx.SetStatusCode(fasthttp.StatusBadRequest) + return + } + sent := strings.TrimSpace(string(ctx.PostBody())) + if sent == "" { + ctx.SetStatusCode(fasthttp.StatusBadRequest) + return + } + text, err := SaveChat(animeId, username, sent) + if err != nil { + addErrorToCtx(ctx, err) + return + } + _, err = ctx.WriteString(text) + if err != nil { + addErrorToCtx(ctx, err) + return + } + ctx.SetContentType("text/plain; charset=utf-8") + ctx.SetStatusCode(fasthttp.StatusOK) +} + func WatchPost(ctx *fasthttp.RequestCtx) { processUpdateReq(ctx, true) } diff --git a/schaffer.go b/schaffer.go index ea90a0d..d79fbcc 100644 --- a/schaffer.go +++ b/schaffer.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "errors" + "fmt" "time" ) @@ -163,3 +164,10 @@ func FetchProgress(animeId, userId int64, username string, progress int) (int, t // has no progress or dropped/hold return 0, time.Now(), nil } + +func AddToChat(old, new, user string) string { + buf := NewRingBuf(chatLength) + buf.Write([]byte(old)) + buf.Write([]byte(fmt.Sprintf("[%s][%s]: %s\n", time.Now().Format("02.01.|15:04:05"), user, new))) + return buf.String() +}