Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}