Documentation
¶
Overview ¶
Package address pkg/skychat/address/address.go c4-app-chat the skychat:// address grammar — one shareable, scannable identifier for the three things a user can open: a person, a group, a channel.
Grammar:
skychat://<pk> a person — opens a 1:1 DM skychat://<pk>/<group-id> a group or channel hosted by that visor
Both forms are short enough to print on a card and to encode in a low-density QR code, which is the whole reason they exist: an invite link (skychat:invite:<base64url(json)>) is a few hundred characters because it carries the group's port, mode, admin list and proof-of-work price inline, and a code that dense is unpleasant to scan on a phone.
The trade is that an address is NOT self-contained. A group address names a group but does not describe it, so acting on one requires asking the host visor what it is — see Manager.ProbeGroup. That round trip is also what makes "type a key and let the app work out what it is" possible at all: a bare public key looks identical whether it belongs to a person or to the host of a channel, so nothing can be decided by inspection.
Which of the two forms to hand out is therefore a real choice, not a preference: an address is short and stays valid as the group changes, an invite works while the host is offline. Both are accepted everywhere a user can paste — see the note on Parse and ErrIsInvite.
Why the group ID is a path segment and not, say, a query parameter: a query needs escaping rules that QR alphanumeric mode does not cover cheaply, and "host/resource" is the shape every user already reads correctly from a URL.
Index ¶
Constants ¶
const Scheme = "skychat://"
Scheme is the URI prefix of a skychat address.
The `//` form is deliberate and distinguishes this from the older `skychat:invite:` links: an authority-style `//<pk>` says the part after it is a host, which is exactly what a visor public key is here.
Variables ¶
var ( // ErrEmpty is returned for input that is blank once trimmed. ErrEmpty = errors.New("skychat address: empty") // ErrIsInvite marks input that is a group invite link rather than an // address. Returned as a distinct sentinel so a caller holding one // paste box can try both parsers and route accordingly, rather than // telling a user who pasted a perfectly good invite that their // address is malformed. ErrIsInvite = errors.New("skychat address: this is an invite link, not an address") )
Functions ¶
Types ¶
type Address ¶
type Address struct {
// PK is the visor the address names: the peer for a DM, the group's
// host for a group address.
PK cipher.PubKey
// GroupID is the group's UUID, empty for a DM address.
GroupID string
}
Address is a parsed skychat address.
func Parse ¶
Parse reads any of the accepted spellings of an address:
skychat://<pk> skychat://<pk>/<group-id> <pk> <pk>/<group-id>
The bare forms are accepted because the field this feeds used to take nothing but a raw public key, and every key a user has already saved or shared is in that shape. Requiring the scheme would have broken every one of them for no gain.
Whitespace is trimmed and a trailing slash ignored — both are what a terminal copy, a QR decode, or a chat client's link detector tend to leave behind. A group invite link returns ErrIsInvite so the caller can hand it to the invite parser instead.
func (Address) IsGroup ¶
IsGroup reports whether this address names a group or channel rather than a person.
type Kind ¶
type Kind string
Kind is what an address points at.
const ( // KindDM — a bare public key: a person, opened as a 1:1 chat. KindDM Kind = "dm" // KindGroup — a public key plus a group ID. Whether the group is an // ordinary group or a broadcast channel is NOT knowable from the // address; only the host visor can say, so a resolver reports the // group kind separately. Calling this KindGroup rather than // KindGroupOrChannel keeps the grammar honest: the address form is // the same for both, and pretending otherwise would invite callers // to trust a distinction the string cannot carry. KindGroup Kind = "group" )