xcvr tui

beepin and borpin

+2272 -43
+4
README.md
··· 1 + # tty!xcvr 2 + 3 + talk to you! transceiver is everyone's favorite ATP application, brought to 4 + the teletypewriter!
+233
diff.go
··· 1 + package main 2 + 3 + import () 4 + 5 + type EditType = int 6 + 7 + const ( 8 + EditAdd EditType = iota 9 + EditKeep 10 + EditDel 11 + EditNil 12 + ) 13 + 14 + type Edit struct { 15 + EditType EditType 16 + Utf16Text []uint16 17 + } 18 + 19 + type Editstring struct { 20 + EditType EditType 21 + Text string 22 + } 23 + 24 + type EditSegment struct { 25 + weight int 26 + aidx int 27 + bidx int 28 + parent *EditSegment 29 + } 30 + 31 + type coordinate struct { 32 + a int 33 + b int 34 + } 35 + 36 + type SegmentHeap struct { 37 + segments []*EditSegment 38 + searched map[coordinate]bool 39 + } 40 + 41 + func NewSegmentHeap() SegmentHeap { 42 + segments := make([]*EditSegment, 0, 10) 43 + searched := make(map[coordinate]bool) 44 + return SegmentHeap{segments, searched} 45 + } 46 + 47 + func (h *SegmentHeap) Add(seg *EditSegment) { 48 + searched := h.searched[coordinate{seg.aidx, seg.bidx}] 49 + if searched { 50 + return 51 + } 52 + h.segments = append(h.segments, seg) 53 + h.searched[coordinate{seg.aidx, seg.bidx}] = true 54 + h.siftUp(len(h.segments) - 1) 55 + } 56 + 57 + func (h *SegmentHeap) PopFront() *EditSegment { 58 + if len(h.segments) == 0 { 59 + return nil 60 + } 61 + front := h.segments[0] 62 + if len(h.segments) == 1 { 63 + h.segments = nil 64 + return front 65 + } 66 + h.segments[0] = h.segments[len(h.segments)-1] 67 + h.segments = h.segments[:len(h.segments)-1] 68 + h.siftDown(0) 69 + return front 70 + } 71 + 72 + func (h *SegmentHeap) siftUp(idx int) { 73 + if idx == 0 { 74 + return 75 + } 76 + loweridx := idx 77 + upperidx := (idx - 1) / 2 78 + lower := h.segments[loweridx] 79 + upper := h.segments[upperidx] 80 + if lower.lighter(upper) { 81 + h.segments[upperidx] = lower 82 + h.segments[loweridx] = upper 83 + h.siftUp(upperidx) 84 + } 85 + } 86 + 87 + func (h *SegmentHeap) siftDown(idx int) { 88 + upperidx := idx 89 + var swap *EditSegment 90 + loweridx := idx*2 + 1 91 + lower2idx := idx*2 + 2 92 + if loweridx < len(h.segments) && h.segments[loweridx].lighter(h.segments[upperidx]) { 93 + swap = h.segments[upperidx] 94 + h.segments[upperidx] = h.segments[loweridx] 95 + h.segments[loweridx] = swap 96 + h.siftDown(loweridx) 97 + return 98 + } 99 + if lower2idx < len(h.segments) && h.segments[lower2idx].lighter(h.segments[upperidx]) { 100 + swap = h.segments[upperidx] 101 + h.segments[upperidx] = h.segments[lower2idx] 102 + h.segments[lower2idx] = swap 103 + h.siftDown(lower2idx) 104 + return 105 + } 106 + 107 + } 108 + 109 + func (seg *EditSegment) lighter(A *EditSegment) bool { 110 + if seg.weight < A.weight { 111 + return true 112 + } else if seg.weight > A.weight { 113 + return false 114 + } else { 115 + return seg.aidx+seg.bidx > A.aidx+A.bidx 116 + } 117 + } 118 + 119 + // Diff calculates the diff between wordA and wordB as a miniaml slice of 120 + // edits that you have to make to wordA so that you end up with wordB 121 + func Diff(wordA []uint16, wordB []uint16) []Edit { 122 + heap := NewSegmentHeap() 123 + head := EditSegment{0, 0, 0, nil} 124 + heap.Add(&head) 125 + segment := heap.PopFront() 126 + for !(segment.aidx == len(wordA) && segment.bidx == len(wordB)) { 127 + if segment.aidx != len(wordA) && 128 + segment.bidx != len(wordB) && 129 + wordA[segment.aidx] == wordB[segment.bidx] { 130 + newSegment := EditSegment{segment.weight, segment.aidx + 1, segment.bidx + 1, segment} 131 + heap.Add(&newSegment) 132 + } 133 + if segment.aidx != len(wordA) { 134 + newSegment := EditSegment{segment.weight + 1, segment.aidx + 1, segment.bidx, segment} 135 + heap.Add(&newSegment) 136 + } 137 + if segment.bidx != len(wordB) { 138 + newSegment := EditSegment{segment.weight + 1, segment.aidx, segment.bidx + 1, segment} 139 + heap.Add(&newSegment) 140 + } 141 + segment = heap.PopFront() 142 + } 143 + prevSegment := segment.parent 144 + edits := make([]Edit, 0) 145 + currentEdit := Edit{EditNil, nil} 146 + for prevSegment != nil { 147 + diffA := prevSegment.aidx != segment.aidx 148 + diffB := prevSegment.bidx != segment.bidx 149 + var et EditType 150 + var char uint16 151 + if diffA && diffB { 152 + et = EditKeep 153 + char = wordA[prevSegment.aidx] 154 + } else if diffA { 155 + et = EditDel 156 + char = wordA[prevSegment.aidx] 157 + } else if diffB { 158 + et = EditAdd 159 + char = wordB[prevSegment.bidx] 160 + } else { 161 + et = EditNil 162 + } 163 + if currentEdit.EditType != et { 164 + if currentEdit.EditType != EditNil { 165 + edits = append([]Edit{currentEdit}, edits...) 166 + } 167 + currentEdit = Edit{et, []uint16{char}} 168 + } else { 169 + currentEdit.Utf16Text = append([]uint16{char}, currentEdit.Utf16Text...) 170 + } 171 + segment = prevSegment 172 + prevSegment = segment.parent 173 + } 174 + edits = append([]Edit{currentEdit}, edits...) 175 + return edits 176 + } 177 + 178 + func Diffs(wordA string, wordB string) []Editstring { 179 + heap := NewSegmentHeap() 180 + head := EditSegment{0, 0, 0, nil} 181 + heap.Add(&head) 182 + segment := heap.PopFront() 183 + for !(segment.aidx == len(wordA) && segment.bidx == len(wordB)) { 184 + if segment.aidx != len(wordA) && 185 + segment.bidx != len(wordB) && 186 + wordA[segment.aidx] == wordB[segment.bidx] { 187 + newSegment := EditSegment{segment.weight, segment.aidx + 1, segment.bidx + 1, segment} 188 + heap.Add(&newSegment) 189 + } 190 + if segment.aidx != len(wordA) { 191 + newSegment := EditSegment{segment.weight + 1, segment.aidx + 1, segment.bidx, segment} 192 + heap.Add(&newSegment) 193 + } 194 + if segment.bidx != len(wordB) { 195 + newSegment := EditSegment{segment.weight + 1, segment.aidx, segment.bidx + 1, segment} 196 + heap.Add(&newSegment) 197 + } 198 + segment = heap.PopFront() 199 + } 200 + prevSegment := segment.parent 201 + edits := make([]Editstring, 0) 202 + currentEdit := Editstring{EditNil, ""} 203 + for prevSegment != nil { 204 + diffA := prevSegment.aidx != segment.aidx 205 + diffB := prevSegment.bidx != segment.bidx 206 + var et EditType 207 + var char string 208 + if diffA && diffB { 209 + et = EditKeep 210 + char = string(wordA[prevSegment.aidx]) 211 + } else if diffA { 212 + et = EditDel 213 + char = string(wordA[prevSegment.aidx]) 214 + } else if diffB { 215 + et = EditAdd 216 + char = string(wordB[prevSegment.bidx]) 217 + } else { 218 + et = EditNil 219 + } 220 + if currentEdit.EditType != et { 221 + if currentEdit.EditType != EditNil { 222 + edits = append([]Editstring{currentEdit}, edits...) 223 + } 224 + currentEdit = Editstring{et, char} 225 + } else { 226 + currentEdit.Text = char + currentEdit.Text 227 + } 228 + segment = prevSegment 229 + prevSegment = segment.parent 230 + } 231 + edits = append([]Editstring{currentEdit}, edits...) 232 + return edits 233 + }
+32 -5
go.mod
··· 3 3 go 1.24.2 4 4 5 5 require ( 6 + github.com/bluesky-social/indigo v0.0.0-20250925152209-0f22fe8b39a8 6 7 github.com/charmbracelet/bubbles v0.21.0 7 8 github.com/charmbracelet/bubbletea v1.3.10 9 + github.com/charmbracelet/lipgloss v1.1.0 10 + github.com/gorilla/websocket v1.5.3 11 + github.com/ipfs/go-cid v0.4.1 12 + github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c 13 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e 14 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 15 + google.golang.org/protobuf v1.36.6 8 16 ) 9 17 10 18 require ( 11 19 github.com/atotto/clipboard v0.1.4 // indirect 12 20 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 21 + github.com/beorn7/perks v1.0.1 // indirect 22 + github.com/carlmjohnson/versioninfo v0.22.5 // indirect 23 + github.com/cespare/xxhash/v2 v2.2.0 // indirect 13 24 github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect 14 - github.com/charmbracelet/lipgloss v1.1.0 // indirect 15 25 github.com/charmbracelet/x/ansi v0.10.1 // indirect 16 26 github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect 17 27 github.com/charmbracelet/x/term v0.2.1 // indirect 18 28 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 19 - github.com/gorilla/websocket v1.5.3 // indirect 29 + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect 30 + github.com/klauspost/cpuid/v2 v2.2.7 // indirect 20 31 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 21 32 github.com/mattn/go-isatty v0.0.20 // indirect 22 33 github.com/mattn/go-localereader v0.0.1 // indirect 23 34 github.com/mattn/go-runewidth v0.0.16 // indirect 35 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect 36 + github.com/minio/sha256-simd v1.0.1 // indirect 37 + github.com/mr-tron/base58 v1.2.0 // indirect 24 38 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 25 39 github.com/muesli/cancelreader v0.2.2 // indirect 26 40 github.com/muesli/termenv v0.16.0 // indirect 27 - github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c // indirect 41 + github.com/multiformats/go-base32 v0.1.0 // indirect 42 + github.com/multiformats/go-base36 v0.2.0 // indirect 43 + github.com/multiformats/go-multibase v0.2.0 // indirect 44 + github.com/multiformats/go-multihash v0.2.3 // indirect 45 + github.com/multiformats/go-varint v0.0.7 // indirect 46 + github.com/prometheus/client_golang v1.17.0 // indirect 47 + github.com/prometheus/client_model v0.5.0 // indirect 48 + github.com/prometheus/common v0.45.0 // indirect 49 + github.com/prometheus/procfs v0.12.0 // indirect 28 50 github.com/rivo/uniseg v0.4.7 // indirect 29 51 github.com/sahilm/fuzzy v0.1.1 // indirect 52 + github.com/spaolacci/murmur3 v1.1.0 // indirect 30 53 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 54 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 55 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect 56 + golang.org/x/crypto v0.21.0 // indirect 31 57 golang.org/x/sys v0.36.0 // indirect 32 - golang.org/x/text v0.3.8 // indirect 33 - google.golang.org/protobuf v1.36.6 // indirect 58 + golang.org/x/text v0.14.0 // indirect 59 + golang.org/x/time v0.3.0 // indirect 60 + lukechampine.com/blake3 v1.2.1 // indirect 34 61 )
+127 -4
go.sum
··· 4 4 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 5 5 github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= 6 6 github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= 7 + github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 8 + github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 9 + github.com/bluesky-social/indigo v0.0.0-20250925152209-0f22fe8b39a8 h1:+YD75cZtvj0uFVOjb8XglqJ4Ev4UFKyAvzR3TOMREW0= 10 + github.com/bluesky-social/indigo v0.0.0-20250925152209-0f22fe8b39a8/go.mod h1:n6QE1NDPFoi7PRbMUZmc2y7FibCqiVU4ePpsvhHUBR8= 11 + github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc= 12 + github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8= 13 + github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 14 + github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 7 15 github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= 8 16 github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= 9 17 github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= ··· 20 28 github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= 21 29 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 22 30 github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 31 + github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 32 + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 23 33 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 24 34 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 35 + github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 36 + github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 37 + github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 38 + github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 39 + github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 40 + github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 41 + github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 42 + github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 43 + github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 44 + github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 45 + github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= 46 + github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 25 47 github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= 26 48 github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 49 + github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 50 + github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 51 + github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= 52 + github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= 53 + github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= 54 + github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 55 + github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= 56 + github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 57 + github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 58 + github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 59 + github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= 60 + github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= 61 + github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 62 + github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 63 + github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= 64 + github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= 65 + github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ= 66 + github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= 67 + github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw= 68 + github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo= 69 + github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= 70 + github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= 71 + github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs= 72 + github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk= 73 + github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= 74 + github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= 75 + github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= 76 + github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= 77 + github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= 78 + github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= 79 + github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= 80 + github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= 81 + github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= 82 + github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= 83 + github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= 84 + github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 27 85 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 28 86 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 29 87 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= ··· 34 92 github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 35 93 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 36 94 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 95 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= 96 + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 97 + github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= 98 + github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 99 + github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 100 + github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 37 101 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 38 102 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 39 103 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 40 104 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 41 105 github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= 42 106 github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= 107 + github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 108 + github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 109 + github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= 110 + github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= 111 + github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= 112 + github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= 113 + github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= 114 + github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 115 + github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= 116 + github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 117 + github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= 118 + github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= 119 + github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 120 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 121 + github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= 122 + github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= 123 + github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= 124 + github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= 125 + github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= 126 + github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 127 + github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= 128 + github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= 129 + github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= 130 + github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= 43 131 github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c h1:t33xVlfSwvB80nj1jroRXUaq/RTgjWwD4l7p/ISatUQ= 44 132 github.com/rachel-mp4/lrcproto v0.0.0-20250905154858-2ddb78e31d0c/go.mod h1:hQzO36tQELGbkmRnUtKeM6NMU34t79ZcTlhM+MO7pHw= 45 133 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= ··· 47 135 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 48 136 github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= 49 137 github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= 138 + github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 139 + github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 140 + github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 141 + github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 142 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4= 143 + github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 50 144 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= 51 145 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 52 - golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= 53 - golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= 146 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= 147 + gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 148 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= 149 + gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= 150 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= 151 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= 152 + go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= 153 + go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= 154 + go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= 155 + go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= 156 + go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= 157 + go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= 158 + go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 159 + go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 160 + go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 161 + go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 162 + go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= 163 + go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= 164 + golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= 165 + golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 166 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= 167 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= 54 168 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 169 + golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 55 170 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 56 171 golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= 57 172 golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 58 - golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= 59 - golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 173 + golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 174 + golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 175 + golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= 176 + golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 177 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= 178 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 60 179 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 61 180 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 181 + gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 182 + gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 183 + lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= 184 + lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+1207
lex/lexicons_cbor.go
··· 1 + // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. 2 + 3 + package lex 4 + 5 + import ( 6 + "fmt" 7 + "io" 8 + "math" 9 + "sort" 10 + 11 + util "github.com/bluesky-social/indigo/lex/util" 12 + cid "github.com/ipfs/go-cid" 13 + cbg "github.com/whyrusleeping/cbor-gen" 14 + xerrors "golang.org/x/xerrors" 15 + ) 16 + 17 + var _ = xerrors.Errorf 18 + var _ = cid.Undef 19 + var _ = math.E 20 + var _ = sort.Sort 21 + 22 + func (t *ProfileRecord) MarshalCBOR(w io.Writer) error { 23 + if t == nil { 24 + _, err := w.Write(cbg.CborNull) 25 + return err 26 + } 27 + 28 + cw := cbg.NewCborWriter(w) 29 + fieldCount := 6 30 + 31 + if t.DisplayName == nil { 32 + fieldCount-- 33 + } 34 + 35 + if t.DefaultNick == nil { 36 + fieldCount-- 37 + } 38 + 39 + if t.Status == nil { 40 + fieldCount-- 41 + } 42 + 43 + if t.Avatar == nil { 44 + fieldCount-- 45 + } 46 + 47 + if t.Color == nil { 48 + fieldCount-- 49 + } 50 + 51 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 52 + return err 53 + } 54 + 55 + // t.LexiconTypeID (string) (string) 56 + if len("$type") > 8192 { 57 + return xerrors.Errorf("Value in field \"$type\" was too long") 58 + } 59 + 60 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 61 + return err 62 + } 63 + if _, err := cw.WriteString(string("$type")); err != nil { 64 + return err 65 + } 66 + 67 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.actor.profile"))); err != nil { 68 + return err 69 + } 70 + if _, err := cw.WriteString(string("org.xcvr.actor.profile")); err != nil { 71 + return err 72 + } 73 + 74 + // t.Color (uint64) (uint64) 75 + if t.Color != nil { 76 + 77 + if len("color") > 8192 { 78 + return xerrors.Errorf("Value in field \"color\" was too long") 79 + } 80 + 81 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("color"))); err != nil { 82 + return err 83 + } 84 + if _, err := cw.WriteString(string("color")); err != nil { 85 + return err 86 + } 87 + 88 + if t.Color == nil { 89 + if _, err := cw.Write(cbg.CborNull); err != nil { 90 + return err 91 + } 92 + } else { 93 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(*t.Color)); err != nil { 94 + return err 95 + } 96 + } 97 + 98 + } 99 + 100 + // t.Avatar (util.LexBlob) (struct) 101 + if t.Avatar != nil { 102 + 103 + if len("avatar") > 8192 { 104 + return xerrors.Errorf("Value in field \"avatar\" was too long") 105 + } 106 + 107 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("avatar"))); err != nil { 108 + return err 109 + } 110 + if _, err := cw.WriteString(string("avatar")); err != nil { 111 + return err 112 + } 113 + 114 + if err := t.Avatar.MarshalCBOR(cw); err != nil { 115 + return err 116 + } 117 + } 118 + 119 + // t.Status (string) (string) 120 + if t.Status != nil { 121 + 122 + if len("status") > 8192 { 123 + return xerrors.Errorf("Value in field \"status\" was too long") 124 + } 125 + 126 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("status"))); err != nil { 127 + return err 128 + } 129 + if _, err := cw.WriteString(string("status")); err != nil { 130 + return err 131 + } 132 + 133 + if t.Status == nil { 134 + if _, err := cw.Write(cbg.CborNull); err != nil { 135 + return err 136 + } 137 + } else { 138 + if len(*t.Status) > 8192 { 139 + return xerrors.Errorf("Value in field t.Status was too long") 140 + } 141 + 142 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.Status))); err != nil { 143 + return err 144 + } 145 + if _, err := cw.WriteString(string(*t.Status)); err != nil { 146 + return err 147 + } 148 + } 149 + } 150 + 151 + // t.DefaultNick (string) (string) 152 + if t.DefaultNick != nil { 153 + 154 + if len("defaultNick") > 8192 { 155 + return xerrors.Errorf("Value in field \"defaultNick\" was too long") 156 + } 157 + 158 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("defaultNick"))); err != nil { 159 + return err 160 + } 161 + if _, err := cw.WriteString(string("defaultNick")); err != nil { 162 + return err 163 + } 164 + 165 + if t.DefaultNick == nil { 166 + if _, err := cw.Write(cbg.CborNull); err != nil { 167 + return err 168 + } 169 + } else { 170 + if len(*t.DefaultNick) > 8192 { 171 + return xerrors.Errorf("Value in field t.DefaultNick was too long") 172 + } 173 + 174 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.DefaultNick))); err != nil { 175 + return err 176 + } 177 + if _, err := cw.WriteString(string(*t.DefaultNick)); err != nil { 178 + return err 179 + } 180 + } 181 + } 182 + 183 + // t.DisplayName (string) (string) 184 + if t.DisplayName != nil { 185 + 186 + if len("displayName") > 8192 { 187 + return xerrors.Errorf("Value in field \"displayName\" was too long") 188 + } 189 + 190 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("displayName"))); err != nil { 191 + return err 192 + } 193 + if _, err := cw.WriteString(string("displayName")); err != nil { 194 + return err 195 + } 196 + 197 + if t.DisplayName == nil { 198 + if _, err := cw.Write(cbg.CborNull); err != nil { 199 + return err 200 + } 201 + } else { 202 + if len(*t.DisplayName) > 8192 { 203 + return xerrors.Errorf("Value in field t.DisplayName was too long") 204 + } 205 + 206 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.DisplayName))); err != nil { 207 + return err 208 + } 209 + if _, err := cw.WriteString(string(*t.DisplayName)); err != nil { 210 + return err 211 + } 212 + } 213 + } 214 + return nil 215 + } 216 + 217 + func (t *ProfileRecord) UnmarshalCBOR(r io.Reader) (err error) { 218 + *t = ProfileRecord{} 219 + 220 + cr := cbg.NewCborReader(r) 221 + 222 + maj, extra, err := cr.ReadHeader() 223 + if err != nil { 224 + return err 225 + } 226 + defer func() { 227 + if err == io.EOF { 228 + err = io.ErrUnexpectedEOF 229 + } 230 + }() 231 + 232 + if maj != cbg.MajMap { 233 + return fmt.Errorf("cbor input should be of type map") 234 + } 235 + 236 + if extra > cbg.MaxLength { 237 + return fmt.Errorf("ProfileRecord: map struct too large (%d)", extra) 238 + } 239 + 240 + n := extra 241 + 242 + nameBuf := make([]byte, 11) 243 + for i := uint64(0); i < n; i++ { 244 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 245 + if err != nil { 246 + return err 247 + } 248 + 249 + if !ok { 250 + // Field doesn't exist on this type, so ignore it 251 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 252 + return err 253 + } 254 + continue 255 + } 256 + 257 + switch string(nameBuf[:nameLen]) { 258 + // t.LexiconTypeID (string) (string) 259 + case "$type": 260 + 261 + { 262 + sval, err := cbg.ReadStringWithMax(cr, 8192) 263 + if err != nil { 264 + return err 265 + } 266 + 267 + t.LexiconTypeID = string(sval) 268 + } 269 + // t.Color (uint64) (uint64) 270 + case "color": 271 + 272 + { 273 + 274 + b, err := cr.ReadByte() 275 + if err != nil { 276 + return err 277 + } 278 + if b != cbg.CborNull[0] { 279 + if err := cr.UnreadByte(); err != nil { 280 + return err 281 + } 282 + maj, extra, err = cr.ReadHeader() 283 + if err != nil { 284 + return err 285 + } 286 + if maj != cbg.MajUnsignedInt { 287 + return fmt.Errorf("wrong type for uint64 field") 288 + } 289 + typed := uint64(extra) 290 + t.Color = &typed 291 + } 292 + 293 + } 294 + // t.Avatar (util.LexBlob) (struct) 295 + case "avatar": 296 + 297 + { 298 + 299 + b, err := cr.ReadByte() 300 + if err != nil { 301 + return err 302 + } 303 + if b != cbg.CborNull[0] { 304 + if err := cr.UnreadByte(); err != nil { 305 + return err 306 + } 307 + t.Avatar = new(util.LexBlob) 308 + if err := t.Avatar.UnmarshalCBOR(cr); err != nil { 309 + return xerrors.Errorf("unmarshaling t.Avatar pointer: %w", err) 310 + } 311 + } 312 + 313 + } 314 + // t.Status (string) (string) 315 + case "status": 316 + 317 + { 318 + b, err := cr.ReadByte() 319 + if err != nil { 320 + return err 321 + } 322 + if b != cbg.CborNull[0] { 323 + if err := cr.UnreadByte(); err != nil { 324 + return err 325 + } 326 + 327 + sval, err := cbg.ReadStringWithMax(cr, 8192) 328 + if err != nil { 329 + return err 330 + } 331 + 332 + t.Status = (*string)(&sval) 333 + } 334 + } 335 + // t.DefaultNick (string) (string) 336 + case "defaultNick": 337 + 338 + { 339 + b, err := cr.ReadByte() 340 + if err != nil { 341 + return err 342 + } 343 + if b != cbg.CborNull[0] { 344 + if err := cr.UnreadByte(); err != nil { 345 + return err 346 + } 347 + 348 + sval, err := cbg.ReadStringWithMax(cr, 8192) 349 + if err != nil { 350 + return err 351 + } 352 + 353 + t.DefaultNick = (*string)(&sval) 354 + } 355 + } 356 + // t.DisplayName (string) (string) 357 + case "displayName": 358 + 359 + { 360 + b, err := cr.ReadByte() 361 + if err != nil { 362 + return err 363 + } 364 + if b != cbg.CborNull[0] { 365 + if err := cr.UnreadByte(); err != nil { 366 + return err 367 + } 368 + 369 + sval, err := cbg.ReadStringWithMax(cr, 8192) 370 + if err != nil { 371 + return err 372 + } 373 + 374 + t.DisplayName = (*string)(&sval) 375 + } 376 + } 377 + 378 + default: 379 + // Field doesn't exist on this type, so ignore it 380 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 381 + return err 382 + } 383 + } 384 + } 385 + 386 + return nil 387 + } 388 + func (t *ChannelRecord) MarshalCBOR(w io.Writer) error { 389 + if t == nil { 390 + _, err := w.Write(cbg.CborNull) 391 + return err 392 + } 393 + 394 + cw := cbg.NewCborWriter(w) 395 + fieldCount := 5 396 + 397 + if t.Topic == nil { 398 + fieldCount-- 399 + } 400 + 401 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 402 + return err 403 + } 404 + 405 + // t.Host (string) (string) 406 + if len("host") > 8192 { 407 + return xerrors.Errorf("Value in field \"host\" was too long") 408 + } 409 + 410 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("host"))); err != nil { 411 + return err 412 + } 413 + if _, err := cw.WriteString(string("host")); err != nil { 414 + return err 415 + } 416 + 417 + if len(t.Host) > 8192 { 418 + return xerrors.Errorf("Value in field t.Host was too long") 419 + } 420 + 421 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Host))); err != nil { 422 + return err 423 + } 424 + if _, err := cw.WriteString(string(t.Host)); err != nil { 425 + return err 426 + } 427 + 428 + // t.LexiconTypeID (string) (string) 429 + if len("$type") > 8192 { 430 + return xerrors.Errorf("Value in field \"$type\" was too long") 431 + } 432 + 433 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 434 + return err 435 + } 436 + if _, err := cw.WriteString(string("$type")); err != nil { 437 + return err 438 + } 439 + 440 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.feed.channel"))); err != nil { 441 + return err 442 + } 443 + if _, err := cw.WriteString(string("org.xcvr.feed.channel")); err != nil { 444 + return err 445 + } 446 + 447 + // t.Title (string) (string) 448 + if len("title") > 8192 { 449 + return xerrors.Errorf("Value in field \"title\" was too long") 450 + } 451 + 452 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("title"))); err != nil { 453 + return err 454 + } 455 + if _, err := cw.WriteString(string("title")); err != nil { 456 + return err 457 + } 458 + 459 + if len(t.Title) > 8192 { 460 + return xerrors.Errorf("Value in field t.Title was too long") 461 + } 462 + 463 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Title))); err != nil { 464 + return err 465 + } 466 + if _, err := cw.WriteString(string(t.Title)); err != nil { 467 + return err 468 + } 469 + 470 + // t.Topic (string) (string) 471 + if t.Topic != nil { 472 + 473 + if len("topic") > 8192 { 474 + return xerrors.Errorf("Value in field \"topic\" was too long") 475 + } 476 + 477 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("topic"))); err != nil { 478 + return err 479 + } 480 + if _, err := cw.WriteString(string("topic")); err != nil { 481 + return err 482 + } 483 + 484 + if t.Topic == nil { 485 + if _, err := cw.Write(cbg.CborNull); err != nil { 486 + return err 487 + } 488 + } else { 489 + if len(*t.Topic) > 8192 { 490 + return xerrors.Errorf("Value in field t.Topic was too long") 491 + } 492 + 493 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.Topic))); err != nil { 494 + return err 495 + } 496 + if _, err := cw.WriteString(string(*t.Topic)); err != nil { 497 + return err 498 + } 499 + } 500 + } 501 + 502 + // t.CreatedAt (string) (string) 503 + if len("createdAt") > 8192 { 504 + return xerrors.Errorf("Value in field \"createdAt\" was too long") 505 + } 506 + 507 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil { 508 + return err 509 + } 510 + if _, err := cw.WriteString(string("createdAt")); err != nil { 511 + return err 512 + } 513 + 514 + if len(t.CreatedAt) > 8192 { 515 + return xerrors.Errorf("Value in field t.CreatedAt was too long") 516 + } 517 + 518 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 519 + return err 520 + } 521 + if _, err := cw.WriteString(string(t.CreatedAt)); err != nil { 522 + return err 523 + } 524 + return nil 525 + } 526 + 527 + func (t *ChannelRecord) UnmarshalCBOR(r io.Reader) (err error) { 528 + *t = ChannelRecord{} 529 + 530 + cr := cbg.NewCborReader(r) 531 + 532 + maj, extra, err := cr.ReadHeader() 533 + if err != nil { 534 + return err 535 + } 536 + defer func() { 537 + if err == io.EOF { 538 + err = io.ErrUnexpectedEOF 539 + } 540 + }() 541 + 542 + if maj != cbg.MajMap { 543 + return fmt.Errorf("cbor input should be of type map") 544 + } 545 + 546 + if extra > cbg.MaxLength { 547 + return fmt.Errorf("ChannelRecord: map struct too large (%d)", extra) 548 + } 549 + 550 + n := extra 551 + 552 + nameBuf := make([]byte, 9) 553 + for i := uint64(0); i < n; i++ { 554 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 555 + if err != nil { 556 + return err 557 + } 558 + 559 + if !ok { 560 + // Field doesn't exist on this type, so ignore it 561 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 562 + return err 563 + } 564 + continue 565 + } 566 + 567 + switch string(nameBuf[:nameLen]) { 568 + // t.Host (string) (string) 569 + case "host": 570 + 571 + { 572 + sval, err := cbg.ReadStringWithMax(cr, 8192) 573 + if err != nil { 574 + return err 575 + } 576 + 577 + t.Host = string(sval) 578 + } 579 + // t.LexiconTypeID (string) (string) 580 + case "$type": 581 + 582 + { 583 + sval, err := cbg.ReadStringWithMax(cr, 8192) 584 + if err != nil { 585 + return err 586 + } 587 + 588 + t.LexiconTypeID = string(sval) 589 + } 590 + // t.Title (string) (string) 591 + case "title": 592 + 593 + { 594 + sval, err := cbg.ReadStringWithMax(cr, 8192) 595 + if err != nil { 596 + return err 597 + } 598 + 599 + t.Title = string(sval) 600 + } 601 + // t.Topic (string) (string) 602 + case "topic": 603 + 604 + { 605 + b, err := cr.ReadByte() 606 + if err != nil { 607 + return err 608 + } 609 + if b != cbg.CborNull[0] { 610 + if err := cr.UnreadByte(); err != nil { 611 + return err 612 + } 613 + 614 + sval, err := cbg.ReadStringWithMax(cr, 8192) 615 + if err != nil { 616 + return err 617 + } 618 + 619 + t.Topic = (*string)(&sval) 620 + } 621 + } 622 + // t.CreatedAt (string) (string) 623 + case "createdAt": 624 + 625 + { 626 + sval, err := cbg.ReadStringWithMax(cr, 8192) 627 + if err != nil { 628 + return err 629 + } 630 + 631 + t.CreatedAt = string(sval) 632 + } 633 + 634 + default: 635 + // Field doesn't exist on this type, so ignore it 636 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 637 + return err 638 + } 639 + } 640 + } 641 + 642 + return nil 643 + } 644 + func (t *MessageRecord) MarshalCBOR(w io.Writer) error { 645 + if t == nil { 646 + _, err := w.Write(cbg.CborNull) 647 + return err 648 + } 649 + 650 + cw := cbg.NewCborWriter(w) 651 + fieldCount := 6 652 + 653 + if t.Nick == nil { 654 + fieldCount-- 655 + } 656 + 657 + if t.Color == nil { 658 + fieldCount-- 659 + } 660 + 661 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 662 + return err 663 + } 664 + 665 + // t.Body (string) (string) 666 + if len("body") > 8192 { 667 + return xerrors.Errorf("Value in field \"body\" was too long") 668 + } 669 + 670 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("body"))); err != nil { 671 + return err 672 + } 673 + if _, err := cw.WriteString(string("body")); err != nil { 674 + return err 675 + } 676 + 677 + if len(t.Body) > 8192 { 678 + return xerrors.Errorf("Value in field t.Body was too long") 679 + } 680 + 681 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Body))); err != nil { 682 + return err 683 + } 684 + if _, err := cw.WriteString(string(t.Body)); err != nil { 685 + return err 686 + } 687 + 688 + // t.Nick (string) (string) 689 + if t.Nick != nil { 690 + 691 + if len("nick") > 8192 { 692 + return xerrors.Errorf("Value in field \"nick\" was too long") 693 + } 694 + 695 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("nick"))); err != nil { 696 + return err 697 + } 698 + if _, err := cw.WriteString(string("nick")); err != nil { 699 + return err 700 + } 701 + 702 + if t.Nick == nil { 703 + if _, err := cw.Write(cbg.CborNull); err != nil { 704 + return err 705 + } 706 + } else { 707 + if len(*t.Nick) > 8192 { 708 + return xerrors.Errorf("Value in field t.Nick was too long") 709 + } 710 + 711 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.Nick))); err != nil { 712 + return err 713 + } 714 + if _, err := cw.WriteString(string(*t.Nick)); err != nil { 715 + return err 716 + } 717 + } 718 + } 719 + 720 + // t.LexiconTypeID (string) (string) 721 + if len("$type") > 8192 { 722 + return xerrors.Errorf("Value in field \"$type\" was too long") 723 + } 724 + 725 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 726 + return err 727 + } 728 + if _, err := cw.WriteString(string("$type")); err != nil { 729 + return err 730 + } 731 + 732 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.lrc.message"))); err != nil { 733 + return err 734 + } 735 + if _, err := cw.WriteString(string("org.xcvr.lrc.message")); err != nil { 736 + return err 737 + } 738 + 739 + // t.Color (uint64) (uint64) 740 + if t.Color != nil { 741 + 742 + if len("color") > 8192 { 743 + return xerrors.Errorf("Value in field \"color\" was too long") 744 + } 745 + 746 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("color"))); err != nil { 747 + return err 748 + } 749 + if _, err := cw.WriteString(string("color")); err != nil { 750 + return err 751 + } 752 + 753 + if t.Color == nil { 754 + if _, err := cw.Write(cbg.CborNull); err != nil { 755 + return err 756 + } 757 + } else { 758 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(*t.Color)); err != nil { 759 + return err 760 + } 761 + } 762 + 763 + } 764 + 765 + // t.PostedAt (string) (string) 766 + if len("postedAt") > 8192 { 767 + return xerrors.Errorf("Value in field \"postedAt\" was too long") 768 + } 769 + 770 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("postedAt"))); err != nil { 771 + return err 772 + } 773 + if _, err := cw.WriteString(string("postedAt")); err != nil { 774 + return err 775 + } 776 + 777 + if len(t.PostedAt) > 8192 { 778 + return xerrors.Errorf("Value in field t.PostedAt was too long") 779 + } 780 + 781 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.PostedAt))); err != nil { 782 + return err 783 + } 784 + if _, err := cw.WriteString(string(t.PostedAt)); err != nil { 785 + return err 786 + } 787 + 788 + // t.SignetURI (string) (string) 789 + if len("signetURI") > 8192 { 790 + return xerrors.Errorf("Value in field \"signetURI\" was too long") 791 + } 792 + 793 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("signetURI"))); err != nil { 794 + return err 795 + } 796 + if _, err := cw.WriteString(string("signetURI")); err != nil { 797 + return err 798 + } 799 + 800 + if len(t.SignetURI) > 8192 { 801 + return xerrors.Errorf("Value in field t.SignetURI was too long") 802 + } 803 + 804 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.SignetURI))); err != nil { 805 + return err 806 + } 807 + if _, err := cw.WriteString(string(t.SignetURI)); err != nil { 808 + return err 809 + } 810 + return nil 811 + } 812 + 813 + func (t *MessageRecord) UnmarshalCBOR(r io.Reader) (err error) { 814 + *t = MessageRecord{} 815 + 816 + cr := cbg.NewCborReader(r) 817 + 818 + maj, extra, err := cr.ReadHeader() 819 + if err != nil { 820 + return err 821 + } 822 + defer func() { 823 + if err == io.EOF { 824 + err = io.ErrUnexpectedEOF 825 + } 826 + }() 827 + 828 + if maj != cbg.MajMap { 829 + return fmt.Errorf("cbor input should be of type map") 830 + } 831 + 832 + if extra > cbg.MaxLength { 833 + return fmt.Errorf("MessageRecord: map struct too large (%d)", extra) 834 + } 835 + 836 + n := extra 837 + 838 + nameBuf := make([]byte, 9) 839 + for i := uint64(0); i < n; i++ { 840 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 841 + if err != nil { 842 + return err 843 + } 844 + 845 + if !ok { 846 + // Field doesn't exist on this type, so ignore it 847 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 848 + return err 849 + } 850 + continue 851 + } 852 + 853 + switch string(nameBuf[:nameLen]) { 854 + // t.Body (string) (string) 855 + case "body": 856 + 857 + { 858 + sval, err := cbg.ReadStringWithMax(cr, 8192) 859 + if err != nil { 860 + return err 861 + } 862 + 863 + t.Body = string(sval) 864 + } 865 + // t.Nick (string) (string) 866 + case "nick": 867 + 868 + { 869 + b, err := cr.ReadByte() 870 + if err != nil { 871 + return err 872 + } 873 + if b != cbg.CborNull[0] { 874 + if err := cr.UnreadByte(); err != nil { 875 + return err 876 + } 877 + 878 + sval, err := cbg.ReadStringWithMax(cr, 8192) 879 + if err != nil { 880 + return err 881 + } 882 + 883 + t.Nick = (*string)(&sval) 884 + } 885 + } 886 + // t.LexiconTypeID (string) (string) 887 + case "$type": 888 + 889 + { 890 + sval, err := cbg.ReadStringWithMax(cr, 8192) 891 + if err != nil { 892 + return err 893 + } 894 + 895 + t.LexiconTypeID = string(sval) 896 + } 897 + // t.Color (uint64) (uint64) 898 + case "color": 899 + 900 + { 901 + 902 + b, err := cr.ReadByte() 903 + if err != nil { 904 + return err 905 + } 906 + if b != cbg.CborNull[0] { 907 + if err := cr.UnreadByte(); err != nil { 908 + return err 909 + } 910 + maj, extra, err = cr.ReadHeader() 911 + if err != nil { 912 + return err 913 + } 914 + if maj != cbg.MajUnsignedInt { 915 + return fmt.Errorf("wrong type for uint64 field") 916 + } 917 + typed := uint64(extra) 918 + t.Color = &typed 919 + } 920 + 921 + } 922 + // t.PostedAt (string) (string) 923 + case "postedAt": 924 + 925 + { 926 + sval, err := cbg.ReadStringWithMax(cr, 8192) 927 + if err != nil { 928 + return err 929 + } 930 + 931 + t.PostedAt = string(sval) 932 + } 933 + // t.SignetURI (string) (string) 934 + case "signetURI": 935 + 936 + { 937 + sval, err := cbg.ReadStringWithMax(cr, 8192) 938 + if err != nil { 939 + return err 940 + } 941 + 942 + t.SignetURI = string(sval) 943 + } 944 + 945 + default: 946 + // Field doesn't exist on this type, so ignore it 947 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 948 + return err 949 + } 950 + } 951 + } 952 + 953 + return nil 954 + } 955 + func (t *SignetRecord) MarshalCBOR(w io.Writer) error { 956 + if t == nil { 957 + _, err := w.Write(cbg.CborNull) 958 + return err 959 + } 960 + 961 + cw := cbg.NewCborWriter(w) 962 + fieldCount := 5 963 + 964 + if t.StartedAt == nil { 965 + fieldCount-- 966 + } 967 + 968 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 969 + return err 970 + } 971 + 972 + // t.Author (string) (string) 973 + if len("nick") > 8192 { 974 + return xerrors.Errorf("Value in field \"nick\" was too long") 975 + } 976 + 977 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("nick"))); err != nil { 978 + return err 979 + } 980 + if _, err := cw.WriteString(string("nick")); err != nil { 981 + return err 982 + } 983 + 984 + if len(t.AuthorHandle) > 8192 { 985 + return xerrors.Errorf("Value in field t.Author was too long") 986 + } 987 + 988 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.AuthorHandle))); err != nil { 989 + return err 990 + } 991 + if _, err := cw.WriteString(string(t.AuthorHandle)); err != nil { 992 + return err 993 + } 994 + 995 + // t.LexiconTypeID (string) (string) 996 + if len("$type") > 8192 { 997 + return xerrors.Errorf("Value in field \"$type\" was too long") 998 + } 999 + 1000 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 1001 + return err 1002 + } 1003 + if _, err := cw.WriteString(string("$type")); err != nil { 1004 + return err 1005 + } 1006 + 1007 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("org.xcvr.lrc.signet"))); err != nil { 1008 + return err 1009 + } 1010 + if _, err := cw.WriteString(string("org.xcvr.lrc.signet")); err != nil { 1011 + return err 1012 + } 1013 + 1014 + // t.LRCID (uint64) (uint64) 1015 + if len("lrcID") > 8192 { 1016 + return xerrors.Errorf("Value in field \"lrcID\" was too long") 1017 + } 1018 + 1019 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("lrcID"))); err != nil { 1020 + return err 1021 + } 1022 + if _, err := cw.WriteString(string("lrcID")); err != nil { 1023 + return err 1024 + } 1025 + 1026 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.LRCID)); err != nil { 1027 + return err 1028 + } 1029 + 1030 + // t.StartedAt (string) (string) 1031 + if t.StartedAt != nil { 1032 + 1033 + if len("startedAt") > 8192 { 1034 + return xerrors.Errorf("Value in field \"startedAt\" was too long") 1035 + } 1036 + 1037 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("startedAt"))); err != nil { 1038 + return err 1039 + } 1040 + if _, err := cw.WriteString(string("startedAt")); err != nil { 1041 + return err 1042 + } 1043 + 1044 + if t.StartedAt == nil { 1045 + if _, err := cw.Write(cbg.CborNull); err != nil { 1046 + return err 1047 + } 1048 + } else { 1049 + if len(*t.StartedAt) > 8192 { 1050 + return xerrors.Errorf("Value in field t.StartedAt was too long") 1051 + } 1052 + 1053 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.StartedAt))); err != nil { 1054 + return err 1055 + } 1056 + if _, err := cw.WriteString(string(*t.StartedAt)); err != nil { 1057 + return err 1058 + } 1059 + } 1060 + } 1061 + 1062 + // t.ChannelURI (string) (string) 1063 + if len("channelURI") > 8192 { 1064 + return xerrors.Errorf("Value in field \"channelURI\" was too long") 1065 + } 1066 + 1067 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("channelURI"))); err != nil { 1068 + return err 1069 + } 1070 + if _, err := cw.WriteString(string("channelURI")); err != nil { 1071 + return err 1072 + } 1073 + 1074 + if len(t.ChannelURI) > 8192 { 1075 + return xerrors.Errorf("Value in field t.ChannelURI was too long") 1076 + } 1077 + 1078 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.ChannelURI))); err != nil { 1079 + return err 1080 + } 1081 + if _, err := cw.WriteString(string(t.ChannelURI)); err != nil { 1082 + return err 1083 + } 1084 + return nil 1085 + } 1086 + 1087 + func (t *SignetRecord) UnmarshalCBOR(r io.Reader) (err error) { 1088 + *t = SignetRecord{} 1089 + 1090 + cr := cbg.NewCborReader(r) 1091 + 1092 + maj, extra, err := cr.ReadHeader() 1093 + if err != nil { 1094 + return err 1095 + } 1096 + defer func() { 1097 + if err == io.EOF { 1098 + err = io.ErrUnexpectedEOF 1099 + } 1100 + }() 1101 + 1102 + if maj != cbg.MajMap { 1103 + return fmt.Errorf("cbor input should be of type map") 1104 + } 1105 + 1106 + if extra > cbg.MaxLength { 1107 + return fmt.Errorf("SignetRecord: map struct too large (%d)", extra) 1108 + } 1109 + 1110 + n := extra 1111 + 1112 + nameBuf := make([]byte, 10) 1113 + for i := uint64(0); i < n; i++ { 1114 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 1115 + if err != nil { 1116 + return err 1117 + } 1118 + 1119 + if !ok { 1120 + // Field doesn't exist on this type, so ignore it 1121 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 1122 + return err 1123 + } 1124 + continue 1125 + } 1126 + 1127 + switch string(nameBuf[:nameLen]) { 1128 + // t.Author (string) (string) 1129 + case "authorHandle": 1130 + 1131 + { 1132 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1133 + if err != nil { 1134 + return err 1135 + } 1136 + 1137 + t.AuthorHandle = string(sval) 1138 + } 1139 + // t.LexiconTypeID (string) (string) 1140 + case "$type": 1141 + 1142 + { 1143 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1144 + if err != nil { 1145 + return err 1146 + } 1147 + 1148 + t.LexiconTypeID = string(sval) 1149 + } 1150 + // t.LRCID (uint64) (uint64) 1151 + case "lrcID": 1152 + 1153 + { 1154 + 1155 + maj, extra, err = cr.ReadHeader() 1156 + if err != nil { 1157 + return err 1158 + } 1159 + if maj != cbg.MajUnsignedInt { 1160 + return fmt.Errorf("wrong type for uint64 field") 1161 + } 1162 + t.LRCID = uint64(extra) 1163 + 1164 + } 1165 + // t.StartedAt (string) (string) 1166 + case "startedAt": 1167 + 1168 + { 1169 + b, err := cr.ReadByte() 1170 + if err != nil { 1171 + return err 1172 + } 1173 + if b != cbg.CborNull[0] { 1174 + if err := cr.UnreadByte(); err != nil { 1175 + return err 1176 + } 1177 + 1178 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1179 + if err != nil { 1180 + return err 1181 + } 1182 + 1183 + t.StartedAt = (*string)(&sval) 1184 + } 1185 + } 1186 + // t.ChannelURI (string) (string) 1187 + case "channelURI": 1188 + 1189 + { 1190 + sval, err := cbg.ReadStringWithMax(cr, 8192) 1191 + if err != nil { 1192 + return err 1193 + } 1194 + 1195 + t.ChannelURI = string(sval) 1196 + } 1197 + 1198 + default: 1199 + // Field doesn't exist on this type, so ignore it 1200 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 1201 + return err 1202 + } 1203 + } 1204 + } 1205 + 1206 + return nil 1207 + }
+71
lex/types.go
··· 1 + package lex 2 + 3 + import ( 4 + "github.com/bluesky-social/indigo/lex/util" 5 + ) 6 + 7 + func init() { 8 + util.RegisterType("org.xcvr.actor.profile", &ProfileRecord{}) 9 + util.RegisterType("org.xcvr.feed.channel", &ChannelRecord{}) 10 + util.RegisterType("org.xcvr.lrc.message", &MessageRecord{}) 11 + util.RegisterType("org.xcvr.lrc.signet", &SignetRecord{}) 12 + } 13 + 14 + type ProfileRecord struct { 15 + LexiconTypeID string `json:"$type,const=org.xcvr.actor.profile" cborgen:"$type,const=org.xcvr.actor.profile"` 16 + DisplayName *string `json:"displayName,omitempty" cborgen:"displayName,omitempty"` 17 + DefaultNick *string `json:"defaultNick,omitempty" cborgen:"defaultNick,omitempty"` 18 + Status *string `json:"status,omitempty" cborgen:"status,omitempty"` 19 + Avatar *util.LexBlob `json:"avatar,omitempty" cborgen:"avatar,omitempty"` 20 + Color *uint64 `json:"color,omitempty" cborgen:"color,omitempty"` 21 + } 22 + 23 + type ChannelRecord struct { 24 + LexiconTypeID string `json:"$type,const=org.xcvr.feed.channel" cborgen:"$type,const=org.xcvr.feed.channel"` 25 + Title string `json:"title" cborgen:"title"` 26 + Topic *string `json:"topic,omitempty" cborgen:"topic,omitempty"` 27 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 28 + Host string `json:"host" cborgen:"host"` 29 + } 30 + 31 + type MessageRecord struct { 32 + LexiconTypeID string `json:"$type,const=org.xcvr.lrc.message" cborgen:"$type,const=org.xcvr.lrc.message"` 33 + SignetURI string `json:"signetURI" cborgen:"signetURI"` 34 + Body string `json:"body" cborgen:"body"` 35 + Nick *string `json:"nick,omitempty" cborgen:"nick,omitempty"` 36 + Color *uint64 `json:"color,omitempty" cborgen:"color,omitempty"` 37 + PostedAt string `json:"postedAt" cborgen:"postedAt"` 38 + } 39 + 40 + type SignetRecord struct { 41 + LexiconTypeID string `json:"$type,const=org.xcvr.lrc.signet" cborgen:"$type,const=org.xcvr.lrc.signet"` 42 + ChannelURI string `json:"channelURI" cborgen:"channelURI"` 43 + LRCID uint64 `json:"lrcID" cborgen:"lrcID"` 44 + AuthorHandle string `json:"authorHandle" cborgen:"authorHandle"` 45 + StartedAt *string `json:"startedAt,omitempty" cborgen:"startedAt,omitempty"` 46 + } 47 + 48 + type MediaRecord struct { 49 + LexiconTypeID string `json:"$type,const=org.xcvr.lrc.media" cborgen:"$type,const=org.xcvr.lrc.media"` 50 + SignetURI string `json:"signetURI" cborgen:"signetURI"` 51 + Media Media `json:"media" cborgen:"media"` 52 + Nick *string `json:"nick,omitempty" cborgen:"nick,omitempty"` 53 + Color *uint64 `json:"color,omitempty" cborgen:"color,omitempty"` 54 + PostedAt string `json:"postedAt" cborgen:"postedAt"` 55 + } 56 + 57 + type Media struct { 58 + Image *Image 59 + } 60 + 61 + type Image struct { 62 + LexiconTypeID string `json:"$type,const=org.xcvr.lrc.image" cborgen:"$type,const=org.xcvr.lrc.image"` 63 + Alt string `json:"alt" cborgen:"alt"` 64 + AspectRatio *AspectRatio `json:"aspectRatio,omitempty" cborgen:"aspectRatio,omitempty"` 65 + Image *util.BlobSchema `json:"image,omitempty" cborgen:"image,omitempty"` 66 + } 67 + 68 + type AspectRatio struct { 69 + Height int64 `json:"height" cborgen:"height"` 70 + Width int64 `json:"width" cborgen:"width"` 71 + }
+598 -34
main.go
··· 8 8 "io" 9 9 "net/http" 10 10 "os" 11 + "strconv" 11 12 "strings" 12 13 "time" 13 14 "unicode/utf16" 14 15 16 + "github.com/bluesky-social/indigo/api/atproto" 17 + "github.com/bluesky-social/indigo/atproto/client" 18 + "github.com/bluesky-social/indigo/atproto/identity" 19 + "github.com/bluesky-social/indigo/atproto/syntax" 20 + "github.com/bluesky-social/indigo/lex/util" 15 21 "github.com/charmbracelet/bubbles/list" 22 + "github.com/charmbracelet/bubbles/textinput" 16 23 "github.com/charmbracelet/bubbles/viewport" 17 24 tea "github.com/charmbracelet/bubbletea" 18 25 "github.com/charmbracelet/lipgloss" 19 26 "github.com/gorilla/websocket" 20 27 "github.com/rachel-mp4/lrcproto/gen/go" 28 + "github.com/rachel-mp4/ttyxcvr/lex" 21 29 "google.golang.org/protobuf/proto" 22 30 ) 23 31 ··· 60 68 width int 61 69 height int 62 70 error *error 63 - command *string 71 + prompt textinput.Model 72 + draft *textinput.Model 73 + sentmsg *string 64 74 channels *[]Channel 65 75 list *list.Model 66 76 curchannel *Channel 67 77 wsurl *string 68 78 lrcconn *websocket.Conn 79 + lexconn *websocket.Conn 80 + evtchan chan []byte 69 81 cancel func() 70 82 vp *viewport.Model 71 83 msgs map[uint32]*Message 84 + myid *uint32 72 85 renders []*string 73 86 topic *string 74 87 color *uint32 75 88 nick *string 76 89 handle *string 90 + signeturi *string 91 + xrpc *PasswordClient 77 92 } 78 93 79 94 type Message struct { ··· 140 155 var desc string 141 156 var uri string 142 157 var host string 158 + var color *uint32 159 + var author string 143 160 if i, ok := item.(ChannelItem); ok { 144 161 title = i.Title() 145 162 desc = i.Description() 146 - host = subduedStyle.Render(fmt.Sprintf("(hosted by %s)", i.Host())) 163 + author = fmt.Sprintf("(%s)", renderName(i.channel.Creator.DisplayName, i.channel.Creator.Handle)) 164 + host = subduedStyle.Render(fmt.Sprintf("(hosted on %s)", i.Host())) 147 165 if desc == "" { 148 166 desc = subduedStyle.Render("no provided description") 149 167 } 150 168 uri = i.URI() 169 + color = i.channel.Creator.Color 151 170 } else { 152 171 return 153 172 } 154 173 if index == m.Index() { 155 - greenStyle := lipgloss.NewStyle().Foreground(Green) 156 - title = fmt.Sprintf("│%s %s", greenStyle.Render(title), host) 174 + greenStyle := lipgloss.NewStyle().Foreground(ColorFromInt(color)) 175 + title = fmt.Sprintf("│%s %s", greenStyle.Render(title), author) 157 176 desc = fmt.Sprintf("│%s", desc) 158 177 uri = fmt.Sprintf("└%s", strings.Repeat("─", m.Width()-1)) 159 178 } else { 160 179 s := lipgloss.NewStyle() 161 180 s = s.Foreground(subduedColor) 162 181 uri = s.Render(uri) 182 + host = subduedStyle.Render(author) 163 183 } 164 184 fmt.Fprintf(w, "%s %s\n%s\n%s", title, host, desc, uri) 165 185 } 166 186 167 187 func initialModel() model { 188 + prompt := textinput.New() 189 + prompt.Prompt = ":" 190 + nick := "wanderer" 191 + color := uint32(33096) 168 192 return model{ 169 193 state: Splash, 170 194 mode: Normal, 195 + prompt: prompt, 171 196 width: 30, 172 197 height: 20, 198 + nick: &nick, 199 + color: &color, 173 200 } 174 201 } 175 202 func (m model) Init() tea.Cmd { ··· 213 240 214 241 type errMsg struct{ err error } 215 242 243 + func login(handle string, secret string) tea.Cmd { 244 + return func() tea.Msg { 245 + hdl, err := syntax.ParseHandle(handle) 246 + if err != nil { 247 + err = errors.New("handle failed to parse: " + err.Error()) 248 + return errMsg{err} 249 + } 250 + id, err := identity.DefaultDirectory().LookupHandle(context.Background(), hdl) 251 + if err != nil { 252 + err = errors.New("handle failed to loopup: " + err.Error()) 253 + return errMsg{err} 254 + } 255 + xrpc := NewPasswordClient(id.DID.String(), id.PDSEndpoint()) 256 + err = xrpc.CreateSession(context.Background(), handle, secret) 257 + if err != nil { 258 + return errMsg{err} 259 + } 260 + return loggedInMsg{xrpc} 261 + } 262 + } 263 + 264 + type loggedInMsg struct { 265 + xrpc *PasswordClient 266 + } 267 + 216 268 func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 217 269 switch msg := msg.(type) { 218 270 case errMsg: 219 271 m.state = Error 220 272 m.error = &msg.err 273 + return m, nil 274 + case svMsg: 275 + if m.myid != nil && msg.signetView.LrcId == *m.myid { 276 + m.signeturi = &msg.signetView.URI 277 + return m, nil 278 + } 279 + 280 + case loginMsg: 281 + if len(msg.value) == 2 { 282 + return m, login(msg.value[0], msg.value[1]) 283 + } 284 + case loggedInMsg: 285 + m.xrpc = msg.xrpc 286 + return m, nil 287 + 288 + case setMsg: 289 + key, val, found := strings.Cut(msg.value, "=") 290 + if !found { 291 + return m, nil 292 + } 293 + switch key { 294 + case "color", "c": 295 + i, err := strconv.Atoi(val) 296 + if err != nil { 297 + return m, nil 298 + } 299 + b := uint32(i) 300 + m.color = &b 301 + if m.draft != nil { 302 + m.draft.PromptStyle = lipgloss.NewStyle().Foreground(ColorFromInt(&b)) 303 + } 304 + err = sendSet(m.evtchan, m.nick, m.handle, m.color) 305 + if err != nil { 306 + send(errMsg{err}) 307 + } 308 + return m, nil 309 + case "nick", "name", "n": 310 + m.nick = &val 311 + if m.draft != nil { 312 + m.draft.Prompt = renderName(m.nick, m.handle) + " " 313 + } 314 + err := sendSet(m.evtchan, m.nick, m.handle, m.color) 315 + if err != nil { 316 + send(errMsg{err}) 317 + } 318 + return m, nil 319 + case "handle", "h", "at", "@": 320 + m.handle = &val 321 + if m.draft != nil { 322 + m.draft.Prompt = renderName(m.nick, m.handle) + " " 323 + } 324 + err := sendSet(m.evtchan, m.nick, m.handle, m.color) 325 + if err != nil { 326 + send(errMsg{err}) 327 + } 328 + return m, nil 329 + } 221 330 222 331 case tea.WindowSizeMsg: 223 332 m.height = msg.Height 224 333 m.width = msg.Width 334 + if m.vp != nil { 335 + m.vp.Width = msg.Width 336 + m.vp.Height = msg.Height - 2 337 + } 338 + if m.renders != nil { 339 + for _, message := range m.msgs { 340 + message.renderMessage(msg.Width) 341 + } 342 + m.vp.SetContent(JoinDeref(m.renders, "")) 343 + } 344 + if m.list != nil { 345 + m.list.SetSize(msg.Width, msg.Height) 346 + } 347 + return m, nil 225 348 226 349 case tea.KeyMsg: 227 350 switch msg.String() { ··· 257 380 m.error = &err 258 381 return m, nil 259 382 } 383 + id := msg.e.Id 260 384 switch msg := msg.e.Msg.(type) { 261 385 case *lrcpb.Event_Ping: 262 386 return m, nil ··· 269 393 m.error = &err 270 394 return m, nil 271 395 } 396 + if msg.Init.Echoed != nil && *msg.Init.Echoed { 397 + m.myid = msg.Init.Id 398 + } 272 399 m.vp.SetContent(JoinDeref(m.renders, "")) 273 400 return m, nil 274 401 case *lrcpb.Event_Pub: ··· 310 437 } 311 438 return m, nil 312 439 case *lrcpb.Event_Editbatch: 440 + if id == nil { 441 + return m, nil 442 + } 443 + err := editMessage(*id, msg.Editbatch.Edits, m.msgs, &m.renders, m.width) 444 + if err != nil { 445 + m.state = Error 446 + m.error = &err 447 + return m, nil 448 + } 449 + m.vp.SetContent(JoinDeref(m.renders, "")) 313 450 return m, nil 451 + } 452 + case tea.KeyMsg: 453 + switch m.mode { 454 + case Normal: 455 + switch msg.String() { 456 + case "i", "a": 457 + m.mode = Insert 458 + return m, m.draft.Focus() 459 + case ":": 460 + m.mode = Command 461 + return m, m.prompt.Focus() 462 + } 463 + case Insert: 464 + switch msg.String() { 465 + case "esc": 466 + m.mode = Normal 467 + m.draft.Blur() 468 + return m, nil 469 + case "enter": 470 + if m.sentmsg != nil { 471 + if m.xrpc != nil && m.signeturi != nil { 472 + var color64 *uint64 473 + if m.color != nil { 474 + c64 := uint64(*m.color) 475 + color64 = &c64 476 + } 477 + lmr := lex.MessageRecord{ 478 + SignetURI: *m.signeturi, 479 + Body: *m.sentmsg, 480 + Nick: m.nick, 481 + Color: color64, 482 + PostedAt: syntax.DatetimeNow().String(), 483 + } 484 + m.draft.SetValue("") 485 + m.sentmsg = nil 486 + m.myid = nil 487 + m.signeturi = nil 488 + return m, tea.Batch(sendPub(m.lrcconn), createMSGCmd(m.xrpc, &lmr)) 489 + } 490 + m.draft.SetValue("") 491 + m.sentmsg = nil 492 + return m, sendPub(m.lrcconn) 493 + } 494 + return m, nil 495 + } 496 + case Command: 497 + switch msg.String() { 498 + case "esc": 499 + m.mode = Normal 500 + m.prompt.Blur() 501 + m.prompt.SetValue("") 502 + return m, nil 503 + case "enter": 504 + m.mode = Normal 505 + m.prompt.Blur() 506 + v := m.prompt.Value() 507 + m.prompt.SetValue("") 508 + return m, evaluateCommand(v) 509 + default: 510 + } 511 + } 512 + } 513 + switch m.mode { 514 + case Normal: 515 + vp, cmd := m.vp.Update(msg) 516 + m.vp = &vp 517 + return m, cmd 518 + case Command: 519 + prompt, cmd := m.prompt.Update(msg) 520 + m.prompt = prompt 521 + return m, cmd 522 + case Insert: 523 + draft, cmd := m.draft.Update(msg) 524 + if m.sentmsg == nil && draft.Value() != "" { 525 + nv := draft.Value() 526 + m.sentmsg = &nv 527 + m.draft = &draft 528 + return m, tea.Batch(cmd, sendInsert(m.lrcconn, nv, 0, true)) 529 + } 530 + if m.sentmsg != nil && *m.sentmsg != draft.Value() { 531 + draftutf16 := utf16.Encode([]rune(draft.Value())) 532 + sentutf16 := utf16.Encode([]rune(*m.sentmsg)) 533 + edits := Diff(sentutf16, draftutf16) 534 + m.draft = &draft 535 + sentmsg := draft.Value() 536 + m.sentmsg = &sentmsg 537 + return m, tea.Batch(cmd, sendEditBatch(m.evtchan, edits)) 538 + } 539 + m.draft = &draft 540 + return m, cmd 541 + } 542 + return m, nil 543 + } 314 544 545 + func createMSGCmd(xrpc *PasswordClient, lmr *lex.MessageRecord) tea.Cmd { 546 + return func() tea.Msg { 547 + _, _, err := xrpc.CreateXCVRMessage(lmr, context.Background()) 548 + if err != nil { 549 + return errMsg{err} 315 550 } 551 + return nil 316 552 } 317 - vp, cmd := m.vp.Update(msg) 318 - m.vp = &vp 319 - return m, cmd 553 + } 554 + 555 + func sendEditBatch(datachan chan []byte, edits []Edit) tea.Cmd { 556 + return func() tea.Msg { 557 + idx := 0 558 + batch := make([]*lrcpb.Edit, 0) 559 + for _, edit := range edits { 560 + switch edit.EditType { 561 + case EditDel: 562 + idx2 := idx + len(edit.Utf16Text) 563 + evt := makeDelete(uint32(idx), uint32(idx2)) 564 + edit := lrcpb.Edit{Edit: &lrcpb.Edit_Delete{Delete: evt.GetDelete()}} 565 + batch = append(batch, &edit) 566 + case EditKeep: 567 + idx = idx + len(edit.Utf16Text) 568 + case EditAdd: 569 + evt := makeInsert(string(utf16.Decode(edit.Utf16Text)), uint32(idx)) 570 + idx = idx + len(edit.Utf16Text) 571 + edit := lrcpb.Edit{Edit: &lrcpb.Edit_Insert{Insert: evt.GetInsert()}} 572 + batch = append(batch, &edit) 573 + } 574 + } 575 + evt := lrcpb.Event{Msg: &lrcpb.Event_Editbatch{Editbatch: &lrcpb.EditBatch{Edits: batch}}} 576 + data, err := proto.Marshal(&evt) 577 + if err != nil { 578 + return errMsg{err} 579 + } 580 + datachan <- data 581 + return nil 582 + } 583 + } 584 + 585 + func sendPub(conn *websocket.Conn) tea.Cmd { 586 + return func() tea.Msg { 587 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Pub{Pub: &lrcpb.Pub{}}} 588 + data, err := proto.Marshal(evt) 589 + if err != nil { 590 + return errMsg{err} 591 + } 592 + err = conn.WriteMessage(websocket.BinaryMessage, data) 593 + if err != nil { 594 + return errMsg{err} 595 + } 596 + return nil 597 + } 598 + } 599 + 600 + func makeDelete(start uint32, end uint32) *lrcpb.Event { 601 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Delete{Delete: &lrcpb.Delete{Utf16Start: start, Utf16End: end}}} 602 + return evt 603 + } 604 + 605 + func makeInsert(body string, idx uint32) *lrcpb.Event { 606 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Insert{Insert: &lrcpb.Insert{Body: body, Utf16Index: idx}}} 607 + return evt 608 + } 609 + 610 + func sendInsert(conn *websocket.Conn, body string, utf16idx uint32, init bool) tea.Cmd { 611 + return func() tea.Msg { 612 + if init { 613 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Init{Init: &lrcpb.Init{}}} 614 + data, err := proto.Marshal(evt) 615 + if err != nil { 616 + return errMsg{err} 617 + } 618 + if conn == nil { 619 + return nil 620 + } 621 + err = conn.WriteMessage(websocket.BinaryMessage, data) 622 + if err != nil { 623 + return errMsg{err} 624 + } 625 + } 626 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Insert{Insert: &lrcpb.Insert{Body: body, Utf16Index: utf16idx}}} 627 + data, err := proto.Marshal(evt) 628 + if err != nil { 629 + return errMsg{err} 630 + } 631 + err = conn.WriteMessage(websocket.BinaryMessage, data) 632 + if err != nil { 633 + return errMsg{err} 634 + } 635 + return nil 636 + } 637 + } 638 + 639 + func evaluateCommand(command string) tea.Cmd { 640 + return func() tea.Msg { 641 + parts := strings.Split(command, " ") 642 + if parts == nil { 643 + return nil 644 + } 645 + switch parts[0] { 646 + case "q": 647 + return tea.QuitMsg{} 648 + case "se", "set": 649 + if len(parts) != 1 { 650 + return setMsg{parts[1]} 651 + } 652 + case "resize": 653 + return tea.WindowSize() 654 + case "login": 655 + if len(parts) != 1 { 656 + return loginMsg{parts[1:]} 657 + } 658 + } 659 + return nil 660 + } 661 + } 662 + 663 + type loginMsg struct { 664 + value []string 665 + } 666 + 667 + type setMsg struct { 668 + value string 320 669 } 321 670 322 671 // i think that the type of renders is a bit awkward, but i want deletemessage + friends to just modify the rendered ··· 372 721 result = append(result, baseUTF16Units[end:]...) 373 722 resultRunes := utf16.Decode(result) 374 723 return string(resultRunes) 724 + } 725 + 726 + func editMessage(id uint32, edits []*lrcpb.Edit, msgmap map[uint32]*Message, renders *[]*string, width int) error { 727 + for _, edit := range edits { 728 + switch e := edit.Edit.(type) { 729 + case *lrcpb.Edit_Insert: 730 + ins := e.Insert 731 + ins.Id = &id 732 + err := insertMessage(ins, msgmap, renders, width) 733 + if err != nil { 734 + return err 735 + } 736 + case *lrcpb.Edit_Delete: 737 + del := e.Delete 738 + del.Id = &id 739 + err := deleteMessage(del, msgmap, renders, width) 740 + if err != nil { 741 + return err 742 + } 743 + } 744 + } 745 + return nil 375 746 } 376 747 377 748 func insertMessage(msg *lrcpb.Insert, msgmap map[uint32]*Message, renders *[]*string, width int) error { ··· 474 845 return 475 846 } 476 847 stylem := lipgloss.NewStyle().Width(width).Align(lipgloss.Left) 477 - styleh := stylem.Foreground(Green) 848 + styleh := stylem.Foreground(ColorFromInt(m.color)) 478 849 if m.active { 479 850 styleh = styleh.Reverse(true) 480 851 stylem = styleh 481 852 } 482 - var nick string 483 - if m.nick != nil { 484 - nick = *m.nick 485 - } 486 - var handle string 487 - if m.handle != nil && *m.handle != "" { 488 - handle = fmt.Sprintf("@%s", *m.handle) 489 - } 490 - header := styleh.Render(fmt.Sprintf("%s%s", nick, handle)) 853 + header := styleh.Render(renderName(m.nick, m.handle)) 491 854 body := stylem.Render(m.text) 492 855 *m.rendered = fmt.Sprintf("%s\n%s\n", header, body) 493 856 } ··· 498 861 m.state = Connected 499 862 m.cancel = msg.cancel 500 863 m.msgs = make(map[uint32]*Message) 501 - vp := viewport.New(m.width, m.height-1) 864 + vp := viewport.New(m.width, m.height-2) 502 865 m.vp = &vp 503 - go startLRCHandlers(msg.conn) 866 + draft := textinput.New() 867 + draft.Prompt = renderName(m.nick, m.handle) + " " 868 + draft.PromptStyle = lipgloss.NewStyle().Foreground(ColorFromInt(m.color)) 869 + draft.Placeholder = "press i to start typing" 870 + draft.Width = m.width 871 + m.draft = &draft 872 + go startLRCHandlers(msg.conn, msg.lexconn, m.nick, m.handle, m.color) 873 + m.lrcconn = msg.conn 874 + m.lexconn = msg.lexconn 875 + m.evtchan = make(chan []byte) 876 + go LRCWriter(m.lrcconn, m.evtchan) 504 877 return m, nil 505 878 } 506 879 return m, nil 507 880 } 508 881 509 - func startLRCHandlers(conn *websocket.Conn) { 882 + func LRCWriter(conn *websocket.Conn, datachan chan []byte) { 883 + for data := range datachan { 884 + err := conn.WriteMessage(websocket.BinaryMessage, data) 885 + if err != nil { 886 + send(errMsg{err}) 887 + return 888 + } 889 + } 890 + } 891 + 892 + func renderName(nick *string, handle *string) string { 893 + var n string 894 + if nick != nil { 895 + n = *nick 896 + } 897 + var h string 898 + if handle != nil { 899 + h = fmt.Sprintf("@%s", *handle) 900 + } 901 + return fmt.Sprintf("%s%s", n, h) 902 + } 903 + 904 + func sendSet(datachan chan []byte, nick *string, handle *string, color *uint32) error { 905 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Set{Set: &lrcpb.Set{Nick: nick, ExternalID: handle, Color: color}}} 906 + data, err := proto.Marshal(evt) 907 + if err != nil { 908 + return err 909 + } 910 + datachan <- data 911 + return nil 912 + 913 + } 914 + 915 + func startLRCHandlers(conn *websocket.Conn, lexconn *websocket.Conn, nick *string, handle *string, color *uint32) { 510 916 if conn == nil { 511 917 send(errMsg{errors.New("provided nil conn")}) 512 918 return 513 919 } 514 - nick := "wanderer" 515 - evt := &lrcpb.Event{Msg: &lrcpb.Event_Set{Set: &lrcpb.Set{Nick: &nick}}} 920 + evt := &lrcpb.Event{Msg: &lrcpb.Event_Set{Set: &lrcpb.Set{Nick: nick, ExternalID: handle, Color: color}}} 516 921 data, err := proto.Marshal(evt) 517 922 if err != nil { 518 923 send(errMsg{errors.New("failed to marshal: " + err.Error())}) 519 924 return 520 925 } 926 + conn.WriteMessage(websocket.BinaryMessage, data) 521 927 522 - evt = &lrcpb.Event{Msg: &lrcpb.Event_Get{Get: &lrcpb.Get{Topic: &nick}}} 928 + bep := "bep" 929 + evt = &lrcpb.Event{Msg: &lrcpb.Event_Get{Get: &lrcpb.Get{Topic: &bep}}} 523 930 data, err = proto.Marshal(evt) 524 931 if err != nil { 525 932 send(errMsg{errors.New("failed to marshal: " + err.Error())}) ··· 527 934 } 528 935 conn.WriteMessage(websocket.BinaryMessage, data) 529 936 go listenToConn(conn) 937 + go listenToLexConn(lexconn) 938 + } 939 + 940 + type typedJSON struct { 941 + Type string `json:"$type"` 942 + } 943 + 944 + func listenToLexConn(conn *websocket.Conn) { 945 + for { 946 + var rawMsg json.RawMessage 947 + err := conn.ReadJSON(&rawMsg) 948 + if err != nil { 949 + send(errMsg{err}) 950 + return 951 + } 952 + var typed typedJSON 953 + err = json.Unmarshal(rawMsg, &typed) 954 + if err != nil { 955 + send(errMsg{err}) 956 + return 957 + } 958 + switch typed.Type { 959 + case "org.xcvr.lrc.defs#signetView": 960 + var sv SignetView 961 + err = json.Unmarshal(rawMsg, &sv) 962 + if err != nil { 963 + send(errMsg{err}) 964 + return 965 + } 966 + send(svMsg{&sv}) 967 + } 968 + } 969 + } 970 + 971 + type svMsg struct { 972 + signetView *SignetView 973 + } 974 + 975 + type SignetView struct { 976 + Type string `json:"$type,const=org.xcvr.lrc.defs#signetView"` 977 + URI string `json:"uri"` 978 + IssuerHandle string `json:"issuerHandle"` 979 + ChannelURI string `json:"channelURI"` 980 + LrcId uint32 `json:"lrcID"` 981 + AuthorHandle string `json:"authorHandle"` 982 + StartedAt time.Time `json:"startedAt"` 530 983 } 531 984 532 985 func listenToConn(conn *websocket.Conn) { ··· 568 1021 if err != nil { 569 1022 return errMsg{err} 570 1023 } 571 - return connMsg{conn, cancel} 1024 + 1025 + dialer = websocket.DefaultDialer 1026 + lexconn, _, err := dialer.DialContext(ctx, fmt.Sprintf("wss://xcvr.org/xrpc/org.xcvr.lrc.subscribeLexStream?uri=%s", m.curchannel.URI), http.Header{}) 1027 + if err != nil { 1028 + return errMsg{err} 1029 + } 1030 + return connMsg{conn, lexconn, cancel} 572 1031 } 573 1032 } 574 1033 575 1034 type connMsg struct { 576 - conn *websocket.Conn 577 - cancel func() 1035 + conn *websocket.Conn 1036 + lexconn *websocket.Conn 1037 + cancel func() 578 1038 } 579 1039 580 1040 const ( ··· 707 1167 } 708 1168 remainingspace := m.width - len(address) - len(topic) 709 1169 var footertext string 710 - if remainingspace < 1 { 711 - footertext = address 1170 + if m.mode == Command { 1171 + footertext = m.prompt.View() 1172 + } else if remainingspace < 1 { 1173 + footertext = fmt.Sprintf("%s%s", address, strings.Repeat(" ", m.width-len(address))) 712 1174 } else { 713 1175 footertext = fmt.Sprintf("%s%s%s", address, strings.Repeat(" ", remainingspace), topic) 714 1176 } 715 1177 insert := m.mode == Insert 716 - footerstyle := lipgloss.NewStyle().Foreground(Green).Reverse(insert) 1178 + footerstyle := lipgloss.NewStyle().Reverse(insert) 1179 + if m.mode != Command { 1180 + footerstyle = footerstyle.Foreground(ColorFromInt(m.color)) 1181 + } 717 1182 footer := footerstyle.Render(footertext) 718 - return fmt.Sprintf("%s\n%s", vpt, footer) 1183 + var draftText string 1184 + if m.draft != nil { 1185 + draftText = m.draft.View() 1186 + } 1187 + return fmt.Sprintf("%s\n%s\n%s", vpt, draftText, footer) 719 1188 } 1189 + 720 1190 func (m model) connectingView() string { 721 1191 blip := m.wsurl 722 1192 if blip == nil { ··· 731 1201 732 1202 func (m model) splashView() string { 733 1203 style := lipgloss.NewStyle().Foreground(Green) 734 - part1 := "\n %%%%%%% " 1204 + part00 := "\n ⣰⡀ ⢀⣀ ⡇ ⡇⡠ ⣰⡀ ⢀⡀ ⡀⢀ ⢀⡀ ⡀⢀ ⡇" 1205 + part01 := "\n ⠘⠤ ⠣⠼ ⠣ ⠏⠢ ⠘⠤ ⠣⠜ ⣑⡺ ⠣⠜ ⠣⠼ ⠅" 1206 + part02 := "\n ⣰⡀ ⡀⣀ ⢀⣀ ⣀⡀ ⢀⣀ ⢀⣀ ⢀⡀ ⠄ ⡀⢀ ⢀⡀ ⡀⣀" 1207 + part03 := "\n ⠘⠤ ⠏ ⠣⠼ ⠇⠸ ⠭⠕ ⠣⠤ ⠣⠭ ⠇ ⠱⠃ ⠣⠭ ⠏" 1208 + part1 := "\n\n %%%%%%% " 735 1209 text1 := "tty!xcvr\n" 736 1210 part2 := ` %%%%%%%%%% %%% % % %%%%%%%% 737 1211 %%%%%%%%%%%%%%%%% %%%% %%%%%%%%%%%%%%%%%% ··· 753 1227 press a key 754 1228 to start! 755 1229 ` 756 - s := fmt.Sprintf("%s%s%s%s%s%s%s%s%s", style.Render(part1), text1, style.Render(part2), style.Render(part25), text2, style.Render(part3), text3, style.Render(part4), text4) 757 - 758 - return s 1230 + s := fmt.Sprintf("\n\n\n\n%s%s%s%s%s%s%s%s%s%s%s%s%s", style.Render(part00), style.Render(part01), style.Render(part02), style.Render(part03), style.Render(part1), text1, style.Render(part2), style.Render(part25), text2, style.Render(part3), text3, style.Render(part4), text4) 1231 + offset := lipgloss.NewStyle().MarginLeft((m.width - 58) / 2) 1232 + return offset.Render(s) 759 1233 } 760 1234 761 1235 var send func(msg tea.Msg) ··· 899 1373 } 900 1374 return b.String() 901 1375 } 1376 + 1377 + type PasswordClient struct { 1378 + xrpc *client.APIClient 1379 + accessjwt *string 1380 + refreshjwt *string 1381 + did *string 1382 + } 1383 + 1384 + func NewPasswordClient(did string, host string) *PasswordClient { 1385 + return &PasswordClient{ 1386 + xrpc: client.NewAPIClient(host), 1387 + did: &did, 1388 + } 1389 + } 1390 + 1391 + func (c *PasswordClient) CreateSession(ctx context.Context, identity string, secret string) error { 1392 + input := atproto.ServerCreateSession_Input{ 1393 + Identifier: identity, 1394 + Password: secret, 1395 + } 1396 + var out atproto.ServerCreateSession_Output 1397 + err := c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.server.createSession", nil, input, &out) 1398 + if err != nil { 1399 + return errors.New("I couldn't create a session: " + err.Error()) 1400 + } 1401 + c.accessjwt = &out.AccessJwt 1402 + c.refreshjwt = &out.RefreshJwt 1403 + return nil 1404 + } 1405 + 1406 + func (c *PasswordClient) RefreshSession(ctx context.Context) error { 1407 + c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.refreshjwt)) 1408 + var out atproto.ServerRefreshSession_Output 1409 + err := c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.server.refreshSession", nil, nil, &out) 1410 + if err != nil { 1411 + return errors.New("failed to refresh session! " + err.Error()) 1412 + } 1413 + c.accessjwt = &out.AccessJwt 1414 + c.refreshjwt = &out.RefreshJwt 1415 + return nil 1416 + } 1417 + 1418 + func (c *PasswordClient) CreateXCVRMessage(message *lex.MessageRecord, ctx context.Context) (cid string, uri string, err error) { 1419 + input := atproto.RepoCreateRecord_Input{ 1420 + Collection: "org.xcvr.lrc.message", 1421 + Repo: *c.did, 1422 + Record: &util.LexiconTypeDecoder{Val: message}, 1423 + } 1424 + return c.createMyRecord(input, ctx) 1425 + } 1426 + 1427 + func (c *PasswordClient) createMyRecord(input atproto.RepoCreateRecord_Input, ctx context.Context) (cid string, uri string, err error) { 1428 + if c.accessjwt == nil { 1429 + err = errors.New("must create a session first") 1430 + return 1431 + } 1432 + c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt)) 1433 + var out atproto.RepoCreateRecord_Output 1434 + err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.createRecord", nil, input, &out) 1435 + if err != nil { 1436 + err1 := err.Error() 1437 + err = c.RefreshSession(ctx) 1438 + if err != nil { 1439 + err = errors.New(fmt.Sprintf("failed to refresh session while creating %s! first %s then %s", input.Collection, err1, err.Error())) 1440 + return 1441 + } 1442 + c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt)) 1443 + out = atproto.RepoCreateRecord_Output{} 1444 + err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.createRecord", nil, input, &out) 1445 + if err != nil { 1446 + err = errors.New(fmt.Sprintf("not good, failed to create %s after failing then refreshing session! first %s then %s", input.Collection, err1, err.Error())) 1447 + return 1448 + } 1449 + cid = out.Cid 1450 + uri = out.Uri 1451 + return 1452 + } 1453 + cid = out.Cid 1454 + uri = out.Uri 1455 + return 1456 + } 1457 + 1458 + func ColorFromInt(c *uint32) lipgloss.Color { 1459 + if c == nil { 1460 + return Green 1461 + } 1462 + ui := *c 1463 + guess := fmt.Sprintf("#%06x", ui) 1464 + return lipgloss.Color(guess[0:7]) 1465 + }