Search Apps Documentation Source Content File Folder Download Copy Actions Download

ringlog.gno

2.63 Kb · 110 lines
  1// Package ringlog is an on-chain port of Go's container/ring: a fixed-capacity
  2// circular message board where new posts overwrite the oldest entries once full.
  3package ringlog
  4
  5import (
  6	"chain/runtime"
  7	"chain/runtime/unsafe"
  8	"strconv"
  9	"strings"
 10)
 11
 12// Cap is the maximum number of messages the ring buffer holds.
 13const Cap = 16
 14
 15// Entry is a single posted message.
 16type Entry struct {
 17	Author  address
 18	Message string
 19	Height  int64
 20}
 21
 22var (
 23	buf   [Cap]Entry // the ring storage
 24	head  int        // index of the next write slot
 25	count int        // number of entries currently stored (0 ≤ count ≤ Cap)
 26)
 27
 28// Post adds a message to the ring buffer.
 29// Once Cap entries are stored, the oldest entry is overwritten.
 30func Post(msg string) {
 31	msg = strings.TrimSpace(msg)
 32	if len(msg) == 0 {
 33		panic("message cannot be empty")
 34	}
 35	if len(msg) > 280 {
 36		panic("message too long (max 280 chars)")
 37	}
 38	buf[head] = Entry{
 39		Author:  unsafe.PreviousRealm().Address(),
 40		Message: msg,
 41		Height:  runtime.ChainHeight(),
 42	}
 43	head = (head + 1) % Cap
 44	if count < Cap {
 45		count++
 46	}
 47}
 48
 49// Entries returns all stored messages in chronological order (oldest first).
 50func Entries() []Entry {
 51	if count == 0 {
 52		return nil
 53	}
 54	result := make([]Entry, count)
 55	oldest := (head - count + Cap) % Cap
 56	for i := 0; i < count; i++ {
 57		result[i] = buf[(oldest+i)%Cap]
 58	}
 59	return result
 60}
 61
 62// Len returns the number of messages currently stored.
 63func Len() int { return count }
 64
 65// Render displays the ring buffer as a Markdown page.
 66func Render(path string) string {
 67	var sb strings.Builder
 68
 69	sb.WriteString("# RingLog\n\n")
 70	sb.WriteString("> A ring-buffer message board (capacity: **")
 71	sb.WriteString(strconv.Itoa(Cap))
 72	sb.WriteString("**). New messages overwrite the oldest once the buffer is full.\n\n")
 73
 74	if count == 0 {
 75		sb.WriteString("*No messages yet. Call `Post(msg)` to add one.*\n")
 76		return sb.String()
 77	}
 78
 79	sb.WriteString("| # | Author | Block | Message |\n")
 80	sb.WriteString("|---|--------|-------|---------|\n")
 81
 82	entries := Entries()
 83	for i, e := range entries {
 84		sb.WriteString("| ")
 85		sb.WriteString(strconv.Itoa(i + 1))
 86		sb.WriteString(" | `")
 87		sb.WriteString(shorten(e.Author.String()))
 88		sb.WriteString("` | ")
 89		sb.WriteString(strconv.FormatInt(e.Height, 10))
 90		sb.WriteString(" | ")
 91		sb.WriteString(e.Message)
 92		sb.WriteString(" |\n")
 93	}
 94
 95	sb.WriteString("\n*Showing ")
 96	sb.WriteString(strconv.Itoa(count))
 97	sb.WriteString(" of ")
 98	sb.WriteString(strconv.Itoa(Cap))
 99	sb.WriteString(" slots used.*\n")
100
101	return sb.String()
102}
103
104// shorten trims a long address for display.
105func shorten(s string) string {
106	if len(s) <= 14 {
107		return s
108	}
109	return s[:6] + "…" + s[len(s)-6:]
110}