@@ -0,0 +1,29 @@+package bbs
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestLastCallers(t *testing.T) {
+ srv := testServer(t, &Config{AllowAnonymous: true})
+ addr := listen(t, srv)
+
+ ana := login(t, addr, "ana", newSigner(t))
+ login(t, addr, "guest", nil)
+
+ ana.send("l")
+ ana.waitFor("LAST CALLERS")
+ ana.waitFor("guest-")
+ ana.waitFor("ssh")
+
+ client := dial(t, addr, newSigner(t))
+ out, code := run(t, client, "lastcallers output=text", "")
+ if code != 0 || !strings.Contains(out, "ana") || !strings.Contains(out, "guest-") {
+ t.Fatalf("lastcallers (exit %d):\n%s", code, out)
+ }
+ // The dispatcher call itself is not a visit.
+ if strings.Count(out, "\n") != 2 {
+ t.Fatalf("want two visits, got:\n%s", out)
+ }
+}
@@ -570,6 +570,31 @@ return &dispatch.Result{Data: online, Lines: lines}, nil },
},
{
+ Name: "lastcallers",
+ Summary: "who called the BBS last, newest first",
+ Args: []dispatch.Arg{{Name: "count", Kind: dispatch.KindInt, Min: 1, Max: 50, Help: "how many (default 10)"}},
+ Free: true,
+ Run: func(_ context.Context, c *dispatch.Call) (*dispatch.Result, error) {
+ n := c.Int("count")
+ if n == 0 {
+ n = 10
+ }
+ callers, err := s.cstore.LastCallers(n)
+ if err != nil {
+ return nil, err
+ }
+ lines := make([]string, 0, len(callers))
+ for _, cl := range callers {
+ lines = append(lines, fmt.Sprintf("%4s %-16s %s", ago(time.Since(cl.At)), cl.Nick, cl.Via))
+ }
+ if callers == nil {
+ callers = []community.Caller{}
+ }
+
+ return &dispatch.Result{Data: callers, Lines: lines}, nil
+ },
+ },
+ {
Name: "wall",
Summary: "the latest one-liners on the wall",
Args: []dispatch.Arg{{Name: "count", Kind: dispatch.KindInt, Min: 1, Max: 50, Help: "how many (default 10)"}},
@@ -246,4 +246,8 @@ "BBS_THEME_RETRO90": "retro 90s", "BBS_THEME_MODERN": "retro-modern",
"BBS_THEME_PLAIN": "plain",
"BBS_FX": "modem effect",
+ "BBS_CALLERS": "last callers",
+ "BBS_CALLERS_SUM": "who came by",
+ "BBS_TITLE_CALLERS": "LAST CALLERS",
+ "BBS_CALLERS_EMPTY": "(nobody yet)",
}
@@ -58,6 +58,7 @@ } lines = append(lines,
st.menuEntry("w", st.t("BBS_WALL"), st.t("BBS_WALL_SUM")),
st.menuEntry("c", st.t("BBS_CHAT"), st.t("BBS_CHAT_SUM")),
+ st.menuEntry("l", st.t("BBS_CALLERS"), st.t("BBS_CALLERS_SUM")),
)
if st.gamesOn() {
lines = append(lines, st.menuEntry("g", st.t("BBS_GAMES"), st.t("BBS_GAMES_SUM")))
@@ -58,6 +58,7 @@ communityCfg communitySettings presence *community.Presence
wall *community.Wall
chat *community.Hub
+ cstore *community.Store // bans, chat log, last callers
games *gamesSettings // nil when games are off or the door is missing
gameSlots *door.Slots // nodes, one per person playing
@@ -116,6 +117,7 @@ if err != nil { return nil, fmt.Errorf("community store: %w", err)
}
cc := s.communityCfg
+ s.cstore = cst
s.wall = community.NewWall(cst, cc.wallMaxLen, cc.wallCooldown)
s.chat = community.NewHub(cst, cc.chatMaxLen, cc.chatPerMinute, cc.chatBurst)
s.chat.SetKeep(cc.chatKeep)
@@ -161,6 +161,8 @@ case 'w', 'W': st.wallMenu()
case 'c', 'C':
st.chatRoom()
+ case 'l', 'L':
+ st.lastCallersScreen()
case 'g', 'G':
if st.gamesOn() {
st.gamesMenu()
@@ -73,6 +73,11 @@ }
st.pres = s.presence.Join(identity, profile.Nick, st.anon)
defer st.pres.Leave()
+ if s.cstore != nil {
+ if err := s.cstore.LogCall(identity, profile.Nick, info.Via, st.anon); err != nil {
+ log.Println("bbs: last callers:", err)
+ }
+ }
done := make(chan struct{})
defer close(done)
@@ -240,5 +240,9 @@ "BBS_GAMES_FULL": "All %d game slots are taken — try again soon", "BBS_GAMES_LATE": "This connection is about to time out — reconnect to play",
"BBS_GAMES_FAILED": "The games could not start — try again later",
"BBS_WHERE_GAME": "playing",
- "BBS_GAMES_EMPTY": "No games on the shelf yet — check back soon"
+ "BBS_GAMES_EMPTY": "No games on the shelf yet — check back soon",
+ "BBS_CALLERS": "last callers",
+ "BBS_CALLERS_SUM": "who came by",
+ "BBS_TITLE_CALLERS": "LAST CALLERS",
+ "BBS_CALLERS_EMPTY": "(nobody yet)"
}
@@ -240,5 +240,9 @@ "BBS_GAMES_FULL": "As %d vagas de jogo estão ocupadas — tente daqui a pouco", "BBS_GAMES_LATE": "Esta conexão está perto do limite de tempo — reconecte para jogar",
"BBS_GAMES_FAILED": "Os jogos não puderam iniciar — tente mais tarde",
"BBS_WHERE_GAME": "jogando",
- "BBS_GAMES_EMPTY": "Ainda não há jogos na estante — volte daqui a pouco"
+ "BBS_GAMES_EMPTY": "Ainda não há jogos na estante — volte daqui a pouco",
+ "BBS_CALLERS": "visitantes",
+ "BBS_CALLERS_SUM": "quem passou por aqui",
+ "BBS_TITLE_CALLERS": "ÚLTIMOS VISITANTES",
+ "BBS_CALLERS_EMPTY": "(ninguém ainda)"
}