<commit_before>package main

// Much of this code originates from https://github.com/AaronO/go-git-http
// Licensed under Apache-2.0

import (
	"compress/flate"
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/gitpods/gitpods/cmd"
	"github.com/go-chi/chi"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
)

type GitHTTP struct {
	root   string
	git    string
	Logger log.Logger
}

func NewGitHTTP(root string) *GitHTTP {
	return &GitHTTP{
		root:   root,
		git:    "/usr/bin/git",
		Logger: log.NewNopLogger(),
	}
}

func (gh *GitHTTP) Handler() *chi.Mux {
	r := chi.NewRouter()
	r.Use(cmd.NewRequestLogger(gh.Logger))

	//dings := githttp.New(gh.root)
	//r.Mount("/", dings)
	//return r

	r.Get("/{owner}/{name}/HEAD", NoCaching(gh.headHandler))
	r.Get("/{owner}/{name}/info/refs", NoCaching(gh.infoRefsHandler))
	r.Get("/{owner}/{name}/objects/{folder:[0-9a-f]{2}}/{file:[0-9a-f]{38}}", CacheForever(gh.looseObjectHandler))
	r.Get("/{owner}/{name}/objects/info/{thing:[^/]*}", NoCaching(gh.infoHandler)) // TODO
	r.Get("/{owner}/{name}/objects/info/alternates", NoCaching(gh.alternatesHandler))
	r.Get("/{owner}/{name}/objects/info/http-alternates", NoCaching(gh.httpAlternatesHandler))
	r.Get("/{owner}/{name}/objects/info/packs", CacheForever(gh.infoPacksHandler))
	r.Get("/{owner}/{name}/objects/pack/pack-{hash:[0-9a-f]{40}}.idx", CacheForever(gh.idxHandler))
	r.Get("/{owner}/{name}/objects/pack/pack-{hash:[0-9a-f]{40}}.pack", CacheForever(gh.packHandler))
	r.Post("/{owner}/{name}/git-{service}", gh.serviceHandler)

	r.NotFound(func(w http.ResponseWriter, r *http.Request) {
		level.Debug(gh.Logger).Log(
			"msg", "not found",
			"path", r.URL.String(),
		)
	})

	return r
}

func NoCaching(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
		w.Header().Set("Pragma", "no-cache")
		w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
		next.ServeHTTP(w, r)
	}
}

func CacheForever(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		now := time.Now()
		expires := now.AddDate(1, 0, 0)
		w.Header().Set("Date", fmt.Sprintf("%d", now.Unix()))
		w.Header().Set("Expires", fmt.Sprintf("%d", expires.Unix()))
		w.Header().Set("Cache-Control", "public, max-age=31536000")
		next.ServeHTTP(w, r)
	}
}

func (gh *GitHTTP) headHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "HEAD")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) alternatesHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/alternates")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) httpAlternatesHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/http-alternates")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) infoPacksHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/packs")

	h := gh.textFileHandler(path, "text/plain; charset=utf-8")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) idxHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	hash := chi.URLParam(r, "hash")
	path := filepath.Join(gh.root, owner, name, fmt.Sprintf("objects/pack/pack-%s.idx", hash))

	h := gh.textFileHandler(path, "application/x-git-packed-objects-toc")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) packHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	hash := chi.URLParam(r, "hash")
	path := filepath.Join(gh.root, owner, name, fmt.Sprintf("objects/pack/pack-%s.pack", hash))

	h := gh.textFileHandler(path, "application/x-git-packed-objects")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) textFileHandler(path string, contentType string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		f, err := os.Stat(path)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", contentType)
		w.Header().Set("Content-Length", fmt.Sprintf("%d", f.Size()))
		w.Header().Set("Last-Modified", f.ModTime().Format(http.TimeFormat))
		http.ServeFile(w, r, path)
	}
}

func (gh *GitHTTP) serviceHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	service := chi.URLParam(r, "service")
	logger := log.With(gh.Logger,
		"owner", owner,
		"name", name,
		"service", service,
	)

	defer r.Body.Close()

	var body io.Reader
	var err error
	switch r.Header.Get("content-encoding") {
	case "gzip":
		body, err = gzip.NewReader(r.Body)
	case "deflate":
		body = flate.NewReader(r.Body)
	default:
		body = r.Body
	}

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create body reader", "err", err)
		return
	}

	args := []string{service, "--stateless-rpc", "."}
	cmd := exec.CommandContext(context.Background(), gh.git, args...)
	cmd.Dir = filepath.Join(gh.root, owner, name)

	stdin, err := cmd.StdinPipe()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create pipe to git's stdin", "err", err)
		return
	}
	defer stdin.Close()

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create pipe to git's stdout", "err", err)
		return
	}
	defer stdout.Close()

	if err := cmd.Start(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to start git", "err", err)
		return
	}

	if _, err := io.Copy(stdin, body); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to copy request to git's stdin", "err", err)
		return
	}
	stdin.Close()

	if _, err := io.Copy(w, stdout); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to copy git's stdout to response", "err", err)
		return
	}

	if err := cmd.Wait(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to wait for git", "err", err)
		return
	}

	// TODO: Fire events to channel

	w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))

}

func (gh *GitHTTP) infoRefsHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	service := serviceQuery(r)
	logger := log.With(gh.Logger,
		"owner", owner,
		"name", name,
		"service", service,
	)

	ctx, cancel := context.WithTimeout(r.Context(), time.Second)
	defer cancel()

	args := []string{service, "--stateless-rpc", "--advertise-refs", "."}
	cmd := exec.CommandContext(ctx, gh.git, args...)
	cmd.Dir = filepath.Join(gh.root, owner, name)

	refs, err := cmd.Output()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to get refs", "err", err)
		return
	}

	w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service))
	w.Write(packetWrite(fmt.Sprintf("# service=git-%s\n", service)))
	w.Write(packetFlush())
	w.Write(refs)
}

func (gh *GitHTTP) looseObjectHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	folder := chi.URLParam(r, "folder")
	file := chi.URLParam(r, "file")
	path := filepath.Join(gh.root, owner, name, folder, file)

	gh.textFileHandler(path, "application/x-git-loose-object")
}

func (gh *GitHTTP) infoHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	thing := chi.URLParam(r, "thing")
	path := filepath.Join(gh.root, owner, name, "objects", "info", thing)

	fmt.Println(r.URL.String())
	gh.textFileHandler(path, "text/plain")

}

func ownerName(r *http.Request) (string, string) {
	return chi.URLParam(r, "owner"), chi.URLParam(r, "name")
}

func serviceQuery(r *http.Request) string {
	return strings.TrimPrefix(r.URL.Query().Get("service"), "git-")
}

func packetFlush() []byte {
	return []byte("0000")
}

func packetWrite(str string) []byte {
	s := strconv.FormatInt(int64(len(str)+4), 16)

	if len(s)%4 != 0 {
		s = strings.Repeat("0", 4-len(s)%4) + s
	}

	return []byte(s + str)
}
<commit_msg>Remove debugging githttp code from storage<commit_after>package main

// Much of this code originates from https://github.com/AaronO/go-git-http
// Licensed under Apache-2.0

import (
	"compress/flate"
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/gitpods/gitpods/cmd"
	"github.com/go-chi/chi"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
)

type GitHTTP struct {
	root   string
	git    string
	Logger log.Logger
}

func NewGitHTTP(root string) *GitHTTP {
	return &GitHTTP{
		root:   root,
		git:    "/usr/bin/git",
		Logger: log.NewNopLogger(),
	}
}

func (gh *GitHTTP) Handler() *chi.Mux {
	r := chi.NewRouter()
	r.Use(cmd.NewRequestLogger(gh.Logger))

	r.Get("/{owner}/{name}/HEAD", NoCaching(gh.headHandler))
	r.Get("/{owner}/{name}/info/refs", NoCaching(gh.infoRefsHandler))
	r.Get("/{owner}/{name}/objects/{folder:[0-9a-f]{2}}/{file:[0-9a-f]{38}}", CacheForever(gh.looseObjectHandler))
	r.Get("/{owner}/{name}/objects/info/{thing:[^/]*}", NoCaching(gh.infoHandler)) // TODO
	r.Get("/{owner}/{name}/objects/info/alternates", NoCaching(gh.alternatesHandler))
	r.Get("/{owner}/{name}/objects/info/http-alternates", NoCaching(gh.httpAlternatesHandler))
	r.Get("/{owner}/{name}/objects/info/packs", CacheForever(gh.infoPacksHandler))
	r.Get("/{owner}/{name}/objects/pack/pack-{hash:[0-9a-f]{40}}.idx", CacheForever(gh.idxHandler))
	r.Get("/{owner}/{name}/objects/pack/pack-{hash:[0-9a-f]{40}}.pack", CacheForever(gh.packHandler))
	r.Post("/{owner}/{name}/git-{service}", gh.serviceHandler)

	r.NotFound(func(w http.ResponseWriter, r *http.Request) {
		level.Debug(gh.Logger).Log(
			"msg", "not found",
			"path", r.URL.String(),
		)
	})

	return r
}

func NoCaching(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
		w.Header().Set("Pragma", "no-cache")
		w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
		next.ServeHTTP(w, r)
	}
}

func CacheForever(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		now := time.Now()
		expires := now.AddDate(1, 0, 0)
		w.Header().Set("Date", fmt.Sprintf("%d", now.Unix()))
		w.Header().Set("Expires", fmt.Sprintf("%d", expires.Unix()))
		w.Header().Set("Cache-Control", "public, max-age=31536000")
		next.ServeHTTP(w, r)
	}
}

func (gh *GitHTTP) headHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "HEAD")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) alternatesHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/alternates")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) httpAlternatesHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/http-alternates")

	h := gh.textFileHandler(path, "text/plain")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) infoPacksHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	path := filepath.Join(gh.root, owner, name, "/objects/info/packs")

	h := gh.textFileHandler(path, "text/plain; charset=utf-8")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) idxHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	hash := chi.URLParam(r, "hash")
	path := filepath.Join(gh.root, owner, name, fmt.Sprintf("objects/pack/pack-%s.idx", hash))

	h := gh.textFileHandler(path, "application/x-git-packed-objects-toc")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) packHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	hash := chi.URLParam(r, "hash")
	path := filepath.Join(gh.root, owner, name, fmt.Sprintf("objects/pack/pack-%s.pack", hash))

	h := gh.textFileHandler(path, "application/x-git-packed-objects")
	h.ServeHTTP(w, r)
}

func (gh *GitHTTP) textFileHandler(path string, contentType string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		f, err := os.Stat(path)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", contentType)
		w.Header().Set("Content-Length", fmt.Sprintf("%d", f.Size()))
		w.Header().Set("Last-Modified", f.ModTime().Format(http.TimeFormat))
		http.ServeFile(w, r, path)
	}
}

func (gh *GitHTTP) serviceHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	service := chi.URLParam(r, "service")
	logger := log.With(gh.Logger,
		"owner", owner,
		"name", name,
		"service", service,
	)

	defer r.Body.Close()

	var body io.Reader
	var err error
	switch r.Header.Get("content-encoding") {
	case "gzip":
		body, err = gzip.NewReader(r.Body)
	case "deflate":
		body = flate.NewReader(r.Body)
	default:
		body = r.Body
	}

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create body reader", "err", err)
		return
	}

	args := []string{service, "--stateless-rpc", "."}
	cmd := exec.CommandContext(context.Background(), gh.git, args...)
	cmd.Dir = filepath.Join(gh.root, owner, name)

	stdin, err := cmd.StdinPipe()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create pipe to git's stdin", "err", err)
		return
	}
	defer stdin.Close()

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to create pipe to git's stdout", "err", err)
		return
	}
	defer stdout.Close()

	if err := cmd.Start(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to start git", "err", err)
		return
	}

	if _, err := io.Copy(stdin, body); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to copy request to git's stdin", "err", err)
		return
	}
	stdin.Close()

	if _, err := io.Copy(w, stdout); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to copy git's stdout to response", "err", err)
		return
	}

	if err := cmd.Wait(); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to wait for git", "err", err)
		return
	}

	// TODO: Fire events to channel

	w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))

}

func (gh *GitHTTP) infoRefsHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	service := serviceQuery(r)
	logger := log.With(gh.Logger,
		"owner", owner,
		"name", name,
		"service", service,
	)

	ctx, cancel := context.WithTimeout(r.Context(), time.Second)
	defer cancel()

	args := []string{service, "--stateless-rpc", "--advertise-refs", "."}
	cmd := exec.CommandContext(ctx, gh.git, args...)
	cmd.Dir = filepath.Join(gh.root, owner, name)

	refs, err := cmd.Output()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		level.Warn(logger).Log("msg", "failed to get refs", "err", err)
		return
	}

	w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service))
	w.Write(packetWrite(fmt.Sprintf("# service=git-%s\n", service)))
	w.Write(packetFlush())
	w.Write(refs)
}

func (gh *GitHTTP) looseObjectHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	folder := chi.URLParam(r, "folder")
	file := chi.URLParam(r, "file")
	path := filepath.Join(gh.root, owner, name, folder, file)

	gh.textFileHandler(path, "application/x-git-loose-object")
}

func (gh *GitHTTP) infoHandler(w http.ResponseWriter, r *http.Request) {
	owner, name := ownerName(r)
	thing := chi.URLParam(r, "thing")
	path := filepath.Join(gh.root, owner, name, "objects", "info", thing)

	fmt.Println(r.URL.String())
	gh.textFileHandler(path, "text/plain")

}

func ownerName(r *http.Request) (string, string) {
	return chi.URLParam(r, "owner"), chi.URLParam(r, "name")
}

func serviceQuery(r *http.Request) string {
	return strings.TrimPrefix(r.URL.Query().Get("service"), "git-")
}

func packetFlush() []byte {
	return []byte("0000")
}

func packetWrite(str string) []byte {
	s := strconv.FormatInt(int64(len(str)+4), 16)

	if len(s)%4 != 0 {
		s = strings.Repeat("0", 4-len(s)%4) + s
	}

	return []byte(s + str)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"fmt"
	"log"

	flag "github.com/spf13/pflag"

	"kubevirt.io/kubevirt/pkg/virtctl"
	"kubevirt.io/kubevirt/pkg/virtctl/console"
	"kubevirt.io/kubevirt/pkg/virtctl/convert"
	"kubevirt.io/kubevirt/pkg/virtctl/spice"
)

func main() {

	log.SetFlags(0)
	log.SetOutput(os.Stderr)

	registry := map[string]virtctl.App{
		"console":      &console.Console{},
		"options":      &virtctl.Options{},
		"spice":        &spice.Spice{},
		"convert-spec": convert.NewConvertCommand(),
	}

	for cmd, app := range registry {
		f := app.FlagSet()
		f.Bool("help", false, "Print usage.")
		f.MarkHidden("help")
		f.Usage = func() {
			fmt.Fprint(os.Stderr, app.Usage())
		}

		if os.Args[1] != cmd {
			continue
		}
		flags, err := Parse(f)

		h, _ := flags.GetBool("help")
		if h || err != nil {
			f.Usage()
			return
		}
		os.Exit(app.Run(flags))
	}

	Usage()
	os.Exit(1)
}

func Parse(flags *flag.FlagSet) (*flag.FlagSet, error) {
	flags.AddFlagSet((&virtctl.Options{}).FlagSet())
	err := flags.Parse(os.Args[1:])
	return flags, err
}

func Usage() {
	fmt.Fprintln(os.Stderr,
		`virtctl controls VM related operations on your kubernetes cluster.

Basic Commands:
  console        Connect to a serial console on a VM
  convert-spec   Convert between Libvirt and KubeVirt specifications

Use "virtctl <command> --help" for more information about a given command.
Use "virtctl options" for a list of global command-line options (applies to all commands).
	`)
}
<commit_msg>Don't look for virtctl command if none is given<commit_after>package main

import (
	"os"

	"fmt"
	"log"

	flag "github.com/spf13/pflag"

	"kubevirt.io/kubevirt/pkg/virtctl"
	"kubevirt.io/kubevirt/pkg/virtctl/console"
	"kubevirt.io/kubevirt/pkg/virtctl/convert"
	"kubevirt.io/kubevirt/pkg/virtctl/spice"
)

func main() {

	log.SetFlags(0)
	log.SetOutput(os.Stderr)

	registry := map[string]virtctl.App{
		"console":      &console.Console{},
		"options":      &virtctl.Options{},
		"spice":        &spice.Spice{},
		"convert-spec": convert.NewConvertCommand(),
	}

	if len(os.Args) > 1 {
		for cmd, app := range registry {
			f := app.FlagSet()
			f.Bool("help", false, "Print usage.")
			f.MarkHidden("help")
			f.Usage = func() {
				fmt.Fprint(os.Stderr, app.Usage())
			}

			if os.Args[1] != cmd {
				continue
			}
			flags, err := Parse(f)

			h, _ := flags.GetBool("help")
			if h || err != nil {
				f.Usage()
				return
			}
			os.Exit(app.Run(flags))
		}
	}

	Usage()
	os.Exit(1)
}

func Parse(flags *flag.FlagSet) (*flag.FlagSet, error) {
	flags.AddFlagSet((&virtctl.Options{}).FlagSet())
	err := flags.Parse(os.Args[1:])
	return flags, err
}

func Usage() {
	fmt.Fprintln(os.Stderr,
		`virtctl controls VM related operations on your kubernetes cluster.

Basic Commands:
  console        Connect to a serial console on a VM
  convert-spec   Convert between Libvirt and KubeVirt specifications

Use "virtctl <command> --help" for more information about a given command.
Use "virtctl options" for a list of global command-line options (applies to all commands).
	`)
}
<|endoftext|>


<commit_before>// Package juno implements the messaging spec of the Jupyter Messaging Protocol,
// just for you.
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
package juno

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"os"

	zmq "github.com/zeromq/goczmq"
)

// MessageHeader is a Jupyter message header
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
type MessageHeader struct {
	MessageID   string `json:"msg_id"`
	Username    string `json:"username"`
	Session     string `json:"session"`
	MessageType string `json:"msg_type"`
	Version     string `json:"version"`
}

// Message is a generic Jupyter message (not a wire message)
// http://jupyter-client.readthedocs.org/en/latest/messaging.html#general-message-format
type Message struct {
	Header       MessageHeader          `json:"header"`
	ParentHeader MessageHeader          `json:"parent_header"`
	Metadata     map[string]interface{} `json:"metadata"`
	Content      map[string]interface{} `json:"content"`
}

// MimeBundle is a collection of `mimetypes -> data`
// Example:
//     'text/html' -> '
Hey!
'
//     'image/png' -> 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
type MimeBundle map[string]string

// ConnectionInfo represents the runtime connection data used by Jupyter kernels
type ConnectionInfo struct {
	IOPubPort       int    `json:"iopub_port"`
	StdinPort       int    `json:"stdin_port"`
	IP              string `json:"ip"`
	Transport       string `json:"transport"`
	HBPort          int    `json:"hb_port"`
	SignatureScheme string `json:"signature_scheme"`
	ShellPort       int    `json:"shell_port"`
	ControlPort     int    `json:"control_port"`
	Key             string `json:"key"`
}

// DELIMITER denotes the Jupyter multipart message
const DELIMITER = "<IDS|MSG>"

// ParseWireProtocol fills a Message with all the juicy Jupyter bits
func (m *Message) ParseWireProtocol(wireMessage [][]byte, key []byte) (err error) {
	var i int
	var el []byte

	// Wire protocol
	// http://jupyter-client.readthedocs.org/en/latest/messaging.html#the-wire-protocol
	/**
		[
	  		b'u-u-i-d',         # zmq identity(ies)
	  		b'<IDS|MSG>',       # delimiter
	  		b'baddad42',        # HMAC signature
			b'{header}',        # serialized header dict
			b'{parent_header}', # serialized parent header dict
			b'{metadata}',      # serialized metadata dict
			b'{content}',       # serialized content dict
			b'blob',            # extra raw data buffer(s)
	  		...
		]
	*/
	// Determine where the delimiter is
	for i, el = range wireMessage {
		if string(el) == DELIMITER {
			break // Found our delimiter
		}
	}

	if i >= len(wireMessage) {
		return errors.New("Couldn't find delimeter")
	}

	// Extract the zmq identiti(es)
	//identities := wireMessage[:delimiterLocation]

	// If the message was signed
	if len(key) != 0 {
		// TODO: Programmatic selection of scheme
		mac := hmac.New(sha256.New, key)
		for _, msgpart := range wireMessage[i+2 : i+6] {
			mac.Write(msgpart)
		}
		signature := make([]byte, hex.DecodedLen(len(wireMessage[i+1])))
		hex.Decode(signature, wireMessage[i+1])
		if !hmac.Equal(mac.Sum(nil), signature) {
			return errors.New("Invalid signature")
		}
	}

	json.Unmarshal(wireMessage[i+2], &m.Header)
	json.Unmarshal(wireMessage[i+3], &m.ParentHeader)
	json.Unmarshal(wireMessage[i+4], &m.Metadata)
	json.Unmarshal(wireMessage[i+5], &m.Content)

	return nil
}

// NewConnectionInfo reads in a connection file and creates a ConnectionInfo
// struct
func NewConnectionInfo(filename string) (ConnectionInfo, error) {
	var connInfo ConnectionInfo
	connFile, err := os.Open(filename)

	if err != nil {
		return connInfo, fmt.Errorf("Couldn't open connection file: %v", err)
	}
	defer connFile.Close()

	jsonParser := json.NewDecoder(connFile)

	if err = jsonParser.Decode(&connInfo); err != nil {
		return connInfo, fmt.Errorf("Couldn't parse connection file: %v", err)
	}

	return connInfo, nil
}

// OpenConnectionFile wraps NewConnectionInfo for backwards compatiblity
func OpenConnectionFile(filename string) (ConnectionInfo, error) {
	return NewConnectionInfo(filename)
}

// JupyterSocket is a zmq.Socket coupled with connection information
type JupyterSocket struct {
	ZMQSocket *zmq.Sock
	ConnInfo  ConnectionInfo
}

// ReadMessage reads a Jupyter Protocol Message
func (s *JupyterSocket) ReadMessage() (Message, error) {
	var message Message
	wireMessage, err := s.ZMQSocket.RecvMessage()
	if err != nil {
		return message, fmt.Errorf("Error on receive: %v", err)
	}

	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))

	return message, nil
}

// NewMessage creates a new message from a wire message using the key from this
// socket's connection info
func (s *JupyterSocket) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	message.ParseWireProtocol(wireMessage, []byte(s.ConnInfo.Key))
	return message, nil
}

// Destroy obliterates zmq sockets
func (s *JupyterSocket) Destroy() {
	s.ZMQSocket.Destroy()
}

// NewIOPubSocket creates a new IOPub socket (on SUB) with the connInfo given
// subscribe is a comma delimited list of topics to subscribe to
func NewIOPubSocket(connInfo ConnectionInfo, subscribe string) (*JupyterSocket, error) {
	connectionString := connInfo.IOPubConnection()

	rawIOPubSocket, err := zmq.NewSub(connectionString, subscribe)
	if err != nil {
		return nil, err
	}

	iopub := &JupyterSocket{
		ZMQSocket: rawIOPubSocket,
		ConnInfo:  connInfo,
	}

	return iopub, nil
}

// ConnectionString forms the string for zmq libraries to connect
func (connInfo *ConnectionInfo) ConnectionString(port int) string {
	connectionString := fmt.Sprintf("%s://%s:%d",
		connInfo.Transport,
		connInfo.IP,
		port)
	return connectionString
}

// IOPubConnection forms the connection string for the IOPub socket
func (connInfo *ConnectionInfo) IOPubConnection() string {
	return connInfo.ConnectionString(connInfo.IOPubPort)
}

// NewMessage creates a new message based on
func (connInfo *ConnectionInfo) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	err := message.ParseWireProtocol(wireMessage, []byte(connInfo.Key))
	return message, err
}
<commit_msg>Clean up the previous interfaces for message parse<commit_after>// Package juno implements the messaging spec of the Jupyter Messaging Protocol,
// just for you.
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
package juno

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"hash"
	"os"

	zmq "github.com/zeromq/goczmq"
)

// MessageHeader is a Jupyter message header
// http://jupyter-client.readthedocs.org/en/latest/messaging.html
type MessageHeader struct {
	MessageID   string `json:"msg_id"`
	Username    string `json:"username"`
	Session     string `json:"session"`
	MessageType string `json:"msg_type"`
	Version     string `json:"version"`
}

// Message is a generic Jupyter message (not a wire message)
// http://jupyter-client.readthedocs.org/en/latest/messaging.html#general-message-format
type Message struct {
	Header       MessageHeader          `json:"header"`
	ParentHeader MessageHeader          `json:"parent_header"`
	Metadata     map[string]interface{} `json:"metadata"`
	Content      map[string]interface{} `json:"content"`
}

// MimeBundle is a collection of `mimetypes -> data`
// Example:
//     'text/html' -> '
Hey!
'
//     'image/png' -> 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
type MimeBundle map[string]string

// ConnectionInfo represents the runtime connection data used by Jupyter kernels
type ConnectionInfo struct {
	IOPubPort       int    `json:"iopub_port"`
	StdinPort       int    `json:"stdin_port"`
	IP              string `json:"ip"`
	Transport       string `json:"transport"`
	HBPort          int    `json:"hb_port"`
	SignatureScheme string `json:"signature_scheme"`
	ShellPort       int    `json:"shell_port"`
	ControlPort     int    `json:"control_port"`
	Key             string `json:"key"`
}

// DELIMITER denotes the Jupyter multipart message
const DELIMITER = "<IDS|MSG>"

// ParseWireProtocol fills a Message with all the juicy Jupyter bits
func (m *Message) ParseWireProtocol(wireMessage [][]byte, connInfo ConnectionInfo) (err error) {
	var i int
	var el []byte

	// Wire protocol
	// http://jupyter-client.readthedocs.org/en/latest/messaging.html#the-wire-protocol
	/**
		[
	  		b'u-u-i-d',         # zmq identity(ies)
	  		b'<IDS|MSG>',       # delimiter
	  		b'baddad42',        # HMAC signature
			b'{header}',        # serialized header dict
			b'{parent_header}', # serialized parent header dict
			b'{metadata}',      # serialized metadata dict
			b'{content}',       # serialized content dict
			b'blob',            # extra raw data buffer(s)
	  		...
		]
	*/
	// Determine where the delimiter is
	for i, el = range wireMessage {
		if string(el) == DELIMITER {
			break // Found our delimiter
		}
	}

	if i >= len(wireMessage) {
		return errors.New("Couldn't find delimeter")
	}

	// Extract the zmq identiti(es)
	//identities := wireMessage[:delimiterLocation]

	// If the message was signed
	if len(connInfo.Key) != 0 {
		var hasher func() hash.Hash

		if connInfo.SignatureScheme == "hmac-sha256" {
			hasher = sha256.New
		} else {
			return errors.New("juno only supports hmac-sha256 for signature scheme currently")
		}

		mac := hmac.New(hasher, []byte(connInfo.Key))
		for _, msgpart := range wireMessage[i+2 : i+6] {
			mac.Write(msgpart)
		}
		signature := make([]byte, hex.DecodedLen(len(wireMessage[i+1])))
		hex.Decode(signature, wireMessage[i+1])
		if !hmac.Equal(mac.Sum(nil), signature) {
			return errors.New("Invalid signature")
		}
	}

	json.Unmarshal(wireMessage[i+2], &m.Header)
	json.Unmarshal(wireMessage[i+3], &m.ParentHeader)
	json.Unmarshal(wireMessage[i+4], &m.Metadata)
	json.Unmarshal(wireMessage[i+5], &m.Content)

	return nil
}

// NewConnectionInfo reads in a connection file and creates a ConnectionInfo
// struct
func NewConnectionInfo(filename string) (ConnectionInfo, error) {
	var connInfo ConnectionInfo
	connFile, err := os.Open(filename)

	if err != nil {
		return connInfo, fmt.Errorf("Couldn't open connection file: %v", err)
	}
	defer connFile.Close()

	jsonParser := json.NewDecoder(connFile)

	if err = jsonParser.Decode(&connInfo); err != nil {
		return connInfo, fmt.Errorf("Couldn't parse connection file: %v", err)
	}

	return connInfo, nil
}

// OpenConnectionFile wraps NewConnectionInfo for backwards compatiblity
func OpenConnectionFile(filename string) (ConnectionInfo, error) {
	return NewConnectionInfo(filename)
}

// JupyterSocket is a zmq.Socket coupled with connection information
type JupyterSocket struct {
	ZMQSocket *zmq.Sock
	ConnInfo  ConnectionInfo
}

// ReadMessage reads a Jupyter Protocol Message
func (s *JupyterSocket) ReadMessage() (Message, error) {
	var message Message
	wireMessage, err := s.ZMQSocket.RecvMessage()
	if err != nil {
		return message, fmt.Errorf("Error on receive: %v", err)
	}

	message, err = s.NewMessage(wireMessage)
	if err != nil {
		return message, fmt.Errorf("Error on parsing wire message: %v", err)
	}
	return message, nil
}

// NewMessage creates a new message from a wire message using the key from this
// socket's connection info
func (s *JupyterSocket) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	message.ParseWireProtocol(wireMessage, s.ConnInfo)
	return message, nil
}

// Destroy obliterates zmq sockets
func (s *JupyterSocket) Destroy() {
	s.ZMQSocket.Destroy()
}

// NewIOPubSocket creates a new IOPub socket (on SUB) with the connInfo given
// subscribe is a comma delimited list of topics to subscribe to
func NewIOPubSocket(connInfo ConnectionInfo, subscribe string) (*JupyterSocket, error) {
	connectionString := connInfo.IOPubConnectionString()

	rawIOPubSocket, err := zmq.NewSub(connectionString, subscribe)
	if err != nil {
		return nil, err
	}

	iopub := &JupyterSocket{
		ZMQSocket: rawIOPubSocket,
		ConnInfo:  connInfo,
	}

	return iopub, nil
}

// ConnectionString forms the string for zmq libraries to connect
func (connInfo *ConnectionInfo) ConnectionString(port int) string {
	connectionString := fmt.Sprintf("%s://%s:%d",
		connInfo.Transport,
		connInfo.IP,
		port)
	return connectionString
}

// IOPubConnectionString forms the connection string for the IOPub socket
func (connInfo *ConnectionInfo) IOPubConnectionString() string {
	return connInfo.ConnectionString(connInfo.IOPubPort)
}

// NewMessage creates a new message based only on the connection info
func (connInfo *ConnectionInfo) NewMessage(wireMessage [][]byte) (Message, error) {
	var message Message
	err := message.ParseWireProtocol(wireMessage, *connInfo)
	return message, err
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
	size  int
}

type editorConfig struct {
	cx          int
	cy          int
	rowoff      int
	coloff      int
	screenRows  int
	screenCols  int
	numRows     int
	rows        []erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** row operations ***/

func editorAppendRow(s []byte) {
	var r erow
	r.chars = s
	r.size = len(s)
	E.rows = append(E.rows, r)
	E.numRows++
}

/*** file I/O ***/

func editorOpen(filename string) {
	fd, err := os.Open(filename)
	if err != nil {
		die(err)
	}
	defer fd.Close()
	fp := bufio.NewReader(fd)

	for line, err := fp.ReadBytes('\n'); err == nil; line, err = fp.ReadBytes('\n') {
		// Trim trailing newlines and carriage returns
		for c := line[len(line) - 1]; len(line) > 0 && (c == '\n' || c == '\r'); {
			line = line[:len(line)-1]
			if len(line) > 0 {
				c = line[len(line) - 1]
			}
		}
		editorAppendRow(line)
	}

	if err != nil && err != io.EOF {
		die(err)
	}
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.numRows > 0 && E.cx < E.rows[E.cy].size {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy < E.numRows {
			E.cy++
		}
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorScroll() {
	if E.cy < E.rowoff {
		E.rowoff = E.cy
	}
	if E.cy >= E.rowoff + E.screenRows {
		E.rowoff = E.cy - E.screenRows + 1
	}
	if E.cx < E.coloff {
		E.coloff = E.cx
	}
	if E.cx >= E.coloff + E.screenCols {
		E.coloff = E.cx - E.screenCols + 1
	}
}

func editorRefreshScreen() {
	editorScroll()
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", (E.cy - E.rowoff) + 1, (E.cx - E.coloff) + 1))
	ab.abAppend("\x1b[25h")
	_, e := io.WriteString(os.Stdout, ab.String())
	if e != nil {
		log.Fatal(e)
	}
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows; y++ {
		filerow := y + E.rowoff
		if filerow >= E.numRows {
			if E.numRows == 0 && y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			len := E.rows[filerow].size - E.coloff
			if len < 0 { len = 0 }
			if len > E.screenCols { len = E.screenCols }
			ab.abAppendBytes(E.rows[filerow].chars[E.coloff:E.coloff+len])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	// Initialization a la C not necessary.
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	if len(os.Args) > 1 {
		editorOpen(os.Args[1])
	}

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 77<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
	size  int
}

type editorConfig struct {
	cx          int
	cy          int
	rowoff      int
	coloff      int
	screenRows  int
	screenCols  int
	numRows     int
	rows        []erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** row operations ***/

func editorAppendRow(s []byte) {
	var r erow
	r.chars = s
	r.size = len(s)
	E.rows = append(E.rows, r)
	E.numRows++
}

/*** file I/O ***/

func editorOpen(filename string) {
	fd, err := os.Open(filename)
	if err != nil {
		die(err)
	}
	defer fd.Close()
	fp := bufio.NewReader(fd)

	for line, err := fp.ReadBytes('\n'); err == nil; line, err = fp.ReadBytes('\n') {
		// Trim trailing newlines and carriage returns
		for c := line[len(line) - 1]; len(line) > 0 && (c == '\n' || c == '\r'); {
			line = line[:len(line)-1]
			if len(line) > 0 {
				c = line[len(line) - 1]
			}
		}
		editorAppendRow(line)
	}

	if err != nil && err != io.EOF {
		die(err)
	}
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.cy < E.numRows && E.cx < E.rows[E.cy].size {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy < E.numRows {
			E.cy++
		}
	}

	rowlen := 0
	if E.cy < E.numRows {
		rowlen = E.rows[E.cy].size
	}
	if E.cx > rowlen {
		E.cx = rowlen
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorScroll() {
	if E.cy < E.rowoff {
		E.rowoff = E.cy
	}
	if E.cy >= E.rowoff + E.screenRows {
		E.rowoff = E.cy - E.screenRows + 1
	}
	if E.cx < E.coloff {
		E.coloff = E.cx
	}
	if E.cx >= E.coloff + E.screenCols {
		E.coloff = E.cx - E.screenCols + 1
	}
}

func editorRefreshScreen() {
	editorScroll()
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", (E.cy - E.rowoff) + 1, (E.cx - E.coloff) + 1))
	ab.abAppend("\x1b[25h")
	_, e := io.WriteString(os.Stdout, ab.String())
	if e != nil {
		log.Fatal(e)
	}
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows; y++ {
		filerow := y + E.rowoff
		if filerow >= E.numRows {
			if E.numRows == 0 && y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			len := E.rows[filerow].size - E.coloff
			if len < 0 { len = 0 }
			if len > E.screenCols { len = E.screenCols }
			ab.abAppendBytes(E.rows[filerow].chars[E.coloff:E.coloff+len])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	// Initialization a la C not necessary.
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	if len(os.Args) > 1 {
		editorOpen(os.Args[1])
	}

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>


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

import (
	"crypto/tls"
	"fmt"
	"kite/dnode/rpc"
	"kite/kitekey"
	"kite/protocol"
	"kite/systeminfo"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/nu7hatch/gouuid"
	"github.com/op/go-logging"
)

func init() {
	// Debugging helper: Prints stacktrace on SIGUSR1.
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGUSR1)
	go func() {
		for {
			s := <-c
			fmt.Println("Got signal:", s)
			buf := make([]byte, 1<<16)
			runtime.Stack(buf, true)
			fmt.Println(string(buf))
			fmt.Print("Number of goroutines:", runtime.NumGoroutine())
			m := new(runtime.MemStats)
			runtime.GC()
			runtime.ReadMemStats(m)
			fmt.Printf(", Memory allocated: %+v\n", m.Alloc)
		}
	}()
}

// 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 Start or Run method.
type Kite struct {
	protocol.Kite

	// Is this Kite Public or Private? Default is Private.
	Visibility protocol.Visibility

	// Points to the Kontrol instance if enabled
	Kontrol *Kontrol

	// Parsed JWT token from ~/.kite/kite.key
	kiteKey *jwt.Token

	// Wheter we want to connect to Kontrol on startup, true by default.
	KontrolEnabled bool

	// Wheter we want to register our Kite to Kontrol, true by default.
	RegisterToKontrol bool

	// Use Koding.com's reverse-proxy server for incoming connections.
	// Instead of the Kite's address, address of the Proxy Kite will be
	// registered to Kontrol.
	proxyEnabled bool

	// will be used in query to kontrol for finding proxy kite
	proxyUsername string

	// method map for exported methods
	handlers map[string]HandlerFunc

	// Should handlers run concurrently? Default is true.
	concurrent bool

	// Dnode rpc server
	server *rpc.Server

	listener net.Listener

	// Handlers to call when a Kite opens a connection to this Kite.
	onConnectHandlers []func(*RemoteKite)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*RemoteKite)

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

	// Should kite disable authenticators for incoming requests? Disabled by default
	disableAuthenticate bool

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Trusted root certificates for TLS connections (wss://).
	// Certificate data must be PEM encoded.
	tlsCertificates []string

	// To signal when kite is ready to accept connections
	readyC chan bool

	// To signal when kite is closed with Close()
	closeC chan bool

	// Prints logging messages to stderr and syslog.
	Log *logging.Logger
}

// New creates, initialize and then returns a new Kite instance. It accepts
// a single options argument that is a config struct that needs to be filled
// with several informations like Name, Port, IP and so on.
func New(options *Options) *Kite {
	var err error

	if options == nil {
		options, err = ReadKiteOptions("manifest.json")
		if err != nil {
			log.Fatal("error: could not read config file", err)
		}
	}

	options.validate() // exits if validating fails

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(err)
	}

	k := &Kite{
		Kite: protocol.Kite{
			Name:        options.Kitename,
			ID:          kiteID.String(),
			Version:     options.Version,
			Hostname:    hostname,
			Environment: options.Environment,
			Region:      options.Region,
			Visibility:  options.Visibility,
			URL: protocol.KiteURL{
				&url.URL{
					Scheme: "ws",
					Host:   net.JoinHostPort(options.PublicIP, options.Port),
					Path:   options.Path,
				},
			},
		},
		server:              rpc.NewServer(),
		concurrent:          true,
		KontrolEnabled:      true,
		RegisterToKontrol:   true,
		trustedKontrolKeys:  make(map[string]string),
		Authenticators:      make(map[string]func(*Request) error),
		disableAuthenticate: options.DisableAuthentication,
		handlers:            make(map[string]HandlerFunc),
		readyC:              make(chan bool),
		closeC:              make(chan bool),
	}

	k.Log = newLogger(k.Name)

	k.kiteKey, err = kitekey.Parse()
	if err != nil {
		k.Log.Warning("Cannot read kite key. You must register by running \"kite register\" command.")
	} else if !k.kiteKey.Valid {
		panic(err)
	} else {
		k.Username = k.kiteKey.Claims["sub"].(string)

		if k.KontrolEnabled {
			parsedURL, err := url.Parse(k.kiteKey.Claims["kontrolURL"].(string))
			if err != nil {
				panic(err)
			}

			k.Kontrol = k.NewKontrol(parsedURL)

			k.TrustKontrolKey(k.kiteKey.Claims["iss"].(string), k.kiteKey.Claims["kontrolKey"].(string))
		}
	}

	k.server.SetWrappers(wrapMethodArgs, wrapCallbackArgs, runMethod, runCallback, onError)
	k.server.Properties()["localKite"] = k

	k.server.OnConnect(func(c *rpc.Client) {
		k.Log.Info("New connection from: %s", c.Conn.Request().RemoteAddr)
	})

	// Call registered handlers when a client has disconnected.
	k.server.OnDisconnect(func(c *rpc.Client) {
		if r, ok := c.Properties()["remoteKite"]; ok {
			// Run OnDisconnect handlers.
			k.notifyRemoteKiteDisconnected(r.(*RemoteKite))
		}
	})

	// Every kite should be able to authenticate the user from token.
	k.Authenticators["token"] = k.AuthenticateFromToken
	// A kite accepts requests from Kontrol.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register our internal methods
	k.HandleFunc("systemInfo", func(r *Request) (interface{}, error) { return systeminfo.New() })
	k.HandleFunc("heartbeat", k.handleHeartbeat)
	k.HandleFunc("log", k.handleLog)

	return k
}

// Normally, each incoming request is processed in a new goroutine.
// If you disable concurrency, requests will be processed synchronously.
func (k *Kite) DisableConcurrency() {
	k.server.SetConcurrent(false)
}

// EnableTLS enables "wss://" protocol".
// It uses the same port and disables "ws://".
func (k *Kite) EnableTLS(certFile, keyFile string) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		k.Log.Fatal(err.Error())
	}

	k.server.TlsConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	k.Kite.URL.Scheme = "wss"
}

// Put this kite behind a reverse-proxy. Useful under firewall or NAT.
func (k *Kite) EnableProxy(username string) {
	k.proxyEnabled = true
	k.proxyUsername = username
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

// Add new trusted root certificate for TLS.
func (k *Kite) AddRootCertificate(cert string) {
	k.tlsCertificates = append(k.tlsCertificates, cert)
}

func (k *Kite) CloseNotify() chan bool {
	return k.closeC
}

func (k *Kite) ReadyNotify() chan bool {
	return k.readyC
}

// Run is a blocking method. It runs the kite server and then accepts requests
// asynchronously.
func (k *Kite) Run() {
	if os.Getenv("KITE_VERSION") != "" {
		fmt.Println(k.Version)
		os.Exit(0)
	}

	if err := k.listenAndServe(); err != nil {
		k.Log.Fatal(err)
	}
}

// Start is like Run(), but does not wait for it to complete. It's nonblocking.
func (k *Kite) Start() {
	go k.Run()
	<-k.readyC // wait until we are ready
}

// Close stops the server.
func (k *Kite) Close() {
	k.Log.Notice("Closing server...")
	k.listener.Close()
}

func (k *Kite) handleHeartbeat(r *Request) (interface{}, error) {
	args := r.Args.MustSliceOfLength(2)
	seconds := args[0].MustFloat64()
	ping := args[1].MustFunction()

	go func() {
		for {
			time.Sleep(time.Duration(seconds) * time.Second)
			if ping() != nil {
				return
			}
		}
	}()

	return nil, nil
}

// handleLog prints a log message to stdout.
func (k *Kite) handleLog(r *Request) (interface{}, error) {
	msg := r.Args.One().MustString()
	k.Log.Info(fmt.Sprintf("%s: %s", r.RemoteKite.Name, msg))
	return nil, nil
}

func init() {
	// These logging related stuff needs to be called once because stupid
	// logging library uses global variables and resets the backends every time.
	logging.SetFormatter(logging.MustStringFormatter("%{level:-8s} ▶ %{message}"))
	stderrBackend := logging.NewLogBackend(os.Stderr, "", log.LstdFlags)
	stderrBackend.Color = true
	syslogBackend, _ := logging.NewSyslogBackend("")
	logging.SetBackend(stderrBackend, syslogBackend)
}

// newLogger returns a new logger object for desired name and level.
func newLogger(name string) *logging.Logger {
	logger := logging.MustGetLogger(name)

	var level logging.Level
	switch strings.ToUpper(os.Getenv("KITE_LOG_LEVEL")) {
	case "DEBUG":
		level = logging.DEBUG
	case "INFO":
		level = logging.INFO
	case "NOTICE":
		level = logging.NOTICE
	case "WARNING":
		level = logging.WARNING
	case "ERROR":
		level = logging.ERROR
	case "CRITICAL":
		level = logging.CRITICAL
	default:
		level = logging.INFO
	}

	logging.SetLevel(level, name)
	return logger
}

// listenAndServe starts our rpc server with the given addr.
func (k *Kite) listenAndServe() error {
	var err error

	k.listener, err = net.Listen("tcp4", k.Kite.URL.Host)
	if err != nil {
		return err
	}

	k.Log.Notice("Listening: %s", k.listener.Addr().String())

	// Enable TLS
	if k.server.TlsConfig != nil {
		k.listener = tls.NewListener(k.listener, k.server.TlsConfig)
	}

	// Port is known here if "0" is used as port number
	host, _, _ := net.SplitHostPort(k.Kite.URL.Host)
	_, port, _ := net.SplitHostPort(k.listener.Addr().String())
	k.Kite.URL.Host = net.JoinHostPort(host, port)

	// Kontrol will register to the URLs sent to this channel.
	registerURLs := make(chan *url.URL, 1)

	if k.proxyEnabled {
		// Register to Proxy Kite and stay connected.
		// Fill the channel with registered Proxy URLs.
		go k.keepRegisteredToProxyKite(registerURLs)
	} else {
		// If proxy is not enabled, we must populate the channel ourselves.
		registerURLs <- k.URL.URL // Register with Kite's own URL.
	}

	// We must connect to Kontrol after starting to listen on port
	if k.KontrolEnabled && k.Kontrol != nil {
		if err = k.Kontrol.DialForever(); err != nil {
			k.Log.Critical(err.Error())
		}

		if k.RegisterToKontrol {
			go k.keepRegisteredToKontrol(registerURLs)
		}
	}

	k.Log.Notice("Serving on: %s", k.URL.URL.String())

	close(k.readyC) // listener is ready, signal waiters.

	// An error string equivalent to net.errClosing for using with http.Serve()
	// during a graceful exit. Needed to declare here again because it is not
	// exported by "net" package.
	const errClosing = "use of closed network connection"

	err = http.Serve(k.listener, k.server)
	if strings.Contains(err.Error(), errClosing) {
		// The server is closed by Close() method
		k.Log.Notice("Kite server is closed.")
		close(k.closeC)
		err = nil
	}

	return err
}

// OnConnect registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnConnect(handler func(*RemoteKite)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*RemoteKite)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

// notifyRemoteKiteConnected runs the registered handlers with OnConnect().
func (k *Kite) notifyRemoteKiteConnected(r *RemoteKite) {
	k.Log.Info("Client '%s' is identified as '%s'",
		r.client.Conn.Request().RemoteAddr, r.Name)

	for _, handler := range k.onConnectHandlers {
		go handler(r)
	}
}

func (k *Kite) notifyRemoteKiteDisconnected(r *RemoteKite) {
	k.Log.Info("Client has disconnected: %s", r.Name)

	for _, handler := range k.onDisconnectHandlers {
		go handler(r)
	}
}
<commit_msg>add Kite.AddRootCertificateFile() method<commit_after>// Package kite is a library for creating small micro-services.
// Two main types implemented by this package are
// Kite for creating a micro-service server called "Kite" and
// RemoteKite for communicating with another kites.
package kite

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"kite/dnode/rpc"
	"kite/kitekey"
	"kite/protocol"
	"kite/systeminfo"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/nu7hatch/gouuid"
	"github.com/op/go-logging"
)

func init() {
	// Debugging helper: Prints stacktrace on SIGUSR1.
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGUSR1)
	go func() {
		for {
			s := <-c
			fmt.Println("Got signal:", s)
			buf := make([]byte, 1<<16)
			runtime.Stack(buf, true)
			fmt.Println(string(buf))
			fmt.Print("Number of goroutines:", runtime.NumGoroutine())
			m := new(runtime.MemStats)
			runtime.GC()
			runtime.ReadMemStats(m)
			fmt.Printf(", Memory allocated: %+v\n", m.Alloc)
		}
	}()
}

// 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 Start or Run method.
type Kite struct {
	protocol.Kite

	// Is this Kite Public or Private? Default is Private.
	Visibility protocol.Visibility

	// Points to the Kontrol instance if enabled
	Kontrol *Kontrol

	// Parsed JWT token from ~/.kite/kite.key
	kiteKey *jwt.Token

	// Wheter we want to connect to Kontrol on startup, true by default.
	KontrolEnabled bool

	// Wheter we want to register our Kite to Kontrol, true by default.
	RegisterToKontrol bool

	// Use Koding.com's reverse-proxy server for incoming connections.
	// Instead of the Kite's address, address of the Proxy Kite will be
	// registered to Kontrol.
	proxyEnabled bool

	// will be used in query to kontrol for finding proxy kite
	proxyUsername string

	// method map for exported methods
	handlers map[string]HandlerFunc

	// Should handlers run concurrently? Default is true.
	concurrent bool

	// Dnode rpc server
	server *rpc.Server

	listener net.Listener

	// Handlers to call when a Kite opens a connection to this Kite.
	onConnectHandlers []func(*RemoteKite)

	// Handlers to call when a client has disconnected.
	onDisconnectHandlers []func(*RemoteKite)

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

	// Should kite disable authenticators for incoming requests? Disabled by default
	disableAuthenticate bool

	// Kontrol keys to trust. Kontrol will issue access tokens for kites
	// that are signed with the private counterpart of these keys.
	// Key data must be PEM encoded.
	trustedKontrolKeys map[string]string

	// Trusted root certificates for TLS connections (wss://).
	// Certificate data must be PEM encoded.
	tlsCertificates []string

	// To signal when kite is ready to accept connections
	readyC chan bool

	// To signal when kite is closed with Close()
	closeC chan bool

	// Prints logging messages to stderr and syslog.
	Log *logging.Logger
}

// New creates, initialize and then returns a new Kite instance. It accepts
// a single options argument that is a config struct that needs to be filled
// with several informations like Name, Port, IP and so on.
func New(options *Options) *Kite {
	var err error

	if options == nil {
		options, err = ReadKiteOptions("manifest.json")
		if err != nil {
			log.Fatal("error: could not read config file", err)
		}
	}

	options.validate() // exits if validating fails

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	kiteID, err := uuid.NewV4()
	if err != nil {
		panic(err)
	}

	k := &Kite{
		Kite: protocol.Kite{
			Name:        options.Kitename,
			ID:          kiteID.String(),
			Version:     options.Version,
			Hostname:    hostname,
			Environment: options.Environment,
			Region:      options.Region,
			Visibility:  options.Visibility,
			URL: protocol.KiteURL{
				&url.URL{
					Scheme: "ws",
					Host:   net.JoinHostPort(options.PublicIP, options.Port),
					Path:   options.Path,
				},
			},
		},
		server:              rpc.NewServer(),
		concurrent:          true,
		KontrolEnabled:      true,
		RegisterToKontrol:   true,
		trustedKontrolKeys:  make(map[string]string),
		Authenticators:      make(map[string]func(*Request) error),
		disableAuthenticate: options.DisableAuthentication,
		handlers:            make(map[string]HandlerFunc),
		readyC:              make(chan bool),
		closeC:              make(chan bool),
	}

	k.Log = newLogger(k.Name)

	k.kiteKey, err = kitekey.Parse()
	if err != nil {
		k.Log.Warning("Cannot read kite key. You must register by running \"kite register\" command.")
	} else if !k.kiteKey.Valid {
		panic(err)
	} else {
		k.Username = k.kiteKey.Claims["sub"].(string)

		if k.KontrolEnabled {
			parsedURL, err := url.Parse(k.kiteKey.Claims["kontrolURL"].(string))
			if err != nil {
				panic(err)
			}

			k.Kontrol = k.NewKontrol(parsedURL)

			k.TrustKontrolKey(k.kiteKey.Claims["iss"].(string), k.kiteKey.Claims["kontrolKey"].(string))
		}
	}

	k.server.SetWrappers(wrapMethodArgs, wrapCallbackArgs, runMethod, runCallback, onError)
	k.server.Properties()["localKite"] = k

	k.server.OnConnect(func(c *rpc.Client) {
		k.Log.Info("New connection from: %s", c.Conn.Request().RemoteAddr)
	})

	// Call registered handlers when a client has disconnected.
	k.server.OnDisconnect(func(c *rpc.Client) {
		if r, ok := c.Properties()["remoteKite"]; ok {
			// Run OnDisconnect handlers.
			k.notifyRemoteKiteDisconnected(r.(*RemoteKite))
		}
	})

	// Every kite should be able to authenticate the user from token.
	k.Authenticators["token"] = k.AuthenticateFromToken
	// A kite accepts requests from Kontrol.
	k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey

	// Register our internal methods
	k.HandleFunc("systemInfo", func(r *Request) (interface{}, error) { return systeminfo.New() })
	k.HandleFunc("heartbeat", k.handleHeartbeat)
	k.HandleFunc("log", k.handleLog)

	return k
}

// Normally, each incoming request is processed in a new goroutine.
// If you disable concurrency, requests will be processed synchronously.
func (k *Kite) DisableConcurrency() {
	k.server.SetConcurrent(false)
}

// EnableTLS enables "wss://" protocol".
// It uses the same port and disables "ws://".
func (k *Kite) EnableTLS(certFile, keyFile string) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		k.Log.Fatal(err.Error())
	}

	k.server.TlsConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	k.Kite.URL.Scheme = "wss"
}

// Put this kite behind a reverse-proxy. Useful under firewall or NAT.
func (k *Kite) EnableProxy(username string) {
	k.proxyEnabled = true
	k.proxyUsername = username
}

// Trust a Kontrol key for validating tokens.
func (k *Kite) TrustKontrolKey(issuer, key string) {
	k.trustedKontrolKeys[issuer] = key
}

// Add new trusted root certificate for TLS from a PEM block.
func (k *Kite) AddRootCertificate(cert string) {
	k.tlsCertificates = append(k.tlsCertificates, cert)
}

// Add new trusted root certificate for TLS from a file name.
func (k *Kite) AddRootCertificateFile(certFile string) {
	data, err := ioutil.ReadFile(certFile)
	if err != nil {
		k.Log.Fatalf("Cannot add certificate: %s", err.Error())
	}
	k.tlsCertificates = append(k.tlsCertificates, string(data))
}

func (k *Kite) CloseNotify() chan bool {
	return k.closeC
}

func (k *Kite) ReadyNotify() chan bool {
	return k.readyC
}

// Run is a blocking method. It runs the kite server and then accepts requests
// asynchronously.
func (k *Kite) Run() {
	if os.Getenv("KITE_VERSION") != "" {
		fmt.Println(k.Version)
		os.Exit(0)
	}

	if err := k.listenAndServe(); err != nil {
		k.Log.Fatal(err)
	}
}

// Start is like Run(), but does not wait for it to complete. It's nonblocking.
func (k *Kite) Start() {
	go k.Run()
	<-k.readyC // wait until we are ready
}

// Close stops the server.
func (k *Kite) Close() {
	k.Log.Notice("Closing server...")
	k.listener.Close()
}

func (k *Kite) handleHeartbeat(r *Request) (interface{}, error) {
	args := r.Args.MustSliceOfLength(2)
	seconds := args[0].MustFloat64()
	ping := args[1].MustFunction()

	go func() {
		for {
			time.Sleep(time.Duration(seconds) * time.Second)
			if ping() != nil {
				return
			}
		}
	}()

	return nil, nil
}

// handleLog prints a log message to stdout.
func (k *Kite) handleLog(r *Request) (interface{}, error) {
	msg := r.Args.One().MustString()
	k.Log.Info(fmt.Sprintf("%s: %s", r.RemoteKite.Name, msg))
	return nil, nil
}

func init() {
	// These logging related stuff needs to be called once because stupid
	// logging library uses global variables and resets the backends every time.
	logging.SetFormatter(logging.MustStringFormatter("%{level:-8s} ▶ %{message}"))
	stderrBackend := logging.NewLogBackend(os.Stderr, "", log.LstdFlags)
	stderrBackend.Color = true
	syslogBackend, _ := logging.NewSyslogBackend("")
	logging.SetBackend(stderrBackend, syslogBackend)
}

// newLogger returns a new logger object for desired name and level.
func newLogger(name string) *logging.Logger {
	logger := logging.MustGetLogger(name)

	var level logging.Level
	switch strings.ToUpper(os.Getenv("KITE_LOG_LEVEL")) {
	case "DEBUG":
		level = logging.DEBUG
	case "INFO":
		level = logging.INFO
	case "NOTICE":
		level = logging.NOTICE
	case "WARNING":
		level = logging.WARNING
	case "ERROR":
		level = logging.ERROR
	case "CRITICAL":
		level = logging.CRITICAL
	default:
		level = logging.INFO
	}

	logging.SetLevel(level, name)
	return logger
}

// listenAndServe starts our rpc server with the given addr.
func (k *Kite) listenAndServe() error {
	var err error

	k.listener, err = net.Listen("tcp4", k.Kite.URL.Host)
	if err != nil {
		return err
	}

	k.Log.Notice("Listening: %s", k.listener.Addr().String())

	// Enable TLS
	if k.server.TlsConfig != nil {
		k.listener = tls.NewListener(k.listener, k.server.TlsConfig)
	}

	// Port is known here if "0" is used as port number
	host, _, _ := net.SplitHostPort(k.Kite.URL.Host)
	_, port, _ := net.SplitHostPort(k.listener.Addr().String())
	k.Kite.URL.Host = net.JoinHostPort(host, port)

	// Kontrol will register to the URLs sent to this channel.
	registerURLs := make(chan *url.URL, 1)

	if k.proxyEnabled {
		// Register to Proxy Kite and stay connected.
		// Fill the channel with registered Proxy URLs.
		go k.keepRegisteredToProxyKite(registerURLs)
	} else {
		// If proxy is not enabled, we must populate the channel ourselves.
		registerURLs <- k.URL.URL // Register with Kite's own URL.
	}

	// We must connect to Kontrol after starting to listen on port
	if k.KontrolEnabled && k.Kontrol != nil {
		if err = k.Kontrol.DialForever(); err != nil {
			k.Log.Critical(err.Error())
		}

		if k.RegisterToKontrol {
			go k.keepRegisteredToKontrol(registerURLs)
		}
	}

	k.Log.Notice("Serving on: %s", k.URL.URL.String())

	close(k.readyC) // listener is ready, signal waiters.

	// An error string equivalent to net.errClosing for using with http.Serve()
	// during a graceful exit. Needed to declare here again because it is not
	// exported by "net" package.
	const errClosing = "use of closed network connection"

	err = http.Serve(k.listener, k.server)
	if strings.Contains(err.Error(), errClosing) {
		// The server is closed by Close() method
		k.Log.Notice("Kite server is closed.")
		close(k.closeC)
		err = nil
	}

	return err
}

// OnConnect registers a function to run when a Kite connects to this Kite.
func (k *Kite) OnConnect(handler func(*RemoteKite)) {
	k.onConnectHandlers = append(k.onConnectHandlers, handler)
}

// OnDisconnect registers a function to run when a connected Kite is disconnected.
func (k *Kite) OnDisconnect(handler func(*RemoteKite)) {
	k.onDisconnectHandlers = append(k.onDisconnectHandlers, handler)
}

// notifyRemoteKiteConnected runs the registered handlers with OnConnect().
func (k *Kite) notifyRemoteKiteConnected(r *RemoteKite) {
	k.Log.Info("Client '%s' is identified as '%s'",
		r.client.Conn.Request().RemoteAddr, r.Name)

	for _, handler := range k.onConnectHandlers {
		go handler(r)
	}
}

func (k *Kite) notifyRemoteKiteDisconnected(r *RemoteKite) {
	k.Log.Info("Client has disconnected: %s", r.Name)

	for _, handler := range k.onDisconnectHandlers {
		go handler(r)
	}
}
<|endoftext|>


<commit_before>// beelog project klog
package klog

import (
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/aybabtme/color"
)

type Level int

const (
	Fshortfile = 1 << iota // show filename:lineno
	Fdate
	Ftime
	Fcolor

	Fdatetime = Fdate | Ftime
	Fdevflag  = Fdatetime | Fshortfile | Fcolor // for develop use
	Fstdflag  = Fdatetime | Fcolor
)

const (
	LDebug Level = iota
	LInfo
	LWarning
	LError
	LFatal
)

var (
	DevLog = NewLogger(os.Stdout, "").SetFlags(Fdevflag).SetLevel(LDebug)
	StdLog = NewLogger(os.Stdout, "").SetFlags(Fstdflag).SetLevel(LInfo)
)

var levels = []string{
	"[DEBUG]",
	"[INFO.]",
	"[WARN.]",
	"[ERROR]",
	"[FATAL]",
}

var colors = []color.Paint{
	color.CyanPaint,
	color.GreenPaint,
	color.YellowPaint,
	color.RedPaint,
	color.PurplePaint,
}

type Logger struct {
	out         io.Writer
	level       Level
	logging     *log.Logger
	flags       int
	prefix      string
	colorEnable bool
}

func NewFileLogger(filename string) (log *Logger, err error) {
	fd, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
	if err != nil {
		return
	}
	return NewLogger(fd), nil
}

// default level is debug
func NewLogger(out io.Writer, prefix ...string) *Logger {
	if out == nil {
		out = os.Stdout
	}
	return &Logger{
		level:       LInfo,
		logging:     log.New(out, "", 0),
		colorEnable: runtime.GOOS != "windows" && isTermOutput(),
		flags:       Fstdflag,
		prefix:      strings.Join(prefix, " "),
	}
}

// set flags to change klog output style
func (l *Logger) SetFlags(flag int) *Logger {
	l.flags = flag
	return l
}

// get logger flags
func (l *Logger) Flags() int {
	return l.flags
}

// set output level. L[Debug|Warning...]
func (l *Logger) SetLevel(level Level) *Logger {
	l.level = level
	return l
}

// get current level.
func (l *Logger) Level() Level {
	return l.level
}

func (l *Logger) write(level Level, format string, a ...interface{}) {
	if level < l.level {
		return
	}
	var levelName string = levels[int(level)]
	var sep = " "
	var prefix, outstr = l.prefix, ""

	if l.flags&Fdatetime != 0 {
		now := time.Now()
		layout := ""
		if l.flags&Fdate != 0 {
			layout += "2006/01/02"
		}
		if l.flags&Ftime != 0 {
			layout += " 15:04:05"
		}
		layout = strings.TrimSpace(layout)
		prefix += now.Format(layout)
	}

	if l.flags&Fshortfile != 0 {
		// Retrieve the stack infos
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "<unknown>"
			line = -1
		} else {
			file = file[strings.LastIndex(file, "/")+1:]
		}
		//outstr = fmt.Sprintf("%s %s:%d", outstr, file, line)
		prefix = fmt.Sprintf("%s %s:%d", prefix, file, line)
	}

	outstr += levelName

	if format == "" {
		outstr = outstr + sep + fmt.Sprint(a...)
	} else {
		outstr = outstr + sep + fmt.Sprintf(format, a...)
	}
	outstr = strings.TrimSuffix(outstr, "\n")

	if l.colorEnable && l.flags&Fcolor != 0 {
		brush := color.NewBrush("", colors[int(level)])
		outstr = brush(outstr)
	}

	l.logging.Print(prefix + sep + outstr)
}

func (l *Logger) Debug(v ...interface{}) {
	l.write(LDebug, "", v...)
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	l.write(LDebug, format, v...)
}

func (l *Logger) Info(v ...interface{}) {
	l.write(LInfo, "", v...)
}
func (l *Logger) Infof(format string, v ...interface{}) {
	l.write(LInfo, format, v...)
}
func (l *Logger) Warn(v ...interface{}) {
	l.write(LWarning, "", v...)
}
func (l *Logger) Warnf(format string, v ...interface{}) {
	l.write(LWarning, format, v...)
}
func (l *Logger) Error(v ...interface{}) {
	l.write(LError, "", v...)
}
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.write(LError, format, v...)
}

// will also call os.Exit(1)
func (l *Logger) Fatal(v ...interface{}) {
	l.write(LFatal, "", v...)
	os.Exit(1)
}

// will also call os.Exit(1)
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.write(LFatal, format, v...)
	os.Exit(1)
}
<commit_msg>change file log default level(to Debug and DevFlag)<commit_after>// beelog project klog
package klog

import (
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/aybabtme/color"
)

type Level int

const (
	Fshortfile = 1 << iota // show filename:lineno
	Fdate
	Ftime
	Fcolor

	Fdatetime = Fdate | Ftime
	Fdevflag  = Fdatetime | Fshortfile | Fcolor // for develop use
	Fstdflag  = Fdatetime | Fcolor
)

const (
	LDebug Level = iota
	LInfo
	LWarning
	LError
	LFatal
)

var (
	DevLog = NewLogger(os.Stdout, "").SetFlags(Fdevflag).SetLevel(LDebug)
	StdLog = NewLogger(os.Stdout, "").SetFlags(Fstdflag).SetLevel(LInfo)
)

var levels = []string{
	"[DEBUG]",
	"[INFO.]",
	"[WARN.]",
	"[ERROR]",
	"[FATAL]",
}

var colors = []color.Paint{
	color.CyanPaint,
	color.GreenPaint,
	color.YellowPaint,
	color.RedPaint,
	color.PurplePaint,
}

type Logger struct {
	out         io.Writer
	level       Level
	logging     *log.Logger
	flags       int
	prefix      string
	colorEnable bool
}

// Default LogLevel Debug
func NewFileLogger(filename string) (log *Logger, err error) {
	fd, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
	if err != nil {
		return
	}
	return NewLogger(fd).SetFlags(Fdevflag).SetLevel(LDebug), nil
}

// default level is debug
func NewLogger(out io.Writer, prefix ...string) *Logger {
	if out == nil {
		out = os.Stdout
	}
	return &Logger{
		level:       LInfo,
		logging:     log.New(out, "", 0),
		colorEnable: runtime.GOOS != "windows" && isTermOutput(), // TODO: isTemOutput is not so good
		flags:       Fstdflag,
		prefix:      strings.Join(prefix, " "),
	}
}

// set flags to change klog output style
func (l *Logger) SetFlags(flag int) *Logger {
	l.flags = flag
	return l
}

// get logger flags
func (l *Logger) Flags() int {
	return l.flags
}

// set output level. L[Debug|Warning...]
func (l *Logger) SetLevel(level Level) *Logger {
	l.level = level
	return l
}

// get current level.
func (l *Logger) Level() Level {
	return l.level
}

func (l *Logger) write(level Level, format string, a ...interface{}) {
	if level < l.level {
		return
	}
	var levelName string = levels[int(level)]
	var sep = " "
	var prefix, outstr = l.prefix, ""

	if l.flags&Fdatetime != 0 {
		now := time.Now()
		layout := ""
		if l.flags&Fdate != 0 {
			layout += "2006/01/02"
		}
		if l.flags&Ftime != 0 {
			layout += " 15:04:05"
		}
		layout = strings.TrimSpace(layout)
		prefix += now.Format(layout)
	}

	if l.flags&Fshortfile != 0 {
		// Retrieve the stack infos
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "<unknown>"
			line = -1
		} else {
			file = file[strings.LastIndex(file, "/")+1:]
		}
		//outstr = fmt.Sprintf("%s %s:%d", outstr, file, line)
		prefix = fmt.Sprintf("%s %s:%d", prefix, file, line)
	}

	outstr += levelName

	if format == "" {
		outstr = outstr + sep + fmt.Sprint(a...)
	} else {
		outstr = outstr + sep + fmt.Sprintf(format, a...)
	}
	outstr = strings.TrimSuffix(outstr, "\n")

	if l.colorEnable && l.flags&Fcolor != 0 {
		brush := color.NewBrush("", colors[int(level)])
		outstr = brush(outstr)
	}

	l.logging.Print(prefix + sep + outstr)
}

func (l *Logger) Debug(v ...interface{}) {
	l.write(LDebug, "", v...)
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	l.write(LDebug, format, v...)
}

func (l *Logger) Info(v ...interface{}) {
	l.write(LInfo, "", v...)
}
func (l *Logger) Infof(format string, v ...interface{}) {
	l.write(LInfo, format, v...)
}
func (l *Logger) Warn(v ...interface{}) {
	l.write(LWarning, "", v...)
}
func (l *Logger) Warnf(format string, v ...interface{}) {
	l.write(LWarning, format, v...)
}
func (l *Logger) Error(v ...interface{}) {
	l.write(LError, "", v...)
}
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.write(LError, format, v...)
}

// will also call os.Exit(1)
func (l *Logger) Fatal(v ...interface{}) {
	l.write(LFatal, "", v...)
	os.Exit(1)
}

// will also call os.Exit(1)
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.write(LFatal, format, v...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package yiigo

import (
	"fmt"
	"sync"

	ini "gopkg.in/ini.v1"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// Sequence model for _id auto_increment
type Sequence struct {
	ID  string `bson:"_id"`
	Seq int    `bson:"seq"`
}

var (
	// Mongo default session
	Mongo    *mgo.Session
	mongoMap sync.Map
)

func initMongo() error {
	sections := childSections("mongo")

	if len(sections) > 0 {
		return initMultiMongo(sections)
	}

	return initSingleMongo()
}

func initSingleMongo() error {
	var err error

	section := env.Section("mongo")

	Mongo, err = mongoDial(section)

	if err != nil {
		return fmt.Errorf("mongo error: %s", err.Error())
	}

	return nil
}

func initMultiMongo(sections []*ini.Section) error {
	for _, v := range sections {
		m, err := mongoDial(v)

		if err != nil {
			return fmt.Errorf("mongo error: %s", err.Error())
		}

		mongoMap.Store(v.Name(), m)
	}

	if v, ok := mongoMap.Load("mongo.default"); ok {
		Mongo = v.(*mgo.Session)
	}

	return nil
}

func mongoDial(section *ini.Section) (*mgo.Session, error) {
	host := section.Key("host").MustString("127.0.0.1")
	port := section.Key("port").MustInt(27017)
	username := section.Key("username").MustString("")
	password := section.Key("password").MustString("")

	dsn := fmt.Sprintf("mongodb://%s:%d", host, port)

	if username != "" {
		dsn = fmt.Sprintf("mongodb://%s:%s@%s:%d", username, password, host, port)
	}

	m, err := mgo.Dial(dsn)

	if err != nil {
		return nil, err
	}

	m.SetPoolLimit(EnvInt("mongo", "poolLimit", 10))

	return m, nil
}

// MongoSession get mongo session
func MongoSession(conn ...string) (*mgo.Session, error) {
	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("mongo.%s", c)

	v, ok := mongoMap.Load(schema)

	if !ok {
		return nil, fmt.Errorf("mongodb %s is not connected", schema)
	}

	session := v.(*mgo.Session)

	return session.Clone(), nil
}

// Seq get auto increment id
func Seq(session *mgo.Session, db string, collection string, seqs ...int) (int, error) {
	if len(seqs) == 0 {
		seqs = append(seqs, 1)
	}

	condition := bson.M{"_id": collection}

	change := mgo.Change{
		Update:    bson.M{"$inc": bson.M{"seq": seqs[0]}},
		Upsert:    true,
		ReturnNew: true,
	}

	sequence := Sequence{}

	_, err := session.DB(db).C("sequence").Find(condition).Apply(change, &sequence)

	if err != nil {
		return 0, err
	}

	return sequence.Seq, nil
}
<commit_msg>update mongo<commit_after>package yiigo

import (
	"fmt"
	"sync"

	ini "gopkg.in/ini.v1"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// Sequence model for _id auto_increment
type Sequence struct {
	ID  string `bson:"_id"`
	Seq int    `bson:"seq"`
}

var (
	// Mongo default session
	Mongo    *mgo.Session
	mongoMap sync.Map
)

func initMongo() error {
	sections := childSections("mongo")

	if len(sections) > 0 {
		return initMultiMongo(sections)
	}

	return initSingleMongo()
}

func initSingleMongo() error {
	var err error

	section := env.Section("mongo")

	Mongo, err = mongoDial(section)

	if err != nil {
		return fmt.Errorf("mongo error: %s", err.Error())
	}

	return nil
}

func initMultiMongo(sections []*ini.Section) error {
	for _, v := range sections {
		m, err := mongoDial(v)

		if err != nil {
			return fmt.Errorf("mongo error: %s", err.Error())
		}

		mongoMap.Store(v.Name(), m)
	}

	if v, ok := mongoMap.Load("mongo.default"); ok {
		Mongo = v.(*mgo.Session)
	}

	return nil
}

func mongoDial(section *ini.Section) (*mgo.Session, error) {
	host := section.Key("host").MustString("127.0.0.1")
	port := section.Key("port").MustInt(27017)
	username := section.Key("username").MustString("")
	password := section.Key("password").MustString("")
	poolLimit := section.Key("poolLimit").MustInt(10)

	dsn := fmt.Sprintf("mongodb://%s:%d", host, port)

	if username != "" {
		dsn = fmt.Sprintf("mongodb://%s:%s@%s:%d", username, password, host, port)
	}

	m, err := mgo.Dial(dsn)

	if err != nil {
		return nil, err
	}

	m.SetPoolLimit(poolLimit)

	return m, nil
}

// MongoSession get mongo session
func MongoSession(conn ...string) (*mgo.Session, error) {
	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("mongo.%s", c)

	v, ok := mongoMap.Load(schema)

	if !ok {
		return nil, fmt.Errorf("mongodb %s is not connected", schema)
	}

	session := v.(*mgo.Session)

	return session.Clone(), nil
}

// Seq get auto increment id
func Seq(session *mgo.Session, db string, collection string, seqs ...int) (int, error) {
	if len(seqs) == 0 {
		seqs = append(seqs, 1)
	}

	condition := bson.M{"_id": collection}

	change := mgo.Change{
		Update:    bson.M{"$inc": bson.M{"seq": seqs[0]}},
		Upsert:    true,
		ReturnNew: true,
	}

	sequence := Sequence{}

	_, err := session.DB(db).C("sequence").Find(condition).Apply(change, &sequence)

	if err != nil {
		return 0, err
	}

	return sequence.Seq, nil
}
<|endoftext|>


<commit_before>package swarm

import (
	"network"
	"testing"
	"time"
)

func TestStateSteady(t *testing.T) {
	mult := network.NewNetworkMultiplexer()
	hosts := []string{"A", "B", "C", "D"}
	swarm := "test"
	var swarms []*Blockchain
	hostsseen := make(map[string]int)
	baseblock := &Block{"", swarm, "", nil, nil}
	for i := 0; i < len(hosts); i++ {
		// Create all the blockchains and let them do nothing.
		swarms = append(swarms, NewBlockchain(hosts[i], swarm, nil))
		if state, ok := swarms[i].state.(*StateSwarmInformed); ok {
			// Prevent race hazards
			state.Die(true)
		}
		hostsseen[hosts[i]] = 1
		swarms[i].AddSource(mult)
	}
	for i := 0; i < len(swarms); i++ {
		// Set all blockchains to StateSteady
		// The initial secret string needs to be unique, use host ID
		swarms[i].state = NewStateSteady(swarms[i], baseblock, hostsseen, hosts[i])
	}
	time.Sleep(5 * time.Second)
	// Die swarm, you don't belong in this world
	for _, v := range swarms {
		switch s := v.state.(type) {
		case *StateSteady:
			s.die <- struct{}{}
		default:
			t.Fatal("State unexpectedly changed")
		}
	}
}
<commit_msg>Reduced waiting time of Steady test<commit_after>package swarm

import (
	"network"
	"testing"
	"time"
)

func TestStateSteady(t *testing.T) {
	mult := network.NewNetworkMultiplexer()
	hosts := []string{"A", "B", "C", "D"}
	swarm := "test"
	var swarms []*Blockchain
	hostsseen := make(map[string]int)
	baseblock := &Block{"", swarm, "", nil, nil}
	for i := 0; i < len(hosts); i++ {
		// Create all the blockchains and let them do nothing.
		swarms = append(swarms, NewBlockchain(hosts[i], swarm, nil))
		if state, ok := swarms[i].state.(*StateSwarmInformed); ok {
			// Prevent race hazards
			state.Die(true)
		}
		hostsseen[hosts[i]] = 1
		swarms[i].AddSource(mult)
	}
	for i := 0; i < len(swarms); i++ {
		// Set all blockchains to StateSteady
		// The initial secret string needs to be unique, use host ID
		swarms[i].state = NewStateSteady(swarms[i], baseblock, hostsseen, hosts[i])
	}
	time.Sleep(time.Second)
	// Die swarm, you don't belong in this world
	for _, v := range swarms {
		switch s := v.state.(type) {
		case *StateSteady:
			s.die <- struct{}{}
		default:
			t.Fatal("State unexpectedly changed")
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"os"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/internal/fs"
	"github.com/googlecloudplatform/gcsfuse/internal/perms"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/timeutil"
)

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *flagStorage,
	conn gcs.Conn) (mfs *fuse.MountedFileSystem, err error) {
	// Sanity check: make sure the temporary directory exists and is writable
	// currently. This gives a better user experience than harder to debug EIO
	// errors when reading files in the future.
	if flags.TempDir != "" {
		var f *os.File
		f, err = fsutil.AnonymousFile(flags.TempDir)
		f.Close()

		if err != nil {
			err = fmt.Errorf(
				"Error writing to temporary directory (%q); are you sure it exists "+
					"with the correct permissions?",
				err.Error())
			return
		}
	}

	// Choose UID and GID.
	uid, gid, err := perms.MyUserAndGroup()
	if err != nil {
		err = fmt.Errorf("MyUserAndGroup: %v", err)
		return
	}

	if flags.Uid >= 0 {
		uid = uint32(flags.Uid)
	}

	if flags.Gid >= 0 {
		gid = uint32(flags.Gid)
	}

	// Set up the bucket.
	bucket, err := setUpBucket(
		ctx,
		flags,
		conn,
		bucketName)

	if err != nil {
		err = fmt.Errorf("setUpBucket: %v", err)
		return
	}

	// Create a file system server.
	serverCfg := &fs.ServerConfig{
		CacheClock:             timeutil.RealClock(),
		Bucket:                 bucket,
		TempDir:                flags.TempDir,
		ImplicitDirectories:    flags.ImplicitDirs,
		InodeAttributeCacheTTL: flags.StatCacheTTL,
		DirTypeCacheTTL:        flags.TypeCacheTTL,
		Uid:                    uid,
		Gid:                    gid,
		FilePerms:              os.FileMode(flags.FileMode),
		DirPerms:               os.FileMode(flags.DirMode),

		AppendThreshold: 1 << 21, // 2 MiB, a total guess.
		TmpObjectPrefix: ".gcsfuse_tmp/",
	}

	server, err := fs.NewServer(serverCfg)
	if err != nil {
		err = fmt.Errorf("fs.NewServer: %v", err)
		return
	}

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:      bucket.Name(),
		Options:     flags.MountOptions,
		ErrorLogger: log.New(os.Stderr, "fuse: ", log.Flags()),
	}

	if flags.DebugFuse {
		mountCfg.DebugLogger = log.New(os.Stderr, "fuse_debug: ", 0)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}
<commit_msg>Print a warning when invoked as root.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"os"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/internal/fs"
	"github.com/googlecloudplatform/gcsfuse/internal/perms"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fsutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/timeutil"
)

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *flagStorage,
	conn gcs.Conn) (mfs *fuse.MountedFileSystem, err error) {
	// Sanity check: make sure the temporary directory exists and is writable
	// currently. This gives a better user experience than harder to debug EIO
	// errors when reading files in the future.
	if flags.TempDir != "" {
		var f *os.File
		f, err = fsutil.AnonymousFile(flags.TempDir)
		f.Close()

		if err != nil {
			err = fmt.Errorf(
				"Error writing to temporary directory (%q); are you sure it exists "+
					"with the correct permissions?",
				err.Error())
			return
		}
	}

	// Find the current process's UID and GID. If it was invoked as root and the
	// user hasn't explicitly overridden --uid, everything is going to be owned
	// by root. This is probably not what the user wants, so print a warning.
	uid, gid, err := perms.MyUserAndGroup()
	if err != nil {
		err = fmt.Errorf("MyUserAndGroup: %v", err)
		return
	}

	if uid == 0 && flags.Uid < 0 {
		fmt.Fprintln(os.Stderr, `
WARNING: gcsfuse invoked as root. This will cause all files to be owned by
root. If this is not what you intended, invoke gcsfuse as the user that will
be interacting with the file system.
`)
	}

	// Choose UID and GID.
	if flags.Uid >= 0 {
		uid = uint32(flags.Uid)
	}

	if flags.Gid >= 0 {
		gid = uint32(flags.Gid)
	}

	// Set up the bucket.
	bucket, err := setUpBucket(
		ctx,
		flags,
		conn,
		bucketName)

	if err != nil {
		err = fmt.Errorf("setUpBucket: %v", err)
		return
	}

	// Create a file system server.
	serverCfg := &fs.ServerConfig{
		CacheClock:             timeutil.RealClock(),
		Bucket:                 bucket,
		TempDir:                flags.TempDir,
		ImplicitDirectories:    flags.ImplicitDirs,
		InodeAttributeCacheTTL: flags.StatCacheTTL,
		DirTypeCacheTTL:        flags.TypeCacheTTL,
		Uid:                    uid,
		Gid:                    gid,
		FilePerms:              os.FileMode(flags.FileMode),
		DirPerms:               os.FileMode(flags.DirMode),

		AppendThreshold: 1 << 21, // 2 MiB, a total guess.
		TmpObjectPrefix: ".gcsfuse_tmp/",
	}

	server, err := fs.NewServer(serverCfg)
	if err != nil {
		err = fmt.Errorf("fs.NewServer: %v", err)
		return
	}

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:      bucket.Name(),
		Options:     flags.MountOptions,
		ErrorLogger: log.New(os.Stderr, "fuse: ", log.Flags()),
	}

	if flags.DebugFuse {
		mountCfg.DebugLogger = log.New(os.Stderr, "fuse_debug: ", 0)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}
<|endoftext|>