summaryrefslogtreecommitdiff
path: root/srv/src/http/chat.go
diff options
context:
space:
mode:
Diffstat (limited to 'srv/src/http/chat.go')
-rw-r--r--srv/src/http/chat.go211
1 files changed, 0 insertions, 211 deletions
diff --git a/srv/src/http/chat.go b/srv/src/http/chat.go
deleted file mode 100644
index f76e4ad..0000000
--- a/srv/src/http/chat.go
+++ /dev/null
@@ -1,211 +0,0 @@
-package http
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "strings"
- "unicode"
-
- "github.com/gorilla/websocket"
- "github.com/mediocregopher/blog.mediocregopher.com/srv/chat"
- "github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
-)
-
-type chatHandler struct {
- *http.ServeMux
-
- room chat.Room
- userIDCalc *chat.UserIDCalculator
-
- wsUpgrader websocket.Upgrader
-}
-
-func newChatHandler(
- room chat.Room, userIDCalc *chat.UserIDCalculator,
- requirePowMiddleware func(http.Handler) http.Handler,
-) http.Handler {
- c := &chatHandler{
- ServeMux: http.NewServeMux(),
- room: room,
- userIDCalc: userIDCalc,
-
- wsUpgrader: websocket.Upgrader{},
- }
-
- c.Handle("/history", c.historyHandler())
- c.Handle("/user-id", requirePowMiddleware(c.userIDHandler()))
- c.Handle("/append", requirePowMiddleware(c.appendHandler()))
- c.Handle("/listen", c.listenHandler())
-
- return c
-}
-
-func (c *chatHandler) historyHandler() http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- limit, err := apiutil.StrToInt(r.PostFormValue("limit"), 0)
- if err != nil {
- apiutil.BadRequest(rw, r, fmt.Errorf("invalid limit parameter: %w", err))
- return
- }
-
- cursor := r.PostFormValue("cursor")
-
- cursor, msgs, err := c.room.History(r.Context(), chat.HistoryOpts{
- Limit: limit,
- Cursor: cursor,
- })
-
- if argErr := (chat.ErrInvalidArg{}); errors.As(err, &argErr) {
- apiutil.BadRequest(rw, r, argErr.Err)
- return
- } else if err != nil {
- apiutil.InternalServerError(rw, r, err)
- }
-
- apiutil.JSONResult(rw, r, struct {
- Cursor string `json:"cursor"`
- Messages []chat.Message `json:"messages"`
- }{
- Cursor: cursor,
- Messages: msgs,
- })
- })
-}
-
-func (c *chatHandler) userID(r *http.Request) (chat.UserID, error) {
- name := r.PostFormValue("name")
- if l := len(name); l == 0 {
- return chat.UserID{}, errors.New("name is required")
- } else if l > 16 {
- return chat.UserID{}, errors.New("name too long")
- }
-
- nameClean := strings.Map(func(r rune) rune {
- if !unicode.IsPrint(r) {
- return -1
- }
- return r
- }, name)
-
- if nameClean != name {
- return chat.UserID{}, errors.New("name contains invalid characters")
- }
-
- password := r.PostFormValue("password")
- if l := len(password); l == 0 {
- return chat.UserID{}, errors.New("password is required")
- } else if l > 128 {
- return chat.UserID{}, errors.New("password too long")
- }
-
- return c.userIDCalc.Calculate(name, password), nil
-}
-
-func (c *chatHandler) userIDHandler() http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- userID, err := c.userID(r)
- if err != nil {
- apiutil.BadRequest(rw, r, err)
- return
- }
-
- apiutil.JSONResult(rw, r, struct {
- UserID chat.UserID `json:"userID"`
- }{
- UserID: userID,
- })
- })
-}
-
-func (c *chatHandler) appendHandler() http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- userID, err := c.userID(r)
- if err != nil {
- apiutil.BadRequest(rw, r, err)
- return
- }
-
- body := r.PostFormValue("body")
-
- if l := len(body); l == 0 {
- apiutil.BadRequest(rw, r, errors.New("body is required"))
- return
-
- } else if l > 300 {
- apiutil.BadRequest(rw, r, errors.New("body too long"))
- return
- }
-
- msg, err := c.room.Append(r.Context(), chat.Message{
- UserID: userID,
- Body: body,
- })
-
- if err != nil {
- apiutil.InternalServerError(rw, r, err)
- return
- }
-
- apiutil.JSONResult(rw, r, struct {
- MessageID string `json:"messageID"`
- }{
- MessageID: msg.ID,
- })
- })
-}
-
-func (c *chatHandler) listenHandler() http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-
- ctx := r.Context()
- sinceID := r.FormValue("sinceID")
-
- conn, err := c.wsUpgrader.Upgrade(rw, r, nil)
- if err != nil {
- apiutil.BadRequest(rw, r, err)
- return
- }
- defer conn.Close()
-
- it, err := c.room.Listen(ctx, sinceID)
-
- if errors.As(err, new(chat.ErrInvalidArg)) {
- apiutil.BadRequest(rw, r, err)
- return
-
- } else if errors.Is(err, context.Canceled) {
- return
-
- } else if err != nil {
- apiutil.InternalServerError(rw, r, err)
- return
- }
-
- defer it.Close()
-
- for {
-
- msg, err := it.Next(ctx)
- if errors.Is(err, context.Canceled) {
- return
-
- } else if err != nil {
- apiutil.InternalServerError(rw, r, err)
- return
- }
-
- err = conn.WriteJSON(struct {
- Message chat.Message `json:"message"`
- }{
- Message: msg,
- })
-
- if err != nil {
- apiutil.GetRequestLogger(r).Error(ctx, "couldn't write message", err)
- return
- }
- }
- })
-}