PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/moul/x/daily/microblog/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
moul / x / daily / microblog
Files
3 (README)(gnomod.toml)
Exported functions
3
Module
gno.land/r/moul/x/daily/microblog/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • microblog.gnogno
microblog.gnogno
1// Package microblog is a public microblog wall for gno.land.2//3// Anyone can Post a short message (<= maxMsgLen chars). Every post records4// the caller address, the message, and the block height at which it was made.5// Render displays the wall newest-first, 20 posts per page, with pagination6// driven by the Render path (e.g. "?page=2" or "/2").7package microblog89import (10	"chain"11	"chain/runtime"12	"chain/runtime/unsafe"13	"strconv"14	"strings"15)1617// maxMsgLen is the maximum length (in bytes) of a single post.18const maxMsgLen = 2801920// pageSize is how many posts a single Render page shows.21const pageSize = 202223// post is a single microblog entry.24type post struct {25	Author string // bech32 address of the poster26	Msg    string // the message body27	Height int64  // block height at which it was posted28}2930// posts is the append-only wall, in chronological (oldest-first) order.31// Render reverses this view to show newest-first.32var posts []post3334// Post publishes msg to the wall. It is a crossing function: callers invoke it35// with Post(cross(cur), "hello"). It panics if msg is empty or longer than36// maxMsgLen bytes.37func Post(cur realm, msg string) {38	if !cur.IsCurrent() {39		panic("spoofed realm: cur is not the live crossing frame")40	}41	if len(msg) == 0 {42		panic("microblog: empty message")43	}44	if len(msg) > maxMsgLen {45		panic("microblog: message too long (max " + strconv.Itoa(maxMsgLen) + " bytes)")46	}4748	author := unsafe.PreviousRealm().Address()4950	posts = append(posts, post{51		Author: author.String(),52		Msg:    msg,53		Height: runtime.ChainHeight(),54	})5556	chain.Emit("Post", "author", author.String(), "len", strconv.Itoa(len(msg)))57}5859// Count returns the total number of posts on the wall.60func Count() int {61	return len(posts)62}6364// Render renders the wall as Markdown, newest-first, pageSize posts per page.65// The page is parsed from path: "?page=N", "?p=N", "/N", or a bare "N" all66// select page N (1-indexed). Anything else defaults to page 1.67func Render(path string) string {68	total := len(posts)69	page := parsePage(path)7071	var b strings.Builder72	b.WriteString("# Microblog Wall\n\n")7374	if total == 0 {75		b.WriteString("_No posts yet. Be the first to post._\n")76		return b.String()77	}7879	pages := (total + pageSize - 1) / pageSize80	if page < 1 {81		page = 182	}83	if page > pages {84		page = pages85	}8687	b.WriteString(strconv.Itoa(total))88	b.WriteString(" posts total · page ")89	b.WriteString(strconv.Itoa(page))90	b.WriteString(" of ")91	b.WriteString(strconv.Itoa(pages))92	b.WriteString("\n\n")9394	// Newest-first: post index total-1 is newest. For page p (1-indexed),95	// skip (p-1)*pageSize newest posts, then take up to pageSize.96	start := total - 1 - (page-1)*pageSize97	end := start - pageSize + 198	if end < 0 {99		end = 0100	}101102	for i := start; i >= end; i-- {103		p := posts[i]104		b.WriteString("- **")105		b.WriteString(shortAddr(p.Author))106		b.WriteString("** · height ")107		b.WriteString(strconv.FormatInt(p.Height, 10))108		b.WriteString("\n\n  ")109		b.WriteString(escapeInline(p.Msg))110		b.WriteString("\n")111	}112113	b.WriteString("\n")114	b.WriteString(renderNav(page, pages))115	return b.String()116}117118// renderNav builds a simple prev/next navigation footer as Markdown links.119func renderNav(page, pages int) string {120	var b strings.Builder121	if page > 1 {122		b.WriteString("[← newer](?page=")123		b.WriteString(strconv.Itoa(page - 1))124		b.WriteString(")")125	}126	if page > 1 && page < pages {127		b.WriteString(" · ")128	}129	if page < pages {130		b.WriteString("[older →](?page=")131		b.WriteString(strconv.Itoa(page + 1))132		b.WriteString(")")133	}134	if b.Len() == 0 {135		return ""136	}137	return b.String() + "\n"138}139140// parsePage extracts the 1-indexed page number from a Render path. It accepts141// "?page=N", "?p=N", "/N", and a bare "N". Unrecognized input yields page 1.142func parsePage(path string) int {143	path = strings.TrimSpace(path)144	if path == "" {145		return 1146	}147148	// Query form: "?page=2&foo=bar" or "?p=2".149	if idx := strings.IndexByte(path, '?'); idx >= 0 {150		query := path[idx+1:]151		for _, part := range strings.Split(query, "&") {152			kv := strings.SplitN(part, "=", 2)153			if len(kv) != 2 {154				continue155			}156			if kv[0] == "page" || kv[0] == "p" {157				if n, err := strconv.Atoi(strings.TrimSpace(kv[1])); err == nil {158					return n159				}160			}161		}162		return 1163	}164165	// Path form: "/2" or "2".166	seg := strings.TrimPrefix(path, "/")167	if n, err := strconv.Atoi(seg); err == nil {168		return n169	}170	return 1171}172173// shortAddr abbreviates a bech32 address for display: g1abcd…wxyz.174func shortAddr(addr string) string {175	if len(addr) <= 12 {176		return addr177	}178	return addr[:6] + "…" + addr[len(addr)-4:]179}180181// escapeInline neutralizes characters that would break the Markdown list item182// layout (newlines collapse to spaces; leading markers are defused).183func escapeInline(s string) string {184	s = strings.ReplaceAll(s, "\r\n", " ")185	s = strings.ReplaceAll(s, "\n", " ")186	s = strings.ReplaceAll(s, "\r", " ")187	return s188}189

Functions

  • Count() int

  • Post(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, msg string)

  • Render(path string) string

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.