Coder Social home page Coder Social logo

koding / kite Goto Github PK

View Code? Open in Web Editor NEW
3.3K 3.3K 299.0 4.14 MB

Micro-service framework in Go

Home Page: https://godoc.org/github.com/koding/kite

License: MIT License

Makefile 1.33% Go 96.50% Python 1.96% SQLPL 0.12% Shell 0.08%
authentication-backend discovery-service go web-framework

kite's Introduction

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.

kite's People

Contributors

canthefason avatar cenkalti avatar cihangir avatar d6o avatar eikaas avatar fatih avatar gokmen avatar humanchimp avatar igungor avatar mischief avatar oguzalb avatar pdxjohnny avatar ppknap avatar rjeczalik avatar sent-hil avatar sinan avatar szkl avatar techjanitor avatar wingyplus avatar ybrs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kite's Issues

Update jwt

jwt package is updated and backwards incompatible changes are introduced. We should update the code to use the new API.

Make install does not work (can't load proxy package)

I guess proxy package is changed. Can you update "install" task according to this?

It is obvious but still pasting the error message here:

can't load package: package github.com/koding/kite/proxy/proxy: cannot find package "github.com/koding/kite/proxy/proxy"

Tests are failing

First following tests are failed:

Creating 100 mathworker kites
Creating 100 exp clients
2014/07/13 21:14:22 http: Accept error: accept tcp 127.0.0.1:6075: too many open files; retrying in 5ms
--- FAIL: TestMultiple (2.71 seconds)
    kite_test.go:46: unexpected EOF
--- FAIL: TestKite (1.01 seconds)
    kite_test.go:119: dial tcp 127.0.0.1:3636: too many open files
FAIL
FAIL    github.com/koding/kite  3.782s

After setting ulimit this time I have received this error:

reverseproxy/reverseproxy.go:17:2: cannot find package "github.com/koding/websocketproxy" in any of:
    /usr/local/Cellar/go/1.3/libexec/src/pkg/github.com/koding/websocketproxy (from $GOROOT)
    /Users/canthefason/go/src/github.com/koding/websocketproxy (from $GOPATH)

I guess another issue related with: #42

Generated kite.key is invalid

I am trying to set up a local kontrol install and I am pretty sure I generated my keys and everything correctly but when I go to check the key that i generated with kontrol -initial with kite showkey I am getting an error of:

Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key

error-first callback style

IMO, callbacks should have the error passed first. This is the standard practice in node, and increasingly in browser javascript, it is the convention that Koding uses, and it has some tangible advantages.

must handle errors

It is far too easy to ignore errors.

k.tell('maybeFails', { seed: Math.random() }, (err, result) => {
  doStuffWithResult(result); // whoops, I forgot to handle the error!
});

Putting the error somewhere other than first makes the omission even easier still.

k.tell('maybeFails', { seed: Math.random() }, result => {
  doStuffWithResult(result); // didn't even see/know about the error (it's the second parameter)
});

variadic callback signatures

Compare this:

cb(arg1, arg2, arg3, err)

With this:

cb(err, arg1, arg2, arg3)

In coffeescript, you could write:

k.tell 'fetchThimgamijigs', 42, (err, rest...) -> ...

or in the next edition of JavaScript:

k.tell('fetchThimgamijigs', 42, (err, ...rest) => { ... });

In ES6, the rest parameter must be last (although it's allowed in any position in coffee-script). Having the error first is better style, and lends itself to language idioms.

consistent convention

When the error is always first, we can make convenient assumptions. For instance, without knowing the details of a particular operation, I can write code that assumes that if the the first parameter of a callback is not null, then an error occurred. I can then leverage this information—for instance, I can pipeline the errors away into a triage, and the code doing the pipelining does not need to know anything particular about the individual errors.

I'll leave it there for now, but I guess that there are probably other advantages. These are the major ones tho.

Remove Start() method.

It's confusing and don't really fit in our Library. Run() could return a channel for ReadyNotify() if people want to call it async way (an idea).

implement a method "kite.methods"

This method would return a representation of the signatures for all the methods of a kite:

{
    "square": [ "num", "callback" ],
    "pow": [ { "kwargs": [ "base", "exponent" ] }, "callback" ]
}

We can figure out what color to paint the bikeshed, and also discuss whether we want to also support optional type annotations. The idea is that it's a general faculty for finding out what methods are offered by a kite. On the JS side, we can automatically create method shims for each method so that instead of needing to do, say, kite.tell('getRiffiwobbles') we could more handily call kite.getRiffiwobbles(). Also, for the kite website, we can have a bunch of different kind of kites registered, but the javascript client does not need to know specifics about those kites in order to display UI that will let the user call the remote methods.

We could reflect the type information from the registered methods, and represent that in some way, so that the client could optionally validate the types of arguments it receives before sending the message. The type annotation part seems like a nice-to-have, but I think we do need method itself.

Swap Simple and Kite

Default kite should have Run() methods, should be able to make queries to Kontrol. The kite package should be a low-level package to build packages around.

Remove logs from Tests

To much output is not good. Go testing package has -v for that purpose, therefore each log should be protected and wrapped with testing.Verbose().

Fix shadowing variables

❯ go tool vet -shadow . 
client.go:298: declaration of err shadows declaration at client.go:280
cmd/tell.go:59: declaration of err shadows declaration at cmd/tell.go:35
kontrol/kontrol.go:505: declaration of err shadows declaration at kontrol/kontrol.go:464
kontrol/kontrol.go:515: declaration of err shadows declaration at kontrol/kontrol.go:464
regserv/regserv/main.go:60: declaration of err shadows declaration at regserv/regserv/main.go:42

Remove etcd from kontrol and decouple them.

The current state is not scalable. Etcd is a storage service and needs to work alone. It's deployed once and that's it. Kontrol itself could have multiple instances behind a proxy or domain. Kontrol instances should speak with etcd if necessary.

Currently with any new deployment we also are deploying etcd with it. Decoupling them also is another step to have different storage backends for kontrol. Projects like skydns also uses the same approach.

getToken errors out

It seems like getToken is causing this:

Error in received message: kite error genericError - runtime error: invalid memory address or nil pointer dereference

But it's not returning in error, but instead returning a null token. I think it should respond with an error instead.

We need to fix this in order to finish the expiring tokens implementation for kite.js

Make rpc codec pluggable

Currently message logic is done inside the Dnode via functions passed to it. We should reverse the whole process, just like net/rpc and have custom codecs (gob, json-rpc, bson and co).

how to register a kite to my locally-running Kontrol

I realize this is an issue tracker, not a support forum, but I need to know how I can register a kite, say the mathworker, to my locally-running instance of kontrol, rather than the one that is running at kite-kontrol.koding.com. Please advise.

kite_key or KITE_HOME

Not really an "issue", more of a question

I was noticing that the kite library uses a KITE_HOME variable, whereas over in kite.js we are passing the path to the kite.key file. I guess that we should also pass KITE_HOME instead, and then just find the "./kite/kite.key" file relative to that. Are there other files in KITE_HOME? I wondered why we are using KITE_HOME and inferring the kite.key location rather than jus explicitly passing the path to the kite.key

Closer interface for kite methods.

Our kite handler only satisfies currently this interface:

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

This is sufficient to handle and call a method. We should add a new feature to http://godoc.org/github.com/koding/kite#Kite.Close that when closed it should check whether a method also supports http://golang.org/pkg/io/#Closer, if yes it should call it. Example implementation:

func (k *Kite) Close() {
    //...

    for _, method := range k.handlers {
        if m, ok := method.(io.Closer); ok {
            m.Close()
        }
    }
}

This is helpful for graceful shutdown of a kite or cleaning up resources for some specific methods. This is an idea and open to suggestions.

koding dnode as a separate module?

Maybe we should elevate the koding/dnode protocol as a separate module from koding/kite? This is just an idea, but ISTM there is nothing kite-specific about dnode protocol.

Expose websocket TLSClientConfig

I think it would be good to have the option to configure TLSClientConfig in Gorilla websocket. This would enable the utilization of unsigned certs which seems to be an impossibility right now for wss (?)

http://godoc.org/github.com/gorilla/websocket#Dialer

&tls.Config{InsecureSkipVerify: true}
&tls.Config{RootCAs: certs}

It could potentially be a setting in the Client struct, much like how Kite has TLSConfig for its listener. Or it could just inherit c.LocalKite.TLSConfig when c.dial initializes &sockjsclient.DialOptions.

In addition, a method of setting the TLSConfig for k.kontrol.Client would be useful as well.

I tried to implement this myself but I ran into some strange issues with heartbeat session authentication between a client and kontrol.

Remove debug.PrintStack() for error

Stack only should be printed when something really goes wrong, but not when there is a minor error (like client sending wrong paramaters)

panic: runtime error: close of closed channel

Let's add this here, needs to be fixed. Happens 1/100 and rarely.

2014-07-02 14:34:48 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:34:49 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:34:49 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:34:50 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:34:52 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:34:55 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:35:00 [kloud] ERROR    websocket: bad handshake
2014-07-02 14:35:08 [kloud] ERROR    websocket: bad handshake
panic: runtime error: close of closed channel

goroutine 430 [running]:
runtime.panic(0x4b7da0, 0xb42475)
        /usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
github.com/koding/kite.func·032()
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/tokenrenewer.go:54 +0x2d
github.com/koding/kite.func·007()
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/client.go:358 +0x4b
github.com/koding/kite.(*Client).callOnDisconnectHandlers(0xc2103d5c00)
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/client.go:359 +0xac
github.com/koding/kite.(*Client).run(0xc2103d5c00)
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/client.go:213 +0x35
created by github.com/koding/kite.(*Client).dialForever
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/client.go:166 +0xaa

goroutine 1 [IO wait]:
net.runtime_pollWait(0xe12b70, 0x72, 0x0)
        /private/var/folders/00/0sdwh000h01000cxqpysvccm0035qk/T/bindist922710130/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(*pollDesc).Wait(0xc210047370, 0x72, 0xe110c0, 0x23)
        /usr/local/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(*pollDesc).WaitRead(0xc210047370, 0x23, 0xe110c0)
        /usr/local/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(*netFD).accept(0xc210047310, 0x66c530, 0x0, 0xe110c0, 0x23)
        /usr/local/go/src/pkg/net/fd_unix.go:382 +0x2c2
net.(*TCPListener).AcceptTCP(0xc210113140, 0x184b7b, 0xfb1b78, 0x184b7b)
        /usr/local/go/src/pkg/net/tcpsock_posix.go:233 +0x47
net.(*TCPListener).Accept(0xc210113140, 0xe13088, 0xc2101db078, 0xc2103f6480, 0x0)
        /usr/local/go/src/pkg/net/tcpsock_posix.go:243 +0x27
net/http.(*Server).Serve(0xc2100deeb0, 0xe14068, 0xc210113140, 0x0, 0x0)
        /usr/local/go/src/pkg/net/http/server.go:1622 +0x91
net/http.Serve(0xe14068, 0xc210113140, 0xe140a0, 0xc2100795a0, 0x0, ...)
        /usr/local/go/src/pkg/net/http/server.go:1561 +0x70
github.com/koding/kite.(*Kite).listenAndServe(0xc2100795a0, 0x0, 0x0)
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/server.go:82 +0x3cf
github.com/koding/kite.(*Kite).Run(0xc2100795a0)
        /Users/gokmen/Code/koding/go/src/github.com/koding/kite/server.go:28 +0x10e

kontrol: new signature for getKites()

on the kite.js side, we're doing:

ok = k.tell('getKites', [query, changesHandler]);

I think we want to get rid of these positional parameters (or at least avoid them). I would like it if the signature changes to this:

ok = k.tell('getKites', [{ query, onChange }]);

And once we do koding/kite.js#2, we can remove the extra array wrapper:

ok = k.tell('getKites', { query, onChange });

I am open for suggestions, but for the time being I've chosen the name onChange. The name is not important to me, but I would like to move away from positional parameters.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.