code.oscarkilo.com/okg/chat/chat.go

..
chat.go
chat_test.go
// Package chat is the public HTTP client for OscarKilo's chat
// service. It is used by `okg` and any other tool that talks
// to oscarkilo.com over the network.
//
// The struct here is named HTTPClient (not just Client) so
// applications can wrap it in their own Client abstractions
// without name collision.
package chat

import "time"

import "oscarkilo.com/okg/internal/rest"

// HTTPClient talks to a //chat server over HTTPS. Embeds the
// shared rest helpers; chat-specific methods live below.
type HTTPClient struct {
  *rest.Client
}

func NewHTTPClient(host, apiKey string) *HTTPClient {
  return &HTTPClient{Client: rest.NewClient(host, apiKey)}
}

// Message is a single chat message. No JSON tags — the server
// marshals with default Go field names (PascalCase). FUTURE:
// switch to snake_case once the server adds JSON tags.
type Message struct {
  From      string
  To        string
  Text      string
  CreatedAt time.Time
}

// SendRequest is the body for POST /chat/send.
type SendRequest struct {
  To   string `json:"to"`
  Text string `json:"text"`
}

// Send posts a message to a //chat group. The caller must have
// post rights on chat://<to>#post.
func (c *HTTPClient) Send(req SendRequest) (*Message, error) {
  var msg Message
  if err := c.PostJSON("/chat/send", req, &msg); err != nil {
    return nil, err
  }
  return &msg, nil
}

// SetPermissionsRequest is the body for POST
// /chat/permissions/set. Group is the //who username naming the
// channel; Permission ∈ {read, post, join, pin, ban}; Owner
// and Reader are //who usernames (or "" for "anyone" — only
// honored where the backend allows it).
type SetPermissionsRequest struct {
  Group      string `json:"group"`
  Permission string `json:"permission"`
  Owner      string `json:"owner"`
  Reader     string `json:"reader"`
}

// SetPermissions writes a //chat authz entry on
// chat://<group>#<permission>.
func (c *HTTPClient) SetPermissions(
  req SetPermissionsRequest,
) error {
  return c.PostJSON("/chat/permissions/set", req, nil)
}

// SearchRequest is the body for POST /chat/search.
type SearchRequest struct {
  To string `json:"to,omitempty"`
}

// SearchResponse is the body of POST /chat/search's response.
type SearchResponse struct {
  Messages []*Message `json:"messages"`
}

// Search returns messages matching the filter. The caller must
// have read rights on chat://<To>#read (otherwise the result
// is empty, not an error — per //chat's policy).
func (c *HTTPClient) Search(
  req SearchRequest,
) ([]*Message, error) {
  var res SearchResponse
  if err := c.PostJSON(
    "/chat/search", req, &res); err != nil {
    return nil, err
  }
  return res.Messages, nil
}