kite

package module
v0.0.0-...-52e8796 Latest Latest
Warning

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

Go to latest
Published: Jan 7, 2016 License: MIT Imports: 39 Imported by: 0

README

Kite Micro-Service Framework

Kite is a framework for developing micro-services in Go.

GoDoc Build Status

Kite

Kite is both the name of the framework and the micro-service that is written by using this framework. Basically, Kite is a RPC server as well as a client. It connects to other kites and peers to communicate with each other. They can discover other kites using a service called Kontrol, and communicate with them bidirectionaly. The communication protocol uses a WebSocket (or XHR) as transport in order to allow web applications to connect directly to kites.

Kites can talk with each other by sending dnode messages over a socket session. If the client knows the URL of the server kite it can connect to it directly. If the URL is not known, client can ask for it from Kontrol (Service Discovery).

For more info checkout the blog post at GopherAcademy which explains Kite in more detail: http://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/

Install and Usage

Install the package with:

go get github.com/koding/kite

Import it with:

import "github.com/koding/kite"

and use kite as the package name inside the code.

What is Kontrol?

Kontrol is the service registry and authentication service used by Kites. It is itself a kite too.

When a kite starts to run, it can registers itself to Kontrol with the Register() method if wished. That enables others to find it by querying Kontrol. There is also a Proxy Kite for giving public URLs to registered kites.

Query has 7 fields:

/<username>/<environment>/<name>/<version>/<region>/<hostname>/<id>
  • You must at least give the username.
  • The order of the fields is from general to specific.
  • Query cannot contains empty parts between fields.

Installing Kontrol

Install Kontrol:

go get github.com/koding/kite/kontrol/kontrol

Generate keys for the Kite key:

openssl genrsa -out key.pem 2048
openssl rsa -in key.pem -pubout > key_pub.pem

Set environment variables:

KONTROL_PORT=6000
KONTROL_USERNAME="kontrol"
KONTROL_STORAGE="etcd"
KONTROL_KONTROLURL="http://127.0.0.1:6000/kite"
KONTROL_PUBLICKEYFILE="certs/key_pub.pem"
KONTROL_PRIVATEKEYFILE="certs/key.pem"

Generate initial Kite key:

./bin/kontrol -initial

How can I use kites from a browser?

A browser can also be a Kite. It has it's own methods ("log" for logging a message to the console, "alert" for displaying alert to the user, etc.). A connected kite can call methods defined on the webpage.

See kite.js library for more information.

How can I write a new kite?

  • Import kite package.
  • Create a new instance with kite.New().
  • Add your method handlers with k.HandleFunc() or k.Handle().
  • Call k.Run()

Below you can find an example, a math kite which calculates the square of a received number:

package main

import "github.com/koding/kite"

func main() {
	// Create a kite
	k := kite.New("math", "1.0.0")

	// Add our handler method with the name "square"
	k.HandleFunc("square", func(r *kite.Request) (interface{}, error) {
		a := r.Args.One().MustFloat64()
		result := a * a    // calculate the square
		return result, nil // send back the result
	}).DisableAuthentication()

	// Attach to a server with port 3636 and run it
	k.Config.Port = 3636
	k.Run()
}

Now let's connect to it and send a 4 as an argument.

package main

import (
	"fmt"

	"github.com/koding/kite"
)

func main() {
	k := kite.New("exp2", "1.0.0")

	// Connect to our math kite
	mathWorker := k.NewClient("http://localhost:3636/kite")
	mathWorker.Dial()

	response, _ := mathWorker.Tell("square", 4) // call "square" method with argument 4
	fmt.Println("result:", response.MustFloat64())
}

Check out the examples folder for more examples.

Documentation

Overview

Package kite is a library for creating micro-services. Two main types implemented by this package are Kite for creating a micro-service server called "Kite" and Client for communicating with another kites.

kontrolclient implements a kite.Client for interacting with Kontrol kite.

Package server implements a HTTP(S) server for kites.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoKitesAvailable = errors.New("no kites availabile")

Returned from GetKites when query matches no kites.

Functions

This section is empty.

Types

type Auth

type Auth struct {
	// Type can be "kiteKey", "token" or "sessionID" for now.
	Type string `json:"type"`
	Key  string `json:"key"`
}

Authentication is used when connecting a Client.

type Client

type Client struct {
	// The information about the kite that we are connecting to.
	protocol.Kite

	// A reference to the current Kite running.
	LocalKite *Kite

	// Credentials that we sent in each request.
	Auth *Auth

	// Should we reconnect if disconnected?
	Reconnect bool

	// SockJS base URL
	URL string

	// Should we process incoming messages concurrently or not? Default: true
	Concurrent bool

	// ReadBufferSize is the input buffer size. By default it's 4096.
	ReadBufferSize int

	// WriteBufferSize is the output buffer size. By default it's 4096.
	WriteBufferSize int
	// contains filtered or unexported fields
}

Client is the client for communicating with another Kite. It has Tell() and Go() methods for calling methods sync/async way.

func (*Client) Close

func (c *Client) Close()

func (*Client) Dial

func (c *Client) Dial() (err error)

Dial connects to the remote Kite. Returns error if it can't.

func (*Client) DialForever

func (c *Client) DialForever() (connected chan bool, err error)

Dial connects to the remote Kite. If it can't connect, it retries indefinitely. It returns a channel to check if it's connected or not.

func (*Client) DialTimeout

func (c *Client) DialTimeout(timeout time.Duration) (err error)

DialTimeout acts like Dial but takes a timeout.

func (*Client) Go

func (c *Client) Go(method string, args ...interface{}) chan *response

Go makes an unblocking method call to the server. It returns a channel that the caller can wait on it to get the response.

func (*Client) GoWithTimeout

func (c *Client) GoWithTimeout(method string, timeout time.Duration, args ...interface{}) chan *response

GoWithTimeout does the same thing with Go() method except it takes an extra argument that is the timeout for waiting reply from the remote Kite. If timeout is given 0, the behavior is same as Go().

func (*Client) OnConnect

func (c *Client) OnConnect(handler func())

OnConnect registers a function to run on connect.

func (*Client) OnDisconnect

func (c *Client) OnDisconnect(handler func())

OnDisconnect registers a function to run on disconnect.

func (*Client) RemoteAddr

func (c *Client) RemoteAddr() string

func (*Client) SetUsername

func (c *Client) SetUsername(username string)

func (*Client) Tell

func (c *Client) Tell(method string, args ...interface{}) (result *dnode.Partial, err error)

Tell makes a blocking method call to the server. Waits until the callback function is called by the other side and returns the result and the error.

func (*Client) TellWithTimeout

func (c *Client) TellWithTimeout(method string, timeout time.Duration, args ...interface{}) (result *dnode.Partial, err error)

TellWithTimeout does the same thing with Tell() method except it takes an extra argument that is the timeout for waiting reply from the remote Kite. If timeout is given 0, the behavior is same as Tell().

type Error

type Error struct {
	Type    string `json:"type"`
	Message string `json:"message"`
	CodeVal string `json:"code"`
}

Error is the type of the kite related errors returned from kite package.

func (Error) Code

func (e Error) Code() string

func (Error) Error

func (e Error) Error() string

type Handler

type Handler interface {
	ServeKite(*Request) (result interface{}, err error)
}

Objects implementing the Handler interface can be registered to a method. The returned result must be marshalable with json package.

type HandlerFunc

type HandlerFunc func(*Request) (result interface{}, err error)

HandlerFunc is a type adapter to allow the use of ordinary functions as Kite handlers. If h is a function with the appropriate signature, HandlerFunc(h) is a Handler object that calls h.

func (HandlerFunc) ServeKite

func (h HandlerFunc) ServeKite(r *Request) (interface{}, error)

ServeKite calls h(r)

type Kite

type Kite struct {
	Config *config.Config

	// Log logs with the given Logger interface
	Log Logger

	// SetLogLevel changes the level of the logger. Default is INFO.
	SetLogLevel func(Level)

	// Contains different functions for authenticating user from request.
	// Keys are the authentication types (options.auth.type).
	Authenticators map[string]func(*Request) error

	// MethodHandling defines how the kite is returning the response for
	// multiple handlers
	MethodHandling MethodHandling

	TLSConfig *tls.Config

	Id string // Unique kite instance id
	// contains filtered or unexported fields
}

Kite defines a single process that enables distributed service messaging amongst the peers it is connected. A Kite process acts as a Client and as a Server. That means it can receive request, process them, but it also can make request to other kites.

Do not use this struct directly. Use kite.New function, add your handlers with HandleFunc mehtod, then call Run method to start the inbuilt server (or pass it to any http.Handler compatible server)

func New

func New(name, version string) *Kite

New creates, initialize and then returns a new Kite instance. Version must be in 3-digit semantic form. Name is important that it's also used to be searched by others.

func (*Kite) Addr

func (k *Kite) Addr() string

func (*Kite) AuthenticateFromKiteKey

func (k *Kite) AuthenticateFromKiteKey(r *Request) error

AuthenticateFromKiteKey authenticates user from kite key.

func (*Kite) AuthenticateFromToken

func (k *Kite) AuthenticateFromToken(r *Request) error

AuthenticateFromToken is the default Authenticator for Kite.

func (*Kite) AuthenticateSimpleKiteKey

func (k *Kite) AuthenticateSimpleKiteKey(key string) (string, error)

AuthenticateSimpleKiteKey authenticates user from the given kite key and returns the authenticated username. It's the same as AuthenticateFromKiteKey but can be used without the need for a *kite.Request.

func (*Kite) Close

func (k *Kite) Close()

Close stops the server and the kontrol client instance.

func (*Kite) GetKey

func (k *Kite) GetKey() (string, error)

GetKey is used to get a new public key from kontrol if the current one is invalidated. The key is also replaced in memory and every request is going to use it. This means even if kite.key contains the old key, the kite itself uses the new one.

func (*Kite) GetKites

func (k *Kite) GetKites(query *protocol.KontrolQuery) ([]*Client, error)

GetKites returns the list of Kites matching the query. The returned list contains Ready to connect Client instances. The caller must connect with Client.Dial() before using each Kite. An error is returned when no kites are available.

func (*Kite) GetToken

func (k *Kite) GetToken(kite *protocol.Kite) (string, error)

GetToken is used to get a new token for a single Kite.

func (*Kite) Handle

func (k *Kite) Handle(method string, handler Handler) *Method

Handle registers the handler for the given method. The handler is called when a method call is received from a Kite.

func (*Kite) HandleFunc

func (k *Kite) HandleFunc(method string, handler HandlerFunc) *Method

HandleFunc registers a handler to run when a method call is received from a Kite. It returns a *Method option to further modify certain options on a method call

func (*Kite) HandleHTTP

func (k *Kite) HandleHTTP(pattern string, handler http.Handler)

HandleHTTP registers the HTTP handler for the given pattern into the underlying HTTP muxer.

func (*Kite) HandleHTTPFunc

func (k *Kite) HandleHTTPFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

HandleHTTPFunc registers the HTTP handler for the given pattern into the underlying HTTP muxer.

func (*Kite) Kite

func (k *Kite) Kite() *protocol.Kite

Kite returns the definition of the kite.

func (*Kite) KontrolReadyNotify

func (k *Kite) KontrolReadyNotify() chan struct{}

KontrolReadyNotify returns a channel that is closed when a successful registiration to kontrol is done.

func (*Kite) NewClient

func (k *Kite) NewClient(remoteURL string) *Client

NewClient returns a pointer to a new Client. The returned instance is not connected. You have to call Dial() or DialForever() before calling Tell() and Go() methods.

func (*Kite) NewKeyRenewer

func (k *Kite) NewKeyRenewer(interval time.Duration)

NewKeyRenewer renews the internal key every given interval

func (*Kite) OnConnect

func (k *Kite) OnConnect(handler func(*Client))

func (*Kite) OnDisconnect

func (k *Kite) OnDisconnect(handler func(*Client))

OnDisconnect registers a function to run when a connected Kite is disconnected.

func (*Kite) OnFirstRequest

func (k *Kite) OnFirstRequest(handler func(*Client))

OnFirstRequest registers a function to run when a Kite connects to this Kite.

func (*Kite) Port

func (k *Kite) Port() int

Port returns the TCP port number that the kite listens. Port must be called after the listener is initialized. You can use ServerReadyNotify function to get notified when listener is ready.

Kite starts to listen the port when Run() is called. Since Run() is blocking you need to run it as a goroutine the call this function when listener is ready.

Example:

k := kite.New("x", "1.0.0")
go k.Run()
<-k.ServerReadyNotify()
port := k.Port()

func (*Kite) PostHandle

func (k *Kite) PostHandle(handler Handler)

PostHandle registers an handler which is executed after a kite.Handler method is executed. Calling PostHandler multiple times registers multiple handlers. A non-error return triggers the execution of the next handler. The execution order is FIFO.

func (*Kite) PostHandleFunc

func (k *Kite) PostHandleFunc(handler HandlerFunc)

PostHandleFunc is the same as PostHandle. It accepts a HandlerFunc.

func (*Kite) PreHandle

func (k *Kite) PreHandle(handler Handler)

PreHandle registers an handler which is executed before a kite.Handler method is executed. Calling PreHandle multiple times registers multiple handlers. A non-error return triggers the execution of the next handler. The execution order is FIFO.

func (*Kite) PreHandleFunc

func (k *Kite) PreHandleFunc(handler HandlerFunc)

PreHandleFunc is the same as PreHandle. It accepts a HandlerFunc.

func (*Kite) RSAKey

func (k *Kite) RSAKey(token *jwt.Token) (interface{}, error)

RSAKey returns the corresponding public key for the issuer of the token. It is called by jwt-go package when validating the signature in the token.

func (*Kite) Register

func (k *Kite) Register(kiteURL *url.URL) (*registerResult, error)

Register registers current Kite to Kontrol. After registration other Kites can find it via GetKites() or WatchKites() method. This method does not handle the reconnection case. If you want to keep registered to kontrol, use RegisterForever().

func (*Kite) RegisterForever

func (k *Kite) RegisterForever(kiteURL *url.URL) error

RegisterForever is equilavent to Register(), but it tries to re-register if there is a disconnection. The returned error is for the first register attempt. It returns nil if ReadNotify() is ready and it's registered succesfull.

func (*Kite) RegisterHTTP

func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error)

RegisterHTTP registers current Kite to Kontrol. After registration other Kites can find it via GetKites() or WatchKites() method. It registers again if connection to kontrol is lost.

func (*Kite) RegisterHTTPForever

func (k *Kite) RegisterHTTPForever(kiteURL *url.URL)

RegisterHTTPForever is just like RegisterHTTP however it first tries to register forever until a response from kontrol is received. It's useful to use it during app initializations. After the registration a reconnect is automatically handled inside the RegisterHTTP method.

func (*Kite) RegisterToProxy

func (k *Kite) RegisterToProxy(registerURL *url.URL, query *protocol.KontrolQuery)

RegisterToProxy is just like RegisterForever but registers the given URL to kontrol over a kite-proxy. A Kiteproxy is a reverseproxy that can be used for SSL termination or handling hundreds of kites behind a single. This is a blocking function.

func (*Kite) RegisterToTunnel

func (k *Kite) RegisterToTunnel()

RegisterToTunnel finds a tunnel proxy kite by asking kontrol then registers itselfs on proxy. On error, retries forever. On every successfull registration, it sends the proxied URL to the registerChan channel. There is no register URL needed because the Tunnel Proxy automatically gets the IP from tunneling. This is a blocking function.

func (*Kite) RegisterURL

func (k *Kite) RegisterURL(local bool) *url.URL

RegisterURL returns a URL that is either local or public. It's an helper method to get a Registration URL that can be passed to Kontrol (via the methods Register(), RegisterToProxy(), etc.) It needs to be called after all configurations are done (like TLS, Port,etc.). If local is true a local IP is used, otherwise a public IP is being used.

func (*Kite) Run

func (k *Kite) Run()

Run is a blocking method. It runs the kite server and then accepts requests asynchronously. It supports graceful restart via SIGUSR2.

func (*Kite) ServeHTTP

func (k *Kite) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP helps Kite to satisfy the http.Handler interface. So kite can be used as a standard http server.

func (*Kite) ServerCloseNotify

func (k *Kite) ServerCloseNotify() chan bool

func (*Kite) ServerReadyNotify

func (k *Kite) ServerReadyNotify() chan bool

func (*Kite) SetupKontrolClient

func (k *Kite) SetupKontrolClient() error

SetupKontrolClient setups and prepares a the kontrol instance. It connects to kontrol and reconnects again if there is any disconnections. This method is called internally whenever a kontrol client specific action is taking. However if you wish to connect earlier you may call this method.

func (*Kite) SetupSignalHandler

func (k *Kite) SetupSignalHandler()

SetupSignalHandler listens to signals and toggles the log level to DEBUG mode when it received a SIGUSR2 signal. Another SIGUSR2 toggles the log level back to the old level.

func (*Kite) TellKontrolWithTimeout

func (k *Kite) TellKontrolWithTimeout(method string, timeout time.Duration, args ...interface{}) (result *dnode.Partial, err error)

TellKontrolWithTimeout is a lower level function for communicating directly with kontrol. Like GetKites and GetToken, this automatically sets up and connects to kontrol as needed.

func (*Kite) TrustKontrolKey

func (k *Kite) TrustKontrolKey(issuer, key string)

Trust a Kontrol key for validating tokens.

func (*Kite) UseTLS

func (k *Kite) UseTLS(certPEM, keyPEM string)

func (*Kite) UseTLSFile

func (k *Kite) UseTLSFile(certFile, keyFile string)

type Level

type Level int
const (
	FATAL Level = iota
	ERROR
	WARNING
	INFO
	DEBUG
)

Logging levels.

type Logger

type Logger interface {
	// Fatal logs to the FATAL, ERROR, WARNING, INFO and DEBUG levels,
	// including a stack trace of all running goroutines, then calls
	// os.Exit(1).
	Fatal(format string, args ...interface{})

	// Error logs to the ERROR, WARNING, INFO and DEBUG level.
	Error(format string, args ...interface{})

	// Warning logs to the WARNING, INFO and DEBUG level.
	Warning(format string, args ...interface{})

	// Info logs to the INFO and DEBUG level.
	Info(format string, args ...interface{})

	// Debug logs to the DEBUG level.
	Debug(format string, args ...interface{})
}

Logger is the interface used to log messages in different levels.

type Method

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

Method defines a method and the Handler it is bind to. By default "ReturnMethod" handling is used.

func (*Method) DisableAuthentication

func (m *Method) DisableAuthentication() *Method

DisableAuthentication disables authentication check for this method.

func (*Method) PostHandle

func (m *Method) PostHandle(handler Handler) *Method

PostHandle adds a new kite handler which is executed after the method.

func (*Method) PostHandleFunc

func (m *Method) PostHandleFunc(handler HandlerFunc) *Method

PostHandlerFunc adds a new kite handlerfunc which is executed before the method.

func (*Method) PreHandle

func (m *Method) PreHandle(handler Handler) *Method

PreHandler adds a new kite handler which is executed before the method.

func (*Method) PreHandleFunc

func (m *Method) PreHandleFunc(handler HandlerFunc) *Method

PreHandlerFunc adds a new kite handlerfunc which is executed before the method.

func (*Method) ServeKite

func (m *Method) ServeKite(r *Request) (interface{}, error)

func (*Method) Throttle

func (m *Method) Throttle(fillInterval time.Duration, capacity int64) *Method

Throttle throttles the method for each incoming request. The throttle algorithm is based on token bucket implementation: http://en.wikipedia.org/wiki/Token_bucket. Rate determines the number of request which are allowed per frequency. Example: A capacity of 50 and fillInterval of two seconds means that initially it can handle 50 requests and every two seconds the bucket will be filled with one token until it hits the capacity. If there is a burst API calls, all tokens will be exhausted and clients need to be wait until the bucket is filled with time. For example to have throttle with 30 req/second, you need to have a fillinterval of 33.33 milliseconds.

type MethodHandling

type MethodHandling int

MethodHandling defines how to handle chaining of kite.Handler middlewares. An error breaks the chain regardless of what handling is used. Note that all Pre and Post handlers are executed regardless the handling logic, only the return paramater is defined by the handling mode.

const (
	// ReturnMethod returns main method's response. This is the standard default.
	ReturnMethod MethodHandling = iota

	// ReturnFirst returns the first non-nil response.
	ReturnFirst

	// ReturnLatest returns the latest response (waterfall behaviour)
	ReturnLatest
)

type Request

type Request struct {
	// Method defines the method name which is invoked by the incoming request
	Method string

	// Args defines the incoming arguments for the given method
	Args *dnode.Partial

	// LocalKite defines a context for the local kite
	LocalKite *Kite

	// Client defines a context for the remote kite
	Client *Client

	// Username defines the username which the incoming request is bound to.
	// This is authenticated and validated if authentication is enabled.
	Username string

	// Auth stores the authentication information for the incoming request and
	// the type of authentication. This is not used when authentication is disabled
	Auth *Auth

	// Context holds a context that used by the current ServeKite handler. Any
	// items added to the Context can be fetched from other handlers in the
	// chain. This is useful with PreHandle and PostHandle handlers to pass
	// data between handlers.
	Context cache.Cache
}

Request contains information about the incoming request.

type Response

type Response struct {
	Error  *Error      `json:"error" dnode:"-"`
	Result interface{} `json:"result"`
}

Response is the type of the object that is returned from request handlers and the type of only argument that is passed to callback functions.

type TokenRenewer

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

TokenRenewer renews the token of a Client just before it expires.

func NewTokenRenewer

func NewTokenRenewer(r *Client, k *Kite) (*TokenRenewer, error)

func (*TokenRenewer) RenewWhenExpires

func (t *TokenRenewer) RenewWhenExpires()

RenewWhenExpires renews the token before it expires.

Directories

Path Synopsis
Package config contains a Config struct for kites.
Package config contains a Config struct for kites.
Package dnode implements a dnode scrubber.
Package dnode implements a dnode scrubber.
examples
Command line tool for using kite services.
Command line tool for using kite services.
Package kitekey provides method for reading and writing kite.key file.
Package kitekey provides method for reading and writing kite.key file.
Package protocol defines the communication between the components of the Kite infrastructure.
Package protocol defines the communication between the components of the Kite infrastructure.
Package systeminfo provides a way of getting memory usage, disk usage and various information about the host.
Package systeminfo provides a way of getting memory usage, disk usage and various information about the host.
Package testkeys contains RSA keys and TLS certificates for using in examples and tests.
Package testkeys contains RSA keys and TLS certificates for using in examples and tests.
Package testutil provides a default Kontrol kites for using in tests.
Package testutil provides a default Kontrol kites for using in tests.

Jump to

Keyboard shortcuts

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