Add doc strings for all the thigns
This commit is contained in:
parent
ae2199bff4
commit
2e3907a3b3
38
client.go
38
client.go
|
@ -25,19 +25,27 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// DefaultEnvPath is the default PATH for pre and post hooks that are shelled out to
|
||||
DefaultEnvPath = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
ServiceUser = "salty"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoMessages = errors.New("error: no messages found")
|
||||
ErrNoSender = errors.New("error: no sender configured")
|
||||
ErrNotConnected = errors.New("error: client not connected")
|
||||
// ErrNoMessages is an error returned when there are no further messages found for an inbox from the broker
|
||||
ErrNoMessages = errors.New("error: no messages found")
|
||||
|
||||
// ErrNoSender is an error returned when the client is not properly configured with a valid sender
|
||||
ErrNoSender = errors.New("error: no sender configured")
|
||||
|
||||
// ErrNotConnected is an error returned when the client is not properly configured or connected to a broker
|
||||
ErrNotConnected = errors.New("error: client not connected")
|
||||
|
||||
// ErrMissingIdentity is an error returned when the client is not properly configured with a valid identity
|
||||
ErrMissingIdentity = errors.New("error: missing identity")
|
||||
)
|
||||
|
||||
type addrCache map[string]*Addr
|
||||
|
||||
// Message contains the plaintext (decrypted) message and the sender's public key
|
||||
type Message struct {
|
||||
Text string
|
||||
Key *keys.EdX25519PublicKey
|
||||
|
@ -205,10 +213,19 @@ func (cli *Client) messageHandler(extraenvs, prehook, posthook string, msgs chan
|
|||
}
|
||||
}
|
||||
|
||||
func (cli *Client) Me() *Addr { return cli.me }
|
||||
func (cli *Client) Key() *keys.EdX25519PublicKey { return cli.key.PublicKey() }
|
||||
func (cli *Client) State() *State { return cli.state }
|
||||
// Me returns our (self) address
|
||||
func (cli *Client) Me() *Addr { return cli.me }
|
||||
|
||||
// Key returns out (self) public key
|
||||
func (cli *Client) Key() *keys.EdX25519PublicKey { return cli.key.PublicKey() }
|
||||
|
||||
// State returns the current state of the client
|
||||
func (cli *Client) State() *State { return cli.state }
|
||||
|
||||
// Env sets up a sensible (and hopefully secure) environment for running pre and post hooks
|
||||
// Extra environment variables are parsed from extraenvs and some default variables injected
|
||||
// into the new environment such as PATH, PWD and HOME as well as the current user's Salty address
|
||||
// (SALTY_USER) and their public key (SALTY_IDENTITY).
|
||||
func (cli *Client) Env(extraenvs string) []string {
|
||||
Path := DefaultEnvPath
|
||||
GoPath := os.Getenv("GOPATH")
|
||||
|
@ -242,6 +259,8 @@ func (cli *Client) Env(extraenvs string) []string {
|
|||
return env
|
||||
}
|
||||
|
||||
// Outbox returns the URL of our (self) outbox for sending copies of our outgoing messages to
|
||||
// which is later used by the client as a way to track messages sent.
|
||||
func (cli *Client) Outbox() *url.URL {
|
||||
// use url struct copy to avoid modifying cli.me.Endpoint().Path
|
||||
// https://github.com/golang/go/issues/38351
|
||||
|
@ -253,6 +272,7 @@ func (cli *Client) Outbox() *url.URL {
|
|||
return &ep
|
||||
}
|
||||
|
||||
// OutboxAddr returns the address of our (self) outbox
|
||||
func (cli *Client) OutboxAddr(to *Addr) *Addr {
|
||||
return &Addr{
|
||||
User: to.User,
|
||||
|
@ -264,6 +284,7 @@ func (cli *Client) OutboxAddr(to *Addr) *Addr {
|
|||
}
|
||||
}
|
||||
|
||||
// OutboxClient returns a modified client for our (self) outbox
|
||||
func (cli *Client) OutboxClient(to *Addr) *Client {
|
||||
if to == nil {
|
||||
to = cli.me
|
||||
|
@ -301,6 +322,8 @@ func (cli *Client) OutboxClient(to *Addr) *Client {
|
|||
}
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface and outputs who we (self) are,
|
||||
// what our endpoint is we're connected to (broker), our outbox and our public key.
|
||||
func (cli *Client) String() string {
|
||||
b := &bytes.Buffer{}
|
||||
fmt.Fprintln(b, "Me: ", cli.me)
|
||||
|
@ -393,6 +416,7 @@ func (cli *Client) Send(user, msg string) error {
|
|||
return cli.OutboxClient(addr).SendToAddr(cli.OutboxAddr(addr), msg)
|
||||
}
|
||||
|
||||
// SendToAddr encrypts and sends the message to a specified address
|
||||
func (cli *Client) SendToAddr(addr *Addr, msg string) error {
|
||||
if cli.me == nil || cli.me.IsZero() {
|
||||
return ErrNoSender
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// DateTimeFormat is the default date and time format used for displaying messages
|
||||
DateTimeFormat = "2006-01-02 15:04:05"
|
||||
)
|
||||
|
||||
|
@ -21,6 +22,7 @@ func boundedInt(value, low, high uint8) uint8 {
|
|||
return (((value - low) % diff) + low)
|
||||
}
|
||||
|
||||
// GetUserColor is used by the TUI (terminal ui) client to compute an appropriate ANSI color for a given user
|
||||
func GetUserColor(user string, lower, upper uint8) uint8 {
|
||||
h := fnv.New32()
|
||||
h.Sum([]byte(user))
|
||||
|
|
|
@ -144,6 +144,7 @@ type Identity struct {
|
|||
addr *Addr
|
||||
}
|
||||
|
||||
// Source returns the path of an identity or []byte it if was loaded from a byte string
|
||||
func (i *Identity) Source() string {
|
||||
if i != nil && i.path != "" {
|
||||
return i.path
|
||||
|
@ -151,14 +152,17 @@ func (i *Identity) Source() string {
|
|||
return "[]byte"
|
||||
}
|
||||
|
||||
// Contents returns the contents of the identity as a byte slice
|
||||
func (i *Identity) Contents() []byte {
|
||||
return i.contents
|
||||
}
|
||||
|
||||
// Key returns the full private and public Ed25519 key object for this identity
|
||||
func (i *Identity) Key() *keys.EdX25519Key {
|
||||
return i.key
|
||||
}
|
||||
|
||||
// Addr returns the Salty Address for this identity
|
||||
func (i *Identity) Addr() *Addr {
|
||||
return i.addr
|
||||
}
|
||||
|
@ -189,7 +193,7 @@ func WithIdentityBytes(contents []byte) IdentityOption {
|
|||
return func(i *Identity) { i.contents = contents }
|
||||
}
|
||||
|
||||
// Handle unix home with `~`
|
||||
// FixUnixHome handles paths with a UNIX Home (i.e: ~)
|
||||
func FixUnixHome(p string) string {
|
||||
// Handle unix home with `~`
|
||||
if strings.HasPrefix(p, "~/") {
|
||||
|
|
11
lookup.go
11
lookup.go
|
@ -20,6 +20,9 @@ var (
|
|||
_ Lookuper = (*ProxyLookup)(nil)
|
||||
)
|
||||
|
||||
// Lookuper defines an interface for looking up Salty Addresses, primarily used by the PWA
|
||||
// and possibly other clients, as a way to either perform direct lookups or to have lookups
|
||||
// proxied through a broker.
|
||||
type Lookuper interface {
|
||||
LookupAddr(user string) (*Addr, error)
|
||||
}
|
||||
|
@ -50,10 +53,12 @@ type Config struct {
|
|||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// Capabilities defines optional capabilities of a client
|
||||
type Capabilities struct {
|
||||
AcceptEncoding string
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface and formats capabilities as HTTP headers
|
||||
func (c Capabilities) String() string {
|
||||
return fmt.Sprint("accept-encoding: ", c.AcceptEncoding)
|
||||
}
|
||||
|
@ -76,6 +81,7 @@ func (a *Addr) IsZero() bool {
|
|||
return a.User == "" && a.Domain == ""
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface
|
||||
func (a *Addr) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
Addr string
|
||||
|
@ -94,6 +100,7 @@ func (a *Addr) MarshalJSON() ([]byte, error) {
|
|||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarsaller interface
|
||||
func (a *Addr) UnmarshalJSON(data []byte) error {
|
||||
res := struct {
|
||||
Addr string
|
||||
|
@ -175,6 +182,7 @@ func (a *Addr) HashURI() string {
|
|||
return fmt.Sprintf("https://%s/.well-known/salty/%s.json", a.DiscoveredDomain(), a.Hash())
|
||||
}
|
||||
|
||||
// Refresh forces a lookup and configuration fetch for a Salty Address
|
||||
func (a *Addr) Refresh() error {
|
||||
log.Debugf("Looking up SRV record for _salty._tcp.%s", a.Domain)
|
||||
if target, err := resolver.LookupSRV("salty", "tcp", a.Domain); err == nil {
|
||||
|
@ -211,6 +219,9 @@ func (a *Addr) Refresh() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Avatar returns the cached avatar service for a Salty Address or performs a DNS lookup
|
||||
// for the avatar service to use and cached it (if found) and returns that. If there is no
|
||||
// avatar service found, then a default avatar is used for peers.
|
||||
func (a *Addr) Avatar() string {
|
||||
if a.checkedAvatar {
|
||||
return a.avatar
|
||||
|
|
11
resolv.go
11
resolv.go
|
@ -13,6 +13,9 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Resolver is an interface for performing DNS lookups and is primarily used by the PWA
|
||||
// and possibly other clients where direct DNS queries are not always possible and
|
||||
// instead uses DNS over HTTP to eprform the same functionality.
|
||||
type Resolver interface {
|
||||
LookupSRV(service, proto, domain string) (string, error)
|
||||
}
|
||||
|
@ -20,6 +23,7 @@ type Resolver interface {
|
|||
var (
|
||||
_ Resolver = (*StandardResolver)(nil)
|
||||
|
||||
// ErrSRVRecordNotFound is an error returned by a resolver when there is no SRV record found for the domain of a Salty Address
|
||||
ErrSRVRecordNotFound = errors.New("error: No SRV records found")
|
||||
|
||||
resolver Resolver
|
||||
|
@ -29,12 +33,16 @@ func init() {
|
|||
SetResolver(&StandardResolver{})
|
||||
}
|
||||
|
||||
// SetResolver sets the default resolver used by this package
|
||||
func SetResolver(r Resolver) {
|
||||
resolver = r
|
||||
}
|
||||
|
||||
// StandardResolver is a standard resolver that performs direct DNS queries over
|
||||
// the standard networking protocol using port tcp/53 or udp/53
|
||||
type StandardResolver struct{}
|
||||
|
||||
// LookupSRV implements the Resolver interface
|
||||
func (r *StandardResolver) LookupSRV(service, proto, domain string) (string, error) {
|
||||
log.Debugf("Using StandardResolver, looking up SRV _%s._%s.%s", service, proto, domain)
|
||||
_, records, err := net.LookupSRV(service, proto, domain)
|
||||
|
@ -47,8 +55,11 @@ func (r *StandardResolver) LookupSRV(service, proto, domain string) (string, err
|
|||
return strings.TrimSuffix(records[0].Target, "."), nil
|
||||
}
|
||||
|
||||
// DNSOverHTTPResolver is a resolver that performs DNS queries using a DNS Over HTTP
|
||||
// service where direct DNS queries are not possible (standard resolver).
|
||||
type DNSOverHTTPResolver struct{}
|
||||
|
||||
// LookupSRV implements the Resolver interface
|
||||
func (r *DNSOverHTTPResolver) LookupSRV(service, proto, domain string) (string, error) {
|
||||
name := fmt.Sprintf("_%s._%s.%s", service, proto, domain)
|
||||
|
||||
|
|
7
send.go
7
send.go
|
@ -18,6 +18,13 @@ var (
|
|||
acceptEncodings = []string{"br", "gzip", ""}
|
||||
)
|
||||
|
||||
// Sender defines an interface for sending messages to another Salty Address (user)
|
||||
// and is primarily used by the PWA and possibly other clients to send outbound
|
||||
// messages where it may not always be possible to send the message directly and
|
||||
// instead proxy the message thorugh a broker. Note that even if proxying through
|
||||
// a broker, the message is already encrypted at the point of proxying, so there
|
||||
// needs not be any trust between the client and broker as the broker is treated
|
||||
// as a "dumb" relay.
|
||||
type Sender interface {
|
||||
Send(key *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error
|
||||
}
|
||||
|
|
13
service.go
13
service.go
|
@ -14,6 +14,9 @@ import (
|
|||
"go.yarn.social/lextwt"
|
||||
)
|
||||
|
||||
// Service is an object that implements an async responder (bot) that responds to
|
||||
// textual callbacks (commands) or events. This can be used to implement automated
|
||||
// users, bots or services.
|
||||
type Service struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
|
@ -26,9 +29,13 @@ type Service struct {
|
|||
eventFns map[string]MessageEventHandlerFunc
|
||||
}
|
||||
|
||||
// MessageTextHandlerFunc defines a function type to handle an inbound message to a service
|
||||
type MessageTextHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyText) error
|
||||
|
||||
// MessageEventHandlerFunc defines a function type to handle an inbound event to a service
|
||||
type MessageEventHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyEvent) error
|
||||
|
||||
// NewService constructs a new service with the provided address, identity and state
|
||||
func NewService(me *Addr, id *Identity, state string) (*Service, error) {
|
||||
svc := &Service{
|
||||
me: me,
|
||||
|
@ -44,6 +51,7 @@ func NewService(me *Addr, id *Identity, state string) (*Service, error) {
|
|||
return svc, nil
|
||||
}
|
||||
|
||||
// SetClient sets the client instance to used for this service
|
||||
func (svc *Service) SetClient(cli *Client) {
|
||||
svc.mu.Lock()
|
||||
defer svc.mu.Unlock()
|
||||
|
@ -66,6 +74,7 @@ func (svc *Service) String() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// Respond is a convenitne method to respond to a user with the provided message
|
||||
func (svc *Service) Respond(user, msg string) error {
|
||||
if svc.cli == nil {
|
||||
return fmt.Errorf("service not connected")
|
||||
|
@ -73,6 +82,8 @@ func (svc *Service) Respond(user, msg string) error {
|
|||
return svc.cli.Send(user, msg)
|
||||
}
|
||||
|
||||
// Run runs the service tunil the context is done, if an error occurred at any point
|
||||
// an error is returned.
|
||||
func (svc *Service) Run(ctx context.Context) error {
|
||||
// create the service user's client in a loop until successful
|
||||
// TODO: Should this timeout? Use a context?
|
||||
|
@ -147,6 +158,7 @@ func (svc *Service) handle(ctx context.Context, msg Message) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// TextFunc registers a handler for processing textual callbacks (commands)
|
||||
func (svc *Service) TextFunc(name string, fn MessageTextHandlerFunc) {
|
||||
svc.mu.Lock()
|
||||
defer svc.mu.Unlock()
|
||||
|
@ -154,6 +166,7 @@ func (svc *Service) TextFunc(name string, fn MessageTextHandlerFunc) {
|
|||
svc.textFns[strings.ToUpper(name)] = fn
|
||||
}
|
||||
|
||||
// EventFunc registers a handler for processing event callbacks (events)
|
||||
func (svc *Service) EventFunc(name string, fn MessageEventHandlerFunc) {
|
||||
svc.mu.Lock()
|
||||
defer svc.mu.Unlock()
|
||||
|
|
7
state.go
7
state.go
|
@ -14,18 +14,21 @@ func DefaultState() string {
|
|||
return os.ExpandEnv("$HOME/.config/salty/state.json")
|
||||
}
|
||||
|
||||
// State represents the state of a client and the indices of its inbox(es)
|
||||
type State struct {
|
||||
sync.RWMutex
|
||||
|
||||
Indicies map[string]int64
|
||||
}
|
||||
|
||||
// NewState returns a new empty state
|
||||
func NewState() *State {
|
||||
return &State{
|
||||
Indicies: make(map[string]int64),
|
||||
}
|
||||
}
|
||||
|
||||
// GetIndex returns the current index for the name inbox
|
||||
func (s *State) GetIndex(name string) int64 {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
@ -33,6 +36,7 @@ func (s *State) GetIndex(name string) int64 {
|
|||
return s.Indicies[name]
|
||||
}
|
||||
|
||||
// SetIndex sets the index for the named inbox
|
||||
func (s *State) SetIndex(name string, index int64) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
@ -40,6 +44,7 @@ func (s *State) SetIndex(name string, index int64) {
|
|||
s.Indicies[name] = index
|
||||
}
|
||||
|
||||
// Bytes serialises the state into a byte slice
|
||||
func (s *State) Bytes() ([]byte, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
@ -52,6 +57,7 @@ func (s *State) Bytes() ([]byte, error) {
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// Save persists the state to a file on disk
|
||||
func (s *State) Save(fn string) error {
|
||||
data, err := s.Bytes()
|
||||
if err != nil {
|
||||
|
@ -65,6 +71,7 @@ func (s *State) Save(fn string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// LoadState loads a state from a file on disk
|
||||
func LoadState(r io.Reader) (*State, error) {
|
||||
var state *State
|
||||
|
||||
|
|
Loading…
Reference in New Issue