summaryrefslogtreecommitdiff
path: root/srv/src/http
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2022-09-13 12:12:28 +0200
committerBrian Picciano <mediocregopher@gmail.com>2022-09-13 12:12:28 +0200
commitb1641d1af92eca6e475ea76aaed21a5dab0df185 (patch)
tree147b3176683f3c7e88f9395d6b0c34d21fb71361 /srv/src/http
parent1b3ca1af4b570921bc140988dde27cf938d44f68 (diff)
remove chat functionality completely
Diffstat (limited to 'srv/src/http')
-rw-r--r--srv/src/http/api.go17
-rw-r--r--srv/src/http/chat.go211
-rw-r--r--srv/src/http/tpl/chat.html251
3 files changed, 3 insertions, 476 deletions
diff --git a/srv/src/http/api.go b/srv/src/http/api.go
index 44b9170..01cad50 100644
--- a/srv/src/http/api.go
+++ b/srv/src/http/api.go
@@ -17,7 +17,6 @@ import (
lru "github.com/hashicorp/golang-lru"
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
- "github.com/mediocregopher/blog.mediocregopher.com/srv/chat"
"github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
"github.com/mediocregopher/blog.mediocregopher.com/srv/mailinglist"
"github.com/mediocregopher/blog.mediocregopher.com/srv/post"
@@ -41,9 +40,6 @@ type Params struct {
MailingList mailinglist.MailingList
- GlobalRoom chat.Room
- UserIDCalculator *chat.UserIDCalculator
-
// PublicURL is the base URL which site visitors can navigate to.
PublicURL *url.URL
@@ -176,16 +172,9 @@ func (a *api) apiHandler() http.Handler {
mux.Handle("/mailinglist/finalize", a.mailingListFinalizeHandler())
mux.Handle("/mailinglist/unsubscribe", a.mailingListUnsubscribeHandler())
- mux.Handle("/chat/global/", http.StripPrefix("/chat/global", newChatHandler(
- a.params.GlobalRoom,
- a.params.UserIDCalculator,
- a.requirePowMiddleware,
- )))
-
- // disallowGetMiddleware is used rather than a MethodMux because it has an
- // exception for websockets, which is needed for chat.
- return disallowGetMiddleware(mux)
-
+ return apiutil.MethodMux(map[string]http.Handler{
+ "POST": mux,
+ })
}
func (a *api) blogHandler() http.Handler {
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
- }
- }
- })
-}
diff --git a/srv/src/http/tpl/chat.html b/srv/src/http/tpl/chat.html
deleted file mode 100644
index b2038e2..0000000
--- a/srv/src/http/tpl/chat.html
+++ /dev/null
@@ -1,251 +0,0 @@
-{{ define "body" }}
-
-<script async type="module" src="/assets/api.js"></script>
-
-<style>
- #messages {
- max-height: 65vh;
- overflow: auto;
- padding-right: 2rem;
- }
-
- #messages .message {
- border: 1px solid #AAA;
- border-radius: 10px;
- margin-bottom: 1rem;
- padding: 2rem;
- overflow: auto;
- }
-
- #messages .message .title {
- font-weight: bold;
- font-size: 120%;
- }
-
- #messages .message .secondaryTitle {
- font-family: monospace;
- color: #CCC;
- }
-
- #messages .message p {
- font-family: monospace;
- margin: 1rem 0 0 0;
- }
-
-</style>
-
-<div id="messages"></div>
-
-<span id="fail" style="color: red;"></span>
-
-<script>
-
-const messagesEl = document.getElementById("messages");
-
-let messagesScrolledToBottom = true;
-messagesEl.onscroll = () => {
- const el = messagesEl;
- messagesScrolledToBottom = el.scrollHeight == el.scrollTop + el.clientHeight;
-};
-
-function renderMessages(msgs) {
-
- messagesEl.innerHTML = '';
-
- msgs.forEach((msg) => {
- const el = document.createElement("div");
- el.className = "row message"
-
- const elWithTextContents = (tag, body) => {
- const el = document.createElement(tag);
- el.appendChild(document.createTextNode(body));
- return el;
- };
-
- const titleEl = document.createElement("div");
- titleEl.className = "title";
- el.appendChild(titleEl);
-
- const userNameEl = elWithTextContents("span", msg.userID.name);
- titleEl.appendChild(userNameEl);
-
- const secondaryTitleEl = document.createElement("div");
- secondaryTitleEl.className = "secondaryTitle";
- el.appendChild(secondaryTitleEl);
-
- const dt = new Date(msg.createdAt*1000);
- const dtStr
- = `${dt.getFullYear()}-${dt.getMonth()+1}-${dt.getDate()}`
- + ` ${dt.getHours()}:${dt.getMinutes()}:${dt.getSeconds()}`;
-
- const userIDEl = elWithTextContents("span", `userID:${msg.userID.id} @ ${dtStr}`);
- secondaryTitleEl.appendChild(userIDEl);
-
- const bodyEl = document.createElement("p");
-
- const bodyParts = msg.body.split("\n");
- for (const i in bodyParts) {
- if (i > 0) bodyEl.appendChild(document.createElement("br"));
- bodyEl.appendChild(document.createTextNode(bodyParts[i]));
- }
-
- el.appendChild(bodyEl);
-
- messagesEl.appendChild(el);
- });
-}
-
-
-(async () => {
-
- const failEl = document.getElementById("fail");
- setErr = (msg) => failEl.innerHTML = `${msg} (please refresh the page to retry)`;
-
- try {
-
- const api = await import("/assets/api.js");
-
- const history = await api.call("/api/chat/global/history");
- const msgs = history.messages;
-
- // history returns msgs in time descending, but we display them in time
- // ascending.
- msgs.reverse()
-
- const sinceID = (msgs.length > 0) ? msgs[msgs.length-1].id : "";
-
- const ws = await api.ws("/api/chat/global/listen", {
- params: { sinceID },
- });
-
- while (true) {
- renderMessages(msgs);
-
- // If the user was previously scrolled to the bottom then keep them
- // there.
- if (messagesScrolledToBottom) {
- messagesEl.scrollTop = messagesEl.scrollHeight;
- }
-
- const msg = await ws.next();
- msgs.push(msg.message);
- renderMessages(msgs);
- }
-
-
- } catch (e) {
- e = `Failed to fetch message history: ${e}`
- setErr(e);
- console.error(e);
- return;
- }
-
-})()
-
-</script>
-
-<style>
-#append {
- border: 1px dashed #AAA;
- border-radius: 10px;
- padding: 2rem;
-}
-
-#append #appendBody {
- font-family: monospace;
-}
-
-#append #appendStatus {
- color: red;
-}
-
-</style>
-
-<form id="append">
- <h5>New Message</h5>
- <div class="row">
- <div class="columns four">
- <input class="u-full-width" placeholder="Name" id="appendName" type="text" />
- <input class="u-full-width" placeholder="Secret" id="appendSecret" type="password" />
- </div>
- <div class="columns eight">
- <p>
- Your name is displayed alongside your message.
-
- Your name+secret is used to generate your userID, which is also
- displayed alongside your message.
-
- Other users can validate two messages are from the same person
- by comparing the messages' userID.
- </p>
- </div>
- </div>
- <div class="row">
- <div class="columns twelve">
- <textarea
- style="font-family: monospace"
- id="appendBody"
- class="u-full-width"
- placeholder="Well thought out statement goes here..."
- ></textarea>
- </div>
- </div>
- <div class="row">
- <div class="columns four">
- <input class="u-full-width button-primary" id="appendSubmit" type="button" value="Submit" />
- </div>
- </div>
- <span id="appendStatus"></span>
-</form>
-
-<script>
-
-const append = document.getElementById("append");
-const appendName = document.getElementById("appendName");
-const appendSecret = document.getElementById("appendSecret");
-const appendBody = document.getElementById("appendBody");
-const appendSubmit = document.getElementById("appendSubmit");
-const appendStatus = document.getElementById("appendStatus");
-
-appendSubmit.onclick = async () => {
-
- const appendSubmitOrigValue = appendSubmit.value;
-
- appendSubmit.disabled = true;
- appendSubmit.className = "";
- appendSubmit.value = "Please hold...";
-
- appendStatus.innerHTML = '';
-
- try {
-
- const api = await import("/assets/api.js");
-
- await api.call('/api/chat/global/append', {
- body: {
- name: appendName.value,
- password: appendSecret.value,
- body: appendBody.value,
- },
- requiresPow: true,
- });
-
- appendBody.value = '';
-
- } catch (e) {
-
- appendStatus.innerHTML = e;
-
- } finally {
- appendSubmit.disabled = false;
- appendSubmit.className = "button-primary";
- appendSubmit.value = appendSubmitOrigValue;
- }
-};
-
-</script>
-
-{{ end }}
-
-{{ template "base.html" . }}
-