client

package
v0.0.0-...-13e599b Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2022 License: MIT Imports: 10 Imported by: 0

README

Relationer golang client

Use the golang realtioner client to interact programatically with the relationer server. Read messages and preform CRUD opperations.

Getting started

Go get it:

go get github.com/Lambels/relationer

Simple example:

In this example you will create 2 people and link them together mutually.

package main

import (
    "log"
    "context"

    "github.com/Lambels/relationer/client"
)

func main() {
    rClient := client.New(nil) // default client settings.
    
    bgCtx := context.Background()

    // create first person with name: 'Lambels'
    id, err := rClient.AddPerson(bgCtx, "Lambels")
    if err != nil {
        log.Fatal(err)
    }

    // create second person with name: 'Your-Name'
    id2, err := rClient.AddPerson(bgCtx, "Your-Name")
    if err != nil {
        log.Fatal(err)
    }

    // link them together (both ways, ie: mutual friendship)
    if err := rClient.AddFriendship(bgCtx, id1, id2); err != nil {
        log.Fatal(err)
    }
    if err := rClient.AddFriendship(bgCtx, id2, id1); err != nil {
        log.Fatal(err)
    }
}

Client Settings:

When initiating a client you can pass a configuration struct to the initializator to customize the behaviour of the client.

The client configuration can be split into 2 parts: client.ClientConfig and client.ConsumerConfig, the client.ClientConfig, configures the behaviour of REST methods such as client.Get* or client.Add* while client.ConsumerConfig configures the behaviour of client.Start* methods.

ClientConfig:
// to use the default value for the client cofig pass nil.
client.New(&client.ClientConfig{
    URL: "http://localhost:3000", // default value - http://localhost:8080
    Client: &http.Client{Timeout: 5 * time.Second}, // default value - http.DefaultClient
    ConsumerConfig: nil, // use default consumer config
})
ConsumerConfig:

When in reconnecting state a separate ticking go routine starts which sleeps in intervals of Pulse checks the health of the consumer, if the connection is closed it will attempt a redial or close the consumer if the redial fails. Set a non 0 value for Pulse to indicate a reconnecting state.

// to use the default value for the consumer config pass nil to ConsumerConfig.
client.New(&client.ClientConfig{
    URL: "http://localhost:3000", // default value - http://localhost:8080
    Client: &http.Client{Timeout: 5 * time.Second}, // default value - http.DefaultClient
    ConsumerConfig: &client.ConsumerConfig{
        URL: "amqp://guest:guest@localhost:8080" // default value - amqp://guest:guest@localhost:5672
        BindingKeys: []string{"person.created", "person.deleted"} // default value - "#" (all messages)
        Pulse: 5 * time.Second, // default value - 0
    },
})

More Examples

Client Listening:

package main

import (
	"context"
	"log"

	"github.com/Lambels/relationer/client"
)

func main() {
	c := client.New(nil)
    
    // close will make sure that it will tear any connections and close any consumers left behind.
	defer c.Close()
    
    // start a new detached listener.
	recv, err := c.StartListenDetached(context.Background())
	if err != nil {
		log.Fatal(err)
	}
    
    // loop over messages.
	go func() { 
        log.Println("Started listening...")
		for msg := range recv1 {
			log.Printf("[%v]: %v\n", msg.Type, msg.Data)
		}
	}()
    
    log.Println("Ctrl-C to stop listening.")
	select {}
}

Client listening (attached):

package main

import (
	"context"
	"log"
	"time"

	"github.com/Lambels/relationer/client"
)

func logMessages(recv <-chan *client.Message) {
    go func() {
        log.Println("Started listening...")
		for msg := range recv1 {
			log.Printf("[%v]: %v\n", msg.Type, msg.Data)
		}
    }()
}

func main() {
	c := client.New(nil)
    
    // close will make sure that it will tear any connections and close any consumers left behind.
	defer c.Close()
    
    ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
    defer cancel()

    // start a new detached listener with a timeout context.
	recv, err := c.StartListenDetached(ctx)
	if err != nil {
		log.Fatal(err)
	}
    logMessages(recv)
    
    for i := 0; i < 4; i++ {    
        // start a new reciever without creating a new connection to the rabbitmq server.
        // the true parameter will attach the reciever strictly to the last connection added
        // and skip the load balancing algorithm.
        recv, err := c.StartListenAttached(context.Background(), true)
	    if err != nil {
		    log.Fatal(err)
	    }
        logMessages(recv)
    }
        
    // the resulting connections to the rabbitmq server will be one. (detached listener)
    log.Println("Ctrl-C to stop listening.")
	select {}
}

Documentation

Index

Constants

View Source
const (
	DefaultTimeout = time.Second * 5
	DefaultURL     = "http://localhost:8080"
)
View Source
const DefaultBrokerURL = "amqp://guest:guest@localhost:5672"

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client is the interface between the user and the relationer server.

func New

func New(conf *ClientConfig) *Client

New creates a new relationer client with the provided config.

To use the default config run

client.New(nil)

func (*Client) AddFriendship

func (c *Client) AddFriendship(ctx context.Context, p1, p2 int64) error

AddFriendship creates a new friendship (one-way) between p1 and p2.

func (*Client) AddPerson

func (c *Client) AddPerson(ctx context.Context, name string) (int64, error)

AddPerson adds person with name: name and returns the id if successful.

func (*Client) Close

func (c *Client) Close() error

Close tears any possible amqp connections and consumers taking with it all the registered channels (recievers).

func (*Client) GetAll

func (c *Client) GetAll(ctx context.Context) ([]internal.Friendship, error)

GetAll returns the graph of the current state.

func (*Client) GetDepth

func (c *Client) GetDepth(ctx context.Context, id1, id2 int64) (int, error)

GetDepth gets the depth between two nodes (including the endpoint nodes).

func (*Client) GetFriendship

func (c *Client) GetFriendship(ctx context.Context, id int64) (internal.Friendship, error)

GetFriendship gets the friendships (relationships) the person with id: id has.

func (*Client) GetPerson

func (c *Client) GetPerson(ctx context.Context, id int64) (*internal.Person, error)

GetPerson fetches the person with id: id.

func (*Client) RemovePerson

func (c *Client) RemovePerson(ctx context.Context, id int64) error

RemovePerson removes person with id: id.

func (*Client) StartListenAttached

func (c *Client) StartListenAttached(ctx context.Context, last bool) (<-chan *Message, error)

StartListenAttached will attach to an existing connection if possible, only scenario where it will create a new connection is when the connection pool is empty.

Canceling the context will end up in one of these cases:

1) When a new connection is created by StartListenAttached cancelling the context passed to the function call will destroy the connection only when there are no more recievers attached to it.

2) When the reciever is attached to an existing connection cancelling the context will just remove the reciever without killing the connection, the only way that connection can be killed is if the root reciever (reciever created with StartListenDetached) is killed or an error happens in the connection.

Grouping - group multiple recievers to one root reciever (controlled):

call (*Client).StartListenDetached(ctx) followed by synchronised (*Client).StartListenAttached(ctx, true) , these followed calls will skip the round-robin like load balancer algorithm and attach all the recievers to the last consumer (created by (*Client).StartListenDetached(ctx)) giving you grouped consumer.

Attention: A recv attached to a connection can be closed at any time! You can bundle up recievers with syncronised calls to the client making one root reciever and many dependant recievers.

func (*Client) StartListenDetached

func (c *Client) StartListenDetached(ctx context.Context) (<-chan *Message, error)

StartListenDetached will start a separate connection to the message-broker (rabbitmq) and subscribe the recieving channel to it.

canceling the context provided to this function call will destroy the whole rabbitmq connection taking away with it the initial subscribed channel and any other attached channels with

StartListenAttached()

this way of listening to the messages is recommanded as separate connections for each recieving channel will make recievers more safe and independant.

type ClientConfig

type ClientConfig struct {
	// The relationer server URL - default: http://localhost:8080
	URL string
	// The http client used by the REST client - defualt: http client with 5 second timeout
	Client *http.Client

	// The consumer factory configuration used by the client to generate all consumers.
	ConsumerConfig *ConsumerConfig
}

ClientConfig represents the configurable fields.

type ConsumerConfig

type ConsumerConfig struct {
	// The URL of the broker (rabbitmq) - default: amqp://guest:guest@localhost:5672
	URL string
	// Binding keys to the exchange - defualt: # (all)
	BindingKeys []string

	// Used as timeout to check the health of current connection. (reconnect if needed or close conn)
	Pulse time.Duration
}

ConsumerConfig is used for the creation of consumers, each client has one consumer config which is used to create all consumers via the: StartListenDetached and StartListenAttached methods.

type Message

type Message struct {
	// The type of the message: person.created , person.deleted , friendship.created
	Type string
	// The raw data of the message, encoded to json.
	Data []byte
}

Message represents a message from the message-broker.

Jump to

Keyboard shortcuts

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