urbit

package module
v0.0.0-...-17ee918 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2020 License: MIT Imports: 18 Imported by: 1

README

Urbit HTTP API implementation in Go

PkgGoDev

This module provides functionality to communicate with Urbit ships. See Urbit home page for more details about it.

NOTE: the packages in this module are still in experimental stage, and the API may change as it gets more developed -- the major version is still 0.

Basic usage

Connect with an Urbit ship using

ship, err := urbit.Dial(address, passcode, nil)

Note that the code can be obtained with the command |code in Dojo inside the Urbit environment. The returned value is a Client that can be used to send requests and receive events.

// Send a Poke
ship.Poke("chat-hook", jsonMessage)

// Subscribe to a path inside an app. The ID in result can be used to
// identify events containing updates for this subscription.
result, err := ship.Subscribe("chat-store", "/keys")

// ...

// Consume events.
for ev := range ship.Events() {
	switch (ev.Type) {
	case "diff":
		if (ev.ID == result.ID) {
			// ev.Data contains the data
		}
	}
}

It is important to consume the Events channel, because the Client will not try to buffer individual events, so processing only happens when that channel is consumed. Depending on the program, either a separate goroutine or including the processing the in the program's mainloop will be the typical solutions.

The next step after being able to talk, is to know what to talk. Most apps running inside Urbit are able to talk via JSON. Their own protocols are currently only documented in the source code (see /sur in Urbit). It is also helpful to see how requests are created and responses are parsed in Landscape (Urbit's reference web client).

For Go, these definitions can be mapped into types and serialization helpers, see the chat package for example.

Examples

A good way to learn how to use the module is to look at the commented examples. Run each of them with

go run EXAMPLE.go

By default the examples will try to connect with the default address and passcode used running local development ships ("fake zod"). They can also be specified in the command line

go run EXAMPLE.go --addr ADDRESS --code CODE

each example has a few more options, see them with

go run EXAMPLE.go --help

Documentation

Index

Constants

View Source
const (
	ActionPoke        = "poke"
	ActionSubscribe   = "subscribe"
	ActionUnsubscribe = "unsubscribe"
)
View Source
const (
	// Special Type of Event used by Client to emit information
	// that doesn't come from the ship, e.g. errors Client had
	// processing data.
	ClientError = "go-client-error"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents a connection with an Urbit ship.

func Dial

func Dial(addr, code string, opts *DialOptions) (*Client, error)

Dial connects to an Urbit ship via HTTP address using code to authenticate. Returns a Client that can be used to perform further Requests.

func (*Client) Close

func (c *Client) Close() error

Close the connection with the ship.

func (*Client) Do

func (c *Client) Do(req *Request) Result

Do sends a single request to the ship and returns a result.

func (*Client) DoMany

func (c *Client) DoMany(reqs []*Request) []Result

DoMany combines multiple requests into a single HTTP request and send to the ship. Returns a Result for each request.

func (*Client) Events

func (c *Client) Events() <-chan *Event

Events returns the channel used to obtain events coming from the ship.

The library doesn't buffer individual events coming from the ship, so it is important that the user code consume this channel, to make sure progress is made in all the different requests.

func (*Client) Get

func (c *Client) Get(path, contentType string) ([]byte, error)

Get makes an HTTP GET request to the path inside the ship with a certain Content-Type.

func (*Client) GetJSON

func (c *Client) GetJSON(path string) ([]byte, error)

GetJSON makes an HTTP GET request to the path inside the ship with Content-Type set to "application/json".

func (*Client) Name

func (c *Client) Name() string

Name returns the name of the ship a Client is connected to.

func (*Client) Poke

func (c *Client) Poke(app string, data json.RawMessage) Result

Poke sends a "poke" request to the ship Client is connected to.

func (*Client) PokeShip

func (c *Client) PokeShip(ship, app string, data json.RawMessage) Result

PokeShip sends a "poke" request to a given ship.

func (*Client) Scry

func (c *Client) Scry(app, path string) ([]byte, error)

Scry makes a query to the ship state. Note that not all state "scry-able" via the ship is exported via HTTP.

func (*Client) Subscribe

func (c *Client) Subscribe(app, path string) Result

Subscribe to a given path of an app in the ship Client is connected to. If subscription succeeds, the ship will send (likely multiple) "diff" events containing updates.

func (*Client) SubscribeShip

func (c *Client) SubscribeShip(ship, app, path string) Result

Subscribe to a given path of an app in the given ship. If subscription succeeds, the ship will send (likely multiple) "diff" events containing updates.

func (*Client) Unsubscribe

func (c *Client) Unsubscribe(subscriptionID uint64) Result

Unsubscribe finishes a subscription.

type DialOptions

type DialOptions struct {
	// Trace indicated whether the Client should print to Stderr
	// information about messages sent and received. Used mostly
	// for debugging.
	Trace bool

	// HTTPClient is used to set a custom HTTP client to be used
	// by the Client.
	HTTPClient *http.Client
}

DialOptions include various options

type Event

type Event struct {
	ID   uint64
	Type string `json:"response"`

	Ok  *string
	Err *string

	Data json.RawMessage `json:"json"`
}

Event represents an update sent from the ship to the Client.

type Request

type Request struct {
	Action string `json:"action"`

	// Poke and Subscribe only.
	Ship string `json:"ship,omitempty"`
	App  string `json:"app,omitempty"`

	// Subscribe only.
	Path string `json:"path,omitempty"`

	// Poke only.
	Mark string          `json:"mark,omitempty"`
	Data json.RawMessage `json:"json,omitempty"`

	// Unsubscribe only.
	Subscription uint64 `json:"subscription,omitempty"`
	// contains filtered or unexported fields
}

Request represents a request made from a client to a ship.

It is an "union" of the valid fields for all Action values, so some fields might be ignored, see inline comments below.

type Result

type Result struct {
	// ID assigned to the request. Can be used to find associated
	// events when consuming the Events channel.
	ID uint64

	// Err is not nil if the request resulted in an Error. Note
	// that even if the Request is succesfully sent, it is still
	// possible that Err become non-nil later. See also Wait.
	Err error

	// Requests with a single response will have a channel so can
	// be waited on with the final result. See also Wait.
	Response <-chan error
}

Result is obtained after sending a request.

func (*Result) Wait

func (res *Result) Wait() error

If the Result has an associated channel (e.g. it is a Result of a "poke"), blocks until a response is available. The response will be returned and also stored in Err.

For this method to work, another goroutine must be consuming Events channel.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL