<commit_before>// ATM - Automatic TempUrl Maker
// A builder of Swift TempURLs
// Copyright (c) 2015 Stuart Glenn
// All rights reserved
// Use of this source code is goverened by a BSD 3-clause license,
// see included LICENSE file for details
package main

import (
	"fmt"
	"log"
	"os/user"

	"github.com/codegangsta/cli"
	"github.com/glennsb/atm"
	"github.com/howeyc/gopass"
)

func main() {
	app := cli.NewApp()
	app.Name = "atm"
	app.Usage = "Automated TempURL Maker"
	app.Version = "0.0.1 - 20151025"
	app.Author = "Stuart Glenn"
	app.Email = "Stuart-Glenn@omrf.org"
	app.Copyright = "2015 Stuart Glenn, All rights reserved"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "V, verbose",
			Usage: "show more output",
		},
	}

	app.Commands = []cli.Command{
		serverCommand(),
	}

	app.RunAndExitOnError()
}

func serverFlags() []cli.Flag {
	current_user, err := user.Current()
	default_username := ""
	if nil == err {
		default_username = current_user.Username
	}
	return []cli.Flag{
		cli.StringFlag{
			Name:  "database",
			Usage: "name of database",
			Value: "atm",
		},
		cli.StringFlag{
			Name:  "database-host",
			Usage: "hostname of database server",
			Value: "localhost",
		},
		cli.StringFlag{
			Name:  "database-user",
			Usage: "username for database connection",
			Value: default_username,
		},
		cli.IntFlag{
			Name:  "database-port",
			Usage: "port number of database server",
			Value: 3306,
		},
		cli.DurationFlag{
			Name:  "duration",
			Usage: "Default lifetime for generated tempurl",
			Value: atm.DURATION,
		},
		cli.StringFlag{
			Name:  "object-host, host",
			Usage: "Swift service host prefix",
			Value: atm.HOST,
		},
	}
}

func serverCommand() cli.Command {
	return cli.Command{
		Name:  "server",
		Usage: "Run webservice",
		Flags: serverFlags(),
		Action: func(c *cli.Context) {
			db_user := c.String("database-user")
			db_host := c.String("database-host")
			db := c.String("database")

			fmt.Printf("%s@%s/%s password: ", db_user, db_host, db)
			db_pass := string(gopass.GetPasswd())

			ds, err := atm.NewDatastore("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
				db_user, db_pass, db_host, c.Int("database-port"), db))
			if nil != err {
				log.Fatal(err)
			} else {
				db_pass = ""
				defer ds.Close()

				service := &atm.Server{
					Ds:               ds,
					Object_host:      c.String("object-host"),
					Default_duration: int64(c.Duration("duration").Minutes()),
				}
				service.Run()
			}
		},
	}
}
<commit_msg>Add stub for client commands in the CLI<commit_after>// ATM - Automatic TempUrl Maker
// A builder of Swift TempURLs
// Copyright (c) 2015 Stuart Glenn
// All rights reserved
// Use of this source code is goverened by a BSD 3-clause license,
// see included LICENSE file for details
package main

import (
	"fmt"
	"log"
	"os/user"

	"github.com/codegangsta/cli"
	"github.com/glennsb/atm"
	"github.com/howeyc/gopass"
)

func main() {
	app := cli.NewApp()
	app.Name = "atm"
	app.Usage = "Automated TempURL Maker"
	app.Version = "0.0.1 - 20151025"
	app.Author = "Stuart Glenn"
	app.Email = "Stuart-Glenn@omrf.org"
	app.Copyright = "2015 Stuart Glenn, All rights reserved"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "V, verbose",
			Usage: "show more output",
		},
	}

	app.Commands = clientCommands()
	app.Commands = append(app.Commands, serverCommand())
	app.RunAndExitOnError()
}

func clientCommands() []cli.Command {
	return []cli.Command{
		cli.Command{
			Name:  "url",
			Usage: "Request a temp url",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "api-key, k",
					Usage:  "account/user atm api-key",
					EnvVar: "ATM_API_KEY",
				},
				cli.StringFlag{
					Name:   "api-secret, s",
					Usage:  "account/user atm api-secret",
					EnvVar: "ATM_API_SECRET",
				},
				cli.StringFlag{
					Name:   "host, h",
					Usage:  "atm server endpoint",
					EnvVar: "ATM_HOST",
				},
				cli.StringFlag{
					Name:  "method, m",
					Usage: "HTTP method requested for temp url",
					Value: "GET",
				},
			},
			Action: func(c *cli.Context) {
				log.Fatal("Not implemented yet")
				return
			},
		},
		cli.Command{
			Name:  "key",
			Usage: "Add/Remove signing key",
			Action: func(c *cli.Context) {
				log.Fatal("Not implemented yet")
				return
			},
		},
	}
}

func serverFlags() []cli.Flag {
	current_user, err := user.Current()
	default_username := ""
	if nil == err {
		default_username = current_user.Username
	}
	return []cli.Flag{
		cli.StringFlag{
			Name:  "database",
			Usage: "name of database",
			Value: "atm",
		},
		cli.StringFlag{
			Name:  "database-host",
			Usage: "hostname of database server",
			Value: "localhost",
		},
		cli.StringFlag{
			Name:  "database-user",
			Usage: "username for database connection",
			Value: default_username,
		},
		cli.IntFlag{
			Name:  "database-port",
			Usage: "port number of database server",
			Value: 3306,
		},
		cli.DurationFlag{
			Name:  "duration",
			Usage: "Default lifetime for generated tempurl",
			Value: atm.DURATION,
		},
		cli.StringFlag{
			Name:  "object-host, host",
			Usage: "Swift service host prefix",
			Value: atm.HOST,
		},
	}
}

func serverCommand() cli.Command {
	return cli.Command{
		Name:  "server",
		Usage: "Run webservice",
		Flags: serverFlags(),
		Action: func(c *cli.Context) {
			db_user := c.String("database-user")
			db_host := c.String("database-host")
			db := c.String("database")

			fmt.Printf("%s@%s/%s password: ", db_user, db_host, db)
			db_pass := string(gopass.GetPasswd())

			ds, err := atm.NewDatastore("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
				db_user, db_pass, db_host, c.Int("database-port"), db))
			if nil != err {
				log.Fatal(err)
			} else {
				db_pass = ""
				defer ds.Close()

				service := &atm.Server{
					Ds:               ds,
					Object_host:      c.String("object-host"),
					Default_duration: int64(c.Duration("duration").Minutes()),
				}
				service.Run()
			}
		},
	}
}
<|endoftext|>


<commit_before>//go:generate esc -o static.go -prefix ../web/build -pkg server ../web/build
package server

import (
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/cardigann/cardigann/config"
	"github.com/cardigann/cardigann/indexer"
	"github.com/cardigann/cardigann/logger"
	"github.com/cardigann/cardigann/torznab"
	"github.com/gorilla/mux"
)

const (
	buildDir = "/web/build"
)

var (
	log              = logger.Logger
	apiRoutePrefixes = []string{
		"/torznab/",
		"/download/",
		"/xhr/",
		"/debug/",
	}
)

type Params struct {
	BaseURL    string
	APIKey     []byte
	Passphrase string
	Config     config.Config
	Version    string
}

type handler struct {
	http.Handler
	Params      Params
	FileHandler http.Handler
	indexers    map[string]torznab.Indexer
}

func NewHandler(p Params) (http.Handler, error) {
	h := &handler{
		Params:      p,
		FileHandler: http.FileServer(FS(false)),
		indexers:    map[string]torznab.Indexer{},
	}

	router := mux.NewRouter()

	// torznab routes
	router.HandleFunc("/torznab/{indexer}", h.torznabHandler).Methods("GET")
	router.HandleFunc("/torznab/{indexer}/api", h.torznabHandler).Methods("GET")
	router.HandleFunc("/download/{indexer}/{token}/{filename}", h.downloadHandler).Methods("HEAD")
	router.HandleFunc("/download/{indexer}/{token}/{filename}", h.downloadHandler).Methods("GET")
	router.HandleFunc("/download/{token}/{filename}", h.downloadHandler).Methods("HEAD")
	router.HandleFunc("/download/{token}/{filename}", h.downloadHandler).Methods("GET")

	// xhr routes for the webapp
	router.HandleFunc("/xhr/indexers/{indexer}/test", h.getIndexerTestHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers/{indexer}/config", h.getIndexersConfigHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers/{indexer}/config", h.patchIndexersConfigHandler).Methods("PATCH")
	router.HandleFunc("/xhr/indexers", h.getIndexersHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers", h.patchIndexersHandler).Methods("PATCH")
	router.HandleFunc("/xhr/auth", h.getAuthHandler).Methods("GET")
	router.HandleFunc("/xhr/auth", h.postAuthHandler).Methods("POST")
	router.HandleFunc("/xhr/version", h.getVersionHandler).Methods("GET")

	h.Handler = router
	return h, h.initialize()
}

func (h *handler) initialize() error {
	if h.Params.Passphrase == "" {
		apiKey, hasApiKey, err := h.Params.Config.Get("global", "apikey")
		if err != nil {
			return err
		}
		if !hasApiKey {
			k, err := h.sharedKey()
			if err != nil {
				return err
			}
			h.Params.APIKey = k
			return h.Params.Config.Set("global", "apikey", fmt.Sprintf("%x", k))
		}
		k, err := hex.DecodeString(apiKey)
		if err != nil {
			return err
		}
		h.Params.APIKey = k
	}
	return nil
}

func (h *handler) baseURL(r *http.Request, path string) (*url.URL, error) {
	if h.Params.BaseURL != "" {
		return url.Parse(h.Params.BaseURL)
	}
	proto := "http"
	if r.TLS != nil {
		proto = "https"
	}
	return url.Parse(fmt.Sprintf("%s://%s%s", proto, r.Host, path))
}

func (h *handler) createIndexer(key string) (torznab.Indexer, error) {
	def, err := indexer.DefaultDefinitionLoader.Load(key)
	if err != nil {
		log.WithError(err).Warnf("Failed to load definition for %q", key)
		return nil, err
	}

	log.WithFields(logrus.Fields{"indexer": key}).Debugf("Loaded indexer")
	indexer, err := indexer.NewRunner(def, indexer.RunnerOpts{
		Config: h.Params.Config,
	}), nil
	if err != nil {
		return nil, err
	}

	return indexer, nil
}

func (h *handler) lookupIndexer(key string) (torznab.Indexer, error) {
	if key == "aggregate" {
		return h.createAggregate()
	}
	if _, ok := h.indexers[key]; !ok {
		indexer, err := h.createIndexer(key)
		if err != nil {
			return nil, err
		}
		h.indexers[key] = indexer
	}

	return h.indexers[key], nil
}

func (h *handler) createAggregate() (torznab.Indexer, error) {
	keys, err := indexer.DefaultDefinitionLoader.List()
	if err != nil {
		return nil, err
	}

	agg := indexer.Aggregate{}
	for _, key := range keys {
		if config.IsSectionEnabled(key, h.Params.Config) {
			indexer, err := h.lookupIndexer(key)
			if err != nil {
				return nil, err
			}
			agg = append(agg, indexer)
		}
	}

	return agg, nil
}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); origin != "" {
		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, PATCH")
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers",
			"Accept, Cache-Control, Content-Type, Content-Length, Accept-Encoding, Authorization, Last-Event-ID")
	}
	if r.Method == "OPTIONS" {
		return
	}

	log.WithFields(logrus.Fields{
		"method": r.Method,
		"path":   r.URL.RequestURI(),
		"remote": r.RemoteAddr,
	}).Debugf("%s %s", r.Method, r.URL.RequestURI())

	for _, prefix := range apiRoutePrefixes {
		if strings.HasPrefix(r.URL.Path, prefix) {
			h.Handler.ServeHTTP(w, r)
			return
		}
	}

	h.FileHandler.ServeHTTP(w, r)
}

func (h *handler) torznabHandler(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	indexerID := params["indexer"]

	apiKey := r.URL.Query().Get("apikey")
	if !h.checkAPIKey(apiKey) {
		torznab.Error(w, "Invalid apikey parameter", torznab.ErrInsufficientPrivs)
		return
	}

	indexer, err := h.lookupIndexer(indexerID)
	if err != nil {
		torznab.Error(w, err.Error(), torznab.ErrIncorrectParameter)
		return
	}

	t := r.URL.Query().Get("t")

	if t == "" {
		http.Redirect(w, r, r.URL.Path+"?t=caps", http.StatusTemporaryRedirect)
		return
	}

	switch t {
	case "caps":
		indexer.Capabilities().ServeHTTP(w, r)

	case "search", "tvsearch", "tv-search":
		feed, err := h.search(r, indexer, indexerID)
		if err != nil {
			torznab.Error(w, err.Error(), torznab.ErrUnknownError)
			return
		}
		switch r.URL.Query().Get("format") {
		case "", "xml":
			x, err := xml.MarshalIndent(feed, "", "  ")
			if err != nil {
				torznab.Error(w, err.Error(), torznab.ErrUnknownError)
				return
			}
			w.Header().Set("Content-Type", "application/rss+xml")
			w.Write(x)
		case "json":
			jsonOutput(w, feed)
		}

	default:
		torznab.Error(w, "Unknown type parameter", torznab.ErrIncorrectParameter)
	}
}

func (h *handler) downloadHandler(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	token := params["token"]
	filename := params["filename"]

	log.WithFields(logrus.Fields{"filename": filename}).Debugf("Processing download via handler")

	k, err := h.sharedKey()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	t, err := decodeToken(token, k)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	indexer, err := h.lookupIndexer(t.Site)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	rc, _, err := indexer.Download(t.Link)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	w.Header().Set("Content-Type", "application/x-bittorrent")
	w.Header().Set("Content-Disposition", "attachment; filename="+filename)
	w.Header().Set("Content-Transfer-Encoding", "binary")

	defer rc.Close()
	io.Copy(w, rc)
}

func (h *handler) search(r *http.Request, indexer torznab.Indexer, siteKey string) (*torznab.ResultFeed, error) {
	baseURL, err := h.baseURL(r, "/download")
	if err != nil {
		return nil, err
	}

	query, err := torznab.ParseQuery(r.URL.Query())
	if err != nil {
		return nil, err
	}

	items, err := indexer.Search(query)
	if err != nil {
		return nil, err
	}

	feed := &torznab.ResultFeed{
		Info:  indexer.Info(),
		Items: items,
	}

	k, err := h.sharedKey()
	if err != nil {
		return nil, err
	}

	// rewrite links to use the server
	for idx, item := range feed.Items {
		t := &token{
			Site: item.Site,
			Link: item.Link,
		}

		te, err := t.Encode(k)
		if err != nil {
			log.Debugf("Error encoding token: %v", err)
			return nil, err
		}

		log.Debugf("Generated signed token %q", te)
		feed.Items[idx].Link = fmt.Sprintf("%s/%s/%s.torrent", baseURL.String(), te, item.Title)
	}

	return feed, err
}
<commit_msg>Read passphrase from config on startup, closes #38<commit_after>//go:generate esc -o static.go -prefix ../web/build -pkg server ../web/build
package server

import (
	"encoding/hex"
	"encoding/xml"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/cardigann/cardigann/config"
	"github.com/cardigann/cardigann/indexer"
	"github.com/cardigann/cardigann/logger"
	"github.com/cardigann/cardigann/torznab"
	"github.com/gorilla/mux"
)

const (
	buildDir = "/web/build"
)

var (
	log              = logger.Logger
	apiRoutePrefixes = []string{
		"/torznab/",
		"/download/",
		"/xhr/",
		"/debug/",
	}
)

type Params struct {
	BaseURL    string
	APIKey     []byte
	Passphrase string
	Config     config.Config
	Version    string
}

type handler struct {
	http.Handler
	Params      Params
	FileHandler http.Handler
	indexers    map[string]torznab.Indexer
}

func NewHandler(p Params) (http.Handler, error) {
	h := &handler{
		Params:      p,
		FileHandler: http.FileServer(FS(false)),
		indexers:    map[string]torznab.Indexer{},
	}

	router := mux.NewRouter()

	// torznab routes
	router.HandleFunc("/torznab/{indexer}", h.torznabHandler).Methods("GET")
	router.HandleFunc("/torznab/{indexer}/api", h.torznabHandler).Methods("GET")
	router.HandleFunc("/download/{indexer}/{token}/{filename}", h.downloadHandler).Methods("HEAD")
	router.HandleFunc("/download/{indexer}/{token}/{filename}", h.downloadHandler).Methods("GET")
	router.HandleFunc("/download/{token}/{filename}", h.downloadHandler).Methods("HEAD")
	router.HandleFunc("/download/{token}/{filename}", h.downloadHandler).Methods("GET")

	// xhr routes for the webapp
	router.HandleFunc("/xhr/indexers/{indexer}/test", h.getIndexerTestHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers/{indexer}/config", h.getIndexersConfigHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers/{indexer}/config", h.patchIndexersConfigHandler).Methods("PATCH")
	router.HandleFunc("/xhr/indexers", h.getIndexersHandler).Methods("GET")
	router.HandleFunc("/xhr/indexers", h.patchIndexersHandler).Methods("PATCH")
	router.HandleFunc("/xhr/auth", h.getAuthHandler).Methods("GET")
	router.HandleFunc("/xhr/auth", h.postAuthHandler).Methods("POST")
	router.HandleFunc("/xhr/version", h.getVersionHandler).Methods("GET")

	h.Handler = router
	return h, h.initialize()
}

func (h *handler) initialize() error {
	if h.Params.Passphrase == "" {
		pass, hasPassphrase, _ := h.Params.Config.Get("global", "passphrase")
		if hasPassphrase {
			h.Params.Passphrase = pass
			return nil
		}
		apiKey, hasApiKey, _ := h.Params.Config.Get("global", "apikey")
		if !hasApiKey {
			k, err := h.sharedKey()
			if err != nil {
				return err
			}
			h.Params.APIKey = k
			return h.Params.Config.Set("global", "apikey", fmt.Sprintf("%x", k))
		}
		k, err := hex.DecodeString(apiKey)
		if err != nil {
			return err
		}
		h.Params.APIKey = k
	}
	return nil
}

func (h *handler) baseURL(r *http.Request, path string) (*url.URL, error) {
	if h.Params.BaseURL != "" {
		return url.Parse(h.Params.BaseURL)
	}
	proto := "http"
	if r.TLS != nil {
		proto = "https"
	}
	return url.Parse(fmt.Sprintf("%s://%s%s", proto, r.Host, path))
}

func (h *handler) createIndexer(key string) (torznab.Indexer, error) {
	def, err := indexer.DefaultDefinitionLoader.Load(key)
	if err != nil {
		log.WithError(err).Warnf("Failed to load definition for %q", key)
		return nil, err
	}

	log.WithFields(logrus.Fields{"indexer": key}).Debugf("Loaded indexer")
	indexer, err := indexer.NewRunner(def, indexer.RunnerOpts{
		Config: h.Params.Config,
	}), nil
	if err != nil {
		return nil, err
	}

	return indexer, nil
}

func (h *handler) lookupIndexer(key string) (torznab.Indexer, error) {
	if key == "aggregate" {
		return h.createAggregate()
	}
	if _, ok := h.indexers[key]; !ok {
		indexer, err := h.createIndexer(key)
		if err != nil {
			return nil, err
		}
		h.indexers[key] = indexer
	}

	return h.indexers[key], nil
}

func (h *handler) createAggregate() (torznab.Indexer, error) {
	keys, err := indexer.DefaultDefinitionLoader.List()
	if err != nil {
		return nil, err
	}

	agg := indexer.Aggregate{}
	for _, key := range keys {
		if config.IsSectionEnabled(key, h.Params.Config) {
			indexer, err := h.lookupIndexer(key)
			if err != nil {
				return nil, err
			}
			agg = append(agg, indexer)
		}
	}

	return agg, nil
}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); origin != "" {
		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, PATCH")
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers",
			"Accept, Cache-Control, Content-Type, Content-Length, Accept-Encoding, Authorization, Last-Event-ID")
	}
	if r.Method == "OPTIONS" {
		return
	}

	log.WithFields(logrus.Fields{
		"method": r.Method,
		"path":   r.URL.RequestURI(),
		"remote": r.RemoteAddr,
	}).Debugf("%s %s", r.Method, r.URL.RequestURI())

	for _, prefix := range apiRoutePrefixes {
		if strings.HasPrefix(r.URL.Path, prefix) {
			h.Handler.ServeHTTP(w, r)
			return
		}
	}

	h.FileHandler.ServeHTTP(w, r)
}

func (h *handler) torznabHandler(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	indexerID := params["indexer"]

	apiKey := r.URL.Query().Get("apikey")
	if !h.checkAPIKey(apiKey) {
		torznab.Error(w, "Invalid apikey parameter", torznab.ErrInsufficientPrivs)
		return
	}

	indexer, err := h.lookupIndexer(indexerID)
	if err != nil {
		torznab.Error(w, err.Error(), torznab.ErrIncorrectParameter)
		return
	}

	t := r.URL.Query().Get("t")

	if t == "" {
		http.Redirect(w, r, r.URL.Path+"?t=caps", http.StatusTemporaryRedirect)
		return
	}

	switch t {
	case "caps":
		indexer.Capabilities().ServeHTTP(w, r)

	case "search", "tvsearch", "tv-search":
		feed, err := h.search(r, indexer, indexerID)
		if err != nil {
			torznab.Error(w, err.Error(), torznab.ErrUnknownError)
			return
		}
		switch r.URL.Query().Get("format") {
		case "", "xml":
			x, err := xml.MarshalIndent(feed, "", "  ")
			if err != nil {
				torznab.Error(w, err.Error(), torznab.ErrUnknownError)
				return
			}
			w.Header().Set("Content-Type", "application/rss+xml")
			w.Write(x)
		case "json":
			jsonOutput(w, feed)
		}

	default:
		torznab.Error(w, "Unknown type parameter", torznab.ErrIncorrectParameter)
	}
}

func (h *handler) downloadHandler(w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	token := params["token"]
	filename := params["filename"]

	log.WithFields(logrus.Fields{"filename": filename}).Debugf("Processing download via handler")

	k, err := h.sharedKey()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	t, err := decodeToken(token, k)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	indexer, err := h.lookupIndexer(t.Site)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	rc, _, err := indexer.Download(t.Link)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	w.Header().Set("Content-Type", "application/x-bittorrent")
	w.Header().Set("Content-Disposition", "attachment; filename="+filename)
	w.Header().Set("Content-Transfer-Encoding", "binary")

	defer rc.Close()
	io.Copy(w, rc)
}

func (h *handler) search(r *http.Request, indexer torznab.Indexer, siteKey string) (*torznab.ResultFeed, error) {
	baseURL, err := h.baseURL(r, "/download")
	if err != nil {
		return nil, err
	}

	query, err := torznab.ParseQuery(r.URL.Query())
	if err != nil {
		return nil, err
	}

	items, err := indexer.Search(query)
	if err != nil {
		return nil, err
	}

	feed := &torznab.ResultFeed{
		Info:  indexer.Info(),
		Items: items,
	}

	k, err := h.sharedKey()
	if err != nil {
		return nil, err
	}

	// rewrite links to use the server
	for idx, item := range feed.Items {
		t := &token{
			Site: item.Site,
			Link: item.Link,
		}

		te, err := t.Encode(k)
		if err != nil {
			log.Debugf("Error encoding token: %v", err)
			return nil, err
		}

		log.Debugf("Generated signed token %q", te)
		feed.Items[idx].Link = fmt.Sprintf("%s/%s/%s.torrent", baseURL.String(), te, item.Title)
	}

	return feed, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"strconv"
	"time"
)

type Game struct {
	// Registered clients.
	clients map[*Client]bool

	// Register requests from the clients.
	register chan *Client

	// Unregister requests from clients.
	unregister chan *Client

	// Game objects that currently exist
	history *GameHistory

	// Next valid game object id.
	nextId int
}

type GameSettings struct {
	// All the important game variables
	constants *GameConstants

	// Whether or not to print debug messages.
	debug bool
}

type GameConstants struct {
	ShipAcceleration uint16 `json:"ship_acceleration"`
	ShipRotation     uint16 `json:"ship_rotation"`
	ProjectileSpeed  uint16 `json:"projectile_speed"`
}

type GameError struct {
	What string
}

func (e GameError) Error() string {
	return e.What
}

const (
	gameUpdatePeriod = 10 * time.Millisecond
)

// TODO: Get this working without a global variable, I guess pass a ref to game into the web socket handler function?
var settings = &GameSettings{
	debug: false,

	// Game constants, values are all per-second
	constants: &GameConstants{
		ShipAcceleration: 100, // Pixels per second
		ShipRotation:     100, // Degrees per second
		ProjectileSpeed:  150, // Pixels per second
	},
}
var game = CreateGame()

func CreateGame() *Game {
	g := &Game{
		clients:    make(map[*Client]bool),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		history:    CreateGameHistory(),
	}

	// Create asteroids
	for i := 0; i < 100; i++ {
		id := g.generateId()
		p, a, v, s := RandomAsteroidGeometry()
		g.history.Run(&CreateAsteroidEvent{MakeTimestamp(), id, p, a, v, s})
	}

	return g
}

func (g *Game) Run() {
	gameUpdateTicker := time.NewTicker(gameUpdatePeriod)
	defer func() {
		gameUpdateTicker.Stop()
	}()

	for {
		select {
		case c := <-g.register:
			// Register client
			g.clients[c] = true

			// Create ship
			id := g.generateId()
			state := g.history.Run(&CreateShipEvent{MakeTimestamp(), id, MakePoint(0, 0)})

			// Send game state dump to player
			c.Initialize(id, settings.constants, state)
		case c := <-g.unregister:
			if _, ok := g.clients[c]; ok {
				delete(g.clients, c)
			}
		case <-gameUpdateTicker.C:
			g.history.Tick()
		}
	}
}

func (g *Game) broadcastUpdate(state *GameState) {
	if settings.debug {
		log.Println(fmt.Sprintf("Ships: %d, Projectiles: %d", len(state.Ships), len(state.Projectiles)))
	}

	for c := range g.clients {
		c.SendUpdate(state)
	}
}

func (g *Game) generateId() string {
	g.nextId++
	return strconv.Itoa(g.nextId)
}
<commit_msg>Moved objects debug into game update tick, removed unused broadcastUpdate method.<commit_after>package main

import (
	"fmt"
	"log"
	"strconv"
	"time"
)

type Game struct {
	// Registered clients.
	clients map[*Client]bool

	// Register requests from the clients.
	register chan *Client

	// Unregister requests from clients.
	unregister chan *Client

	// Game objects that currently exist
	history *GameHistory

	// Next valid game object id.
	nextId int
}

type GameSettings struct {
	// All the important game variables
	constants *GameConstants

	// Whether or not to print debug messages.
	debug bool
}

type GameConstants struct {
	ShipAcceleration uint16 `json:"ship_acceleration"`
	ShipRotation     uint16 `json:"ship_rotation"`
	ProjectileSpeed  uint16 `json:"projectile_speed"`
}

type GameError struct {
	What string
}

func (e GameError) Error() string {
	return e.What
}

const (
	gameUpdatePeriod = 10 * time.Millisecond
)

// TODO: Get this working without a global variable, I guess pass a ref to game into the web socket handler function?
var settings = &GameSettings{
	debug: false,

	// Game constants, values are all per-second
	constants: &GameConstants{
		ShipAcceleration: 100, // Pixels per second
		ShipRotation:     100, // Degrees per second
		ProjectileSpeed:  150, // Pixels per second
	},
}
var game = CreateGame()

func CreateGame() *Game {
	g := &Game{
		clients:    make(map[*Client]bool),
		register:   make(chan *Client),
		unregister: make(chan *Client),
		history:    CreateGameHistory(),
	}

	// Create asteroids
	for i := 0; i < 100; i++ {
		id := g.generateId()
		p, a, v, s := RandomAsteroidGeometry()
		g.history.Run(&CreateAsteroidEvent{MakeTimestamp(), id, p, a, v, s})
	}

	return g
}

func (g *Game) Run() {
	gameUpdateTicker := time.NewTicker(gameUpdatePeriod)
	defer func() {
		gameUpdateTicker.Stop()
	}()

	for {
		select {
		case c := <-g.register:
			// Register client
			g.clients[c] = true

			// Create ship
			id := g.generateId()
			state := g.history.Run(&CreateShipEvent{MakeTimestamp(), id, MakePoint(0, 0)})

			// Send game state dump to player
			c.Initialize(id, settings.constants, state)
		case c := <-g.unregister:
			if _, ok := g.clients[c]; ok {
				delete(g.clients, c)
			}
		case <-gameUpdateTicker.C:
			state := g.history.Tick()
			if settings.debug {
				log.Println(fmt.Sprintf("Ships: %d, Projectiles: %d", len(state.Ships), len(state.Projectiles)))
			}
		}
	}
}

func (g *Game) generateId() string {
	g.nextId++
	return strconv.Itoa(g.nextId)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/martini"
	"github.com/martini-contrib/sessions"
	"github.com/shykes/spdy-go"

	"io/ioutil"
)

func main() {
	s := NewServer()
	m := martini.Classic()

	secret,err := ioutil.ReadFile(".secret")
	if err != nil {
		panic(err)
	}
	store := sessions.NewCookieStore(secret)
	m.Use(sessions.Sessions("ask_eecs_auth_session", store))

	m.Get("/q/:id", s.HandleGetQuestion)
	m.Get("/q/:id/vote/:opt", s.HandleVote)
	m.Post("/q", s.HandlePostQuestion)
	m.Get("/q", s.HandleGetQuestions)
	m.Post("/login", s.HandleLogin)
	m.Post("/register", s.HandleRegister)
	m.Post("/logout", s.HandleLogout)
	m.Post("/me", s.HandleMe);
	m.Run()
	//spdy.ListenAndServeTCP(":3000", m)
}
<commit_msg>unused dep<commit_after>package main

import (
	"github.com/codegangsta/martini"
	"github.com/martini-contrib/sessions"
	//"github.com/shykes/spdy-go"

	"io/ioutil"
)

func main() {
	s := NewServer()
	m := martini.Classic()

	secret,err := ioutil.ReadFile(".secret")
	if err != nil {
		panic(err)
	}
	store := sessions.NewCookieStore(secret)
	m.Use(sessions.Sessions("ask_eecs_auth_session", store))

	m.Get("/q/:id", s.HandleGetQuestion)
	m.Get("/q/:id/vote/:opt", s.HandleVote)
	m.Post("/q", s.HandlePostQuestion)
	m.Get("/q", s.HandleGetQuestions)
	m.Post("/login", s.HandleLogin)
	m.Post("/register", s.HandleRegister)
	m.Post("/logout", s.HandleLogout)
	m.Post("/me", s.HandleMe);
	m.Run()
	//spdy.ListenAndServeTCP(":3000", m)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path"
	"runtime"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
	"github.com/urfave/cli"
	"golang.org/x/crypto/acme/autocert"
)

//go:generate fileb0x ab0x.yaml

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	if env := os.Getenv("KLEISTER_ENV_FILE"); env != "" {
		godotenv.Load(env)
	}

	app := cli.NewApp()
	app.Name = "kleister-ui"
	app.Version = Version
	app.Author = "Thomas Boerger <thomas@webhippie.de>"
	app.Usage = "Manage mod packs for Minecraft"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Activate debug information",
			EnvVar:      "KLEISTER_DEBUG",
			Destination: &Config.Debug,
		},
	}

	app.Before = func(c *cli.Context) error {
		logrus.SetOutput(os.Stdout)

		if Config.Debug {
			logrus.SetLevel(logrus.DebugLevel)
		} else {
			logrus.SetLevel(logrus.InfoLevel)
		}

		return nil
	}

	app.Commands = []cli.Command{
		cli.Command{
			Name:  "server",
			Usage: "Start the Kleister UI",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:        "host",
					Value:       "http://localhost:9000",
					Usage:       "External access to the UI",
					EnvVar:      "KLEISTER_UI_HOST",
					Destination: &Config.Server.Host,
				},
				cli.StringFlag{
					Name:        "addr",
					Value:       ":9000",
					Usage:       "Address to bind the server",
					EnvVar:      "KLEISTER_UI_ADDR",
					Destination: &Config.Server.Addr,
				},
				cli.StringFlag{
					Name:        "endpoint",
					Value:       "http://localhost:8000",
					Usage:       "URL for the API server",
					EnvVar:      "KLEISTER_UI_ENDPOINT",
					Destination: &Config.Server.Endpoint,
				},
				cli.StringFlag{
					Name:        "static",
					Value:       "",
					Usage:       "Folder for serving assets",
					EnvVar:      "KLEISTER_UI_STATIC",
					Destination: &Config.Server.Static,
				},
				cli.StringFlag{
					Name:        "storage",
					Value:       "storage/",
					Usage:       "Folder for storing files",
					EnvVar:      "KLEISTER_UI_STORAGE",
					Destination: &Config.Server.Storage,
				},
				cli.StringFlag{
					Name:        "cert",
					Value:       "",
					Usage:       "Path to SSL cert",
					EnvVar:      "KLEISTER_UI_CERT",
					Destination: &Config.Server.Cert,
				},
				cli.StringFlag{
					Name:        "key",
					Value:       "",
					Usage:       "Path to SSL key",
					EnvVar:      "KLEISTER_UI_KEY",
					Destination: &Config.Server.Key,
				},
				cli.BoolFlag{
					Name:        "letsencrypt",
					Usage:       "Enable Let's Encrypt SSL",
					EnvVar:      "KLEISTER_UI_LETSENCRYPT",
					Destination: &Config.Server.LetsEncrypt,
				},
				cli.BoolFlag{
					Name:        "pprof",
					Usage:       "Enable pprof debugger",
					EnvVar:      "KLEISTER_UI_PPROF",
					Destination: &Config.Server.Pprof,
				},
			},
			Action: func(c *cli.Context) {
				logrus.Infof("Starting UI on %s", Config.Server.Addr)

				if Config.Debug {
					gin.SetMode(gin.DebugMode)
				} else {
					gin.SetMode(gin.ReleaseMode)
				}

				e := gin.New()

				e.SetHTMLTemplate(
					Template(),
				)

				e.Use(SetLogger())
				e.Use(SetRecovery())

				if Config.Server.Pprof {
					pprof.Register(
						e,
						&pprof.Options{
							RoutePrefix: "/debug/pprof",
						},
					)
				}

				if Config.Server.Static != "" {
					e.Static(
						"/assets",
						path.Join(Config.Server.Static, "assets"),
					)
				} else {
					e.StaticFS(
						"/assets",
						HTTP,
					)
				}

				e.NoRoute(Index)

				var (
					server *http.Server
				)

				if Config.Server.LetsEncrypt || (Config.Server.Cert != "" && Config.Server.Key != "") {
					curves := []tls.CurveID{
						tls.CurveP521,
						tls.CurveP384,
						tls.CurveP256,
					}

					ciphers := []uint16{
						tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
						tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
					}

					cfg := &tls.Config{
						PreferServerCipherSuites: true,
						MinVersion:               tls.VersionTLS12,
						CurvePreferences:         curves,
						CipherSuites:             ciphers,
					}

					if Config.Server.LetsEncrypt {
						parsed, err := url.Parse(Config.Server.Host)

						if err != nil {
							logrus.Fatal("Failed to parse host name. %s", err)
						}

						certManager := autocert.Manager{
							Prompt:     autocert.AcceptTOS,
							HostPolicy: autocert.HostWhitelist(parsed.Host),
							Cache:      autocert.DirCache(Config.Server.Storage),
						}

						cfg.GetCertificate = certManager.GetCertificate
					} else {
						cert, err := tls.LoadX509KeyPair(
							Config.Server.Cert,
							Config.Server.Key,
						)

						if err != nil {
							logrus.Fatal("Failed to load SSL certificates. %s", err)
						}

						cfg.Certificates = []tls.Certificate{
							cert,
						}
					}

					server = &http.Server{
						Addr:         Config.Server.Addr,
						Handler:      e,
						ReadTimeout:  5 * time.Second,
						WriteTimeout: 10 * time.Second,
						TLSConfig:    cfg,
					}
				} else {
					server = &http.Server{
						Addr:         Config.Server.Addr,
						Handler:      e,
						ReadTimeout:  5 * time.Second,
						WriteTimeout: 10 * time.Second,
					}
				}

				if err := startServer(server); err != nil {
					logrus.Fatal(err)
				}
			},
		},
	}

	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "Show the help, so what you see now",
	}

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version, v",
		Usage: "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Fixed go formatting<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path"
	"runtime"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
	"github.com/urfave/cli"
	"golang.org/x/crypto/acme/autocert"
)

//go:generate fileb0x ab0x.yaml

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	if env := os.Getenv("KLEISTER_ENV_FILE"); env != "" {
		godotenv.Load(env)
	}

	app := cli.NewApp()
	app.Name = "kleister-ui"
	app.Version = Version
	app.Author = "Thomas Boerger <thomas@webhippie.de>"
	app.Usage = "Manage mod packs for Minecraft"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Activate debug information",
			EnvVar:      "KLEISTER_DEBUG",
			Destination: &Config.Debug,
		},
	}

	app.Before = func(c *cli.Context) error {
		logrus.SetOutput(os.Stdout)

		if Config.Debug {
			logrus.SetLevel(logrus.DebugLevel)
		} else {
			logrus.SetLevel(logrus.InfoLevel)
		}

		return nil
	}

	app.Commands = []cli.Command{
		{
			Name:  "server",
			Usage: "Start the Kleister UI",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:        "host",
					Value:       "http://localhost:9000",
					Usage:       "External access to the UI",
					EnvVar:      "KLEISTER_UI_HOST",
					Destination: &Config.Server.Host,
				},
				cli.StringFlag{
					Name:        "addr",
					Value:       ":9000",
					Usage:       "Address to bind the server",
					EnvVar:      "KLEISTER_UI_ADDR",
					Destination: &Config.Server.Addr,
				},
				cli.StringFlag{
					Name:        "endpoint",
					Value:       "http://localhost:8000",
					Usage:       "URL for the API server",
					EnvVar:      "KLEISTER_UI_ENDPOINT",
					Destination: &Config.Server.Endpoint,
				},
				cli.StringFlag{
					Name:        "static",
					Value:       "",
					Usage:       "Folder for serving assets",
					EnvVar:      "KLEISTER_UI_STATIC",
					Destination: &Config.Server.Static,
				},
				cli.StringFlag{
					Name:        "storage",
					Value:       "storage/",
					Usage:       "Folder for storing files",
					EnvVar:      "KLEISTER_UI_STORAGE",
					Destination: &Config.Server.Storage,
				},
				cli.StringFlag{
					Name:        "cert",
					Value:       "",
					Usage:       "Path to SSL cert",
					EnvVar:      "KLEISTER_UI_CERT",
					Destination: &Config.Server.Cert,
				},
				cli.StringFlag{
					Name:        "key",
					Value:       "",
					Usage:       "Path to SSL key",
					EnvVar:      "KLEISTER_UI_KEY",
					Destination: &Config.Server.Key,
				},
				cli.BoolFlag{
					Name:        "letsencrypt",
					Usage:       "Enable Let's Encrypt SSL",
					EnvVar:      "KLEISTER_UI_LETSENCRYPT",
					Destination: &Config.Server.LetsEncrypt,
				},
				cli.BoolFlag{
					Name:        "pprof",
					Usage:       "Enable pprof debugger",
					EnvVar:      "KLEISTER_UI_PPROF",
					Destination: &Config.Server.Pprof,
				},
			},
			Action: func(c *cli.Context) {
				logrus.Infof("Starting UI on %s", Config.Server.Addr)

				if Config.Debug {
					gin.SetMode(gin.DebugMode)
				} else {
					gin.SetMode(gin.ReleaseMode)
				}

				e := gin.New()

				e.SetHTMLTemplate(
					Template(),
				)

				e.Use(SetLogger())
				e.Use(SetRecovery())

				if Config.Server.Pprof {
					pprof.Register(
						e,
						&pprof.Options{
							RoutePrefix: "/debug/pprof",
						},
					)
				}

				if Config.Server.Static != "" {
					e.Static(
						"/assets",
						path.Join(Config.Server.Static, "assets"),
					)
				} else {
					e.StaticFS(
						"/assets",
						HTTP,
					)
				}

				e.NoRoute(Index)

				var (
					server *http.Server
				)

				if Config.Server.LetsEncrypt || (Config.Server.Cert != "" && Config.Server.Key != "") {
					curves := []tls.CurveID{
						tls.CurveP521,
						tls.CurveP384,
						tls.CurveP256,
					}

					ciphers := []uint16{
						tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
						tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
					}

					cfg := &tls.Config{
						PreferServerCipherSuites: true,
						MinVersion:               tls.VersionTLS12,
						CurvePreferences:         curves,
						CipherSuites:             ciphers,
					}

					if Config.Server.LetsEncrypt {
						parsed, err := url.Parse(Config.Server.Host)

						if err != nil {
							logrus.Fatal("Failed to parse host name. %s", err)
						}

						certManager := autocert.Manager{
							Prompt:     autocert.AcceptTOS,
							HostPolicy: autocert.HostWhitelist(parsed.Host),
							Cache:      autocert.DirCache(Config.Server.Storage),
						}

						cfg.GetCertificate = certManager.GetCertificate
					} else {
						cert, err := tls.LoadX509KeyPair(
							Config.Server.Cert,
							Config.Server.Key,
						)

						if err != nil {
							logrus.Fatal("Failed to load SSL certificates. %s", err)
						}

						cfg.Certificates = []tls.Certificate{
							cert,
						}
					}

					server = &http.Server{
						Addr:         Config.Server.Addr,
						Handler:      e,
						ReadTimeout:  5 * time.Second,
						WriteTimeout: 10 * time.Second,
						TLSConfig:    cfg,
					}
				} else {
					server = &http.Server{
						Addr:         Config.Server.Addr,
						Handler:      e,
						ReadTimeout:  5 * time.Second,
						WriteTimeout: 10 * time.Second,
					}
				}

				if err := startServer(server); err != nil {
					logrus.Fatal(err)
				}
			},
		},
	}

	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "Show the help, so what you see now",
	}

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version, v",
		Usage: "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package base

import (
	"github.com/gonum/matrix/mat64"
)

// Classifier implementations predict categorical class labels.
type Classifier interface {
	// Takes a set of Instances, copies the class Attribute
	// and constructs a new set of Instances of equivalent
	// length with only the class Attribute and fills it in
	// with predictions.
	Predict(FixedDataGrid) (FixedDataGrid, error)
	// Takes a set of instances and updates the Classifier's
	// internal structures to enable prediction
	Fit(FixedDataGrid) error
	// Why not make every classifier return a nice-looking string?
	String() string
}

// BaseClassifier stores options common to every classifier.
type BaseClassifier struct {
	TrainingData *DataGrid
}

type BaseRegressor struct {
	Data   mat64.Dense
	Name   string
	Labels []float64
}
<commit_msg>Add a SaveableClassifier interface<commit_after>package base

import (
	"github.com/gonum/matrix/mat64"
)

// Classifier implementations predict categorical class labels.
type Classifier interface {
	// Takes a set of Instances, copies the class Attribute
	// and constructs a new set of Instances of equivalent
	// length with only the class Attribute and fills it in
	// with predictions.
	Predict(FixedDataGrid) (FixedDataGrid, error)
	// Takes a set of instances and updates the Classifier's
	// internal structures to enable prediction
	Fit(FixedDataGrid) error
	// Why not make every classifier return a nice-looking string?
	String() string
}

type SaveableClassifier interface {

	// Save the classifier to a file
	Save(string) error
	// Read recreates the classifier from a file
	Load(string) error
}

// BaseClassifier stores options common to every classifier.
type BaseClassifier struct {
	TrainingData *DataGrid
}

type BaseRegressor struct {
	Data   mat64.Dense
	Name   string
	Labels []float64
}
<|endoftext|>


<commit_before>package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
    "strconv"
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func openfile(filename string) (lines []string) {
    // safely open file
    source, err := os.Open(filename)
    check(err)

    scanner := bufio.NewScanner(source)
    // equivalent to a while loop
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }

    return
}

var x, y int64 // these will be assigned to function params
var xerr, yerr error
func main() {
    lines := openfile(os.Args[1])
    for _, line := range lines {
        words := strings.Split(line, " ")
        // convert function parameters to integer types
        if words[0] == "+" || words[0] == "-" || words[0] == "*" || words[0] == "/" {
            x, xerr = strconv.ParseInt(words[1], 10, 0)
            check(xerr)
            y, yerr = strconv.ParseInt(words[2], 10, 0)
            check(yerr)
        }
        if words[0] == "+" {
            fmt.Println(x + y)
        } else if words[0] == "-" {
            fmt.Println(x - y)
        } else if words[0] == "*" {
            fmt.Println(x * y)
        } else if words[0] == "/" {
            fmt.Println(x / y)
        }
    }
}
<commit_msg>beginnings of var manip<commit_after>package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
    "strconv"
)

var variables map[string]int

// determine whether a token is a variable reference or
// an integer literal, and return it.
func getvalue(item string) int {
    if num, err := strconv.Atoi(item); err == nil {
        return num
    }
    return variables[item]
}

// error management
func check(e error) {
    if e != nil {
        panic(e)
    }
}

func openfile(filename string) (lines []string) {
    // safely open file
    source, err := os.Open(filename)
    check(err)

    scanner := bufio.NewScanner(source)
    // equivalent to a while loop
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }

    return
}

var x, y int64 // these will be assigned to function params
var xerr, yerr error
func main() {
    lines := openfile(os.Args[1])
    for _, line := range lines {
        words := strings.Split(line, " ")
        // convert function parameters to integer types and operate on them
        if words[0] == "+" {
            x, y := getvalue(words[1]), getvalue(words[2])
            fmt.Println(x + y)
        } else if words[0] == "-" {
            x, y := getvalue(words[1]), getvalue(words[2])
            fmt.Println(x - y)
        } else if words[0] == "*" {
            x, y := getvalue(words[1]), getvalue(words[2])
            fmt.Println(x * y)
        } else if words[0] == "/" {
            x, y := getvalue(words[1]), getvalue(words[2])
            var z float32 = float32(x) / float32(y)
            fmt.Println(z)
        }
    }
}
<|endoftext|>


<commit_before>package server

import (
	"sync"

	"github.com/xgfone/go-tools/lifecycle"
)

var (
	manager        = lifecycle.GetDefaultManager()
	locked         = new(sync.Mutex)
	shutdowned     = false
	shouldShutdown = make(chan bool, 1)
)

// RunForever runs for ever.
func RunForever() {
	locked.Lock()
	if shutdowned {
		locked.Unlock()
		panic("The server has been shutdowned")
	}
	locked.Unlock()

	<-shouldShutdown
	manager.Stop()
}

// Shutdown shutdowns the server gracefully.
func Shutdown() {
	locked.Lock()
	defer locked.Unlock()
	if shutdowned {
		return
	}

	shutdowned = true
	shouldShutdown <- true
}

// IsShutdowned returns whether the server has been shutdowned.
func IsShutdowned() (yes bool) {
	locked.Lock()
	yes = shutdowned
	locked.Unlock()
	return
}

// RegisterManager replaces the default lifecycle manager.
// The default manager is the default global manager in the package lifecycle.
func RegisterManager(m *lifecycle.Manager) {
	locked.Lock()
	manager = m
	locked.Unlock()
}
<commit_msg>Add the funtion to wait to shutdown.<commit_after>package server

import (
	"sync"

	"github.com/xgfone/go-tools/lifecycle"
)

var (
	manager        = lifecycle.GetDefaultManager()
	locked         = new(sync.Mutex)
	shutdowned     = false
	shouldShutdown = make(chan bool, 1)
	wait           = lifecycle.NewManager()
)

// RunForever runs for ever.
func RunForever() {
	if IsShutdowned() {
		panic("The server has been shutdowned")
	}

	<-shouldShutdown
	manager.Stop()
}

// Shutdown shutdowns the server gracefully.
func Shutdown() {
	locked.Lock()
	defer locked.Unlock()
	if shutdowned {
		return
	}

	shutdowned = true
	wait.Stop()
	shouldShutdown <- true
}

// IsShutdowned returns whether the server has been shutdowned.
func IsShutdowned() (yes bool) {
	locked.Lock()
	yes = shutdowned
	locked.Unlock()
	return
}

func waitShutdown() {
	in := make(chan interface{})
	out := make(chan interface{})
	wait.RegisterChannel(in, out)
	<-in
	out <- struct{}{}
}

// WaitShutdown will wait until it is shutdowned.
// Return immediately if it has been shutdowned.
func WaitShutdown() {
	if IsShutdowned() {
		return
	}

	waitShutdown()
}

// RegisterManager replaces the default lifecycle manager.
// The default manager is the default global manager in the package lifecycle.
func RegisterManager(m *lifecycle.Manager) {
	locked.Lock()
	manager = m
	locked.Unlock()
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package godoc

import (
	"bytes"
	"fmt"
	"net/http"
	"regexp"
	"strings"
)

type SearchResult struct {
	Query string
	Alert string // error or warning message

	// identifier matches
	Pak HitList       // packages matching Query
	Hit *LookupResult // identifier matches of Query
	Alt *AltWords     // alternative identifiers to look for

	// textual matches
	Found    int         // number of textual occurrences found
	Textual  []FileLines // textual matches of Query
	Complete bool        // true if all textual occurrences of Query are reported
	Idents   map[SpotKind][]Ident
}

func (c *Corpus) Lookup(query string) SearchResult {
	result := &SearchResult{Query: query}

	index, timestamp := c.CurrentIndex()
	if index != nil {
		// identifier search
		var err error
		result, err = index.Lookup(query)
		if err != nil && !c.IndexFullText {
			// ignore the error if full text search is enabled
			// since the query may be a valid regular expression
			result.Alert = "Error in query string: " + err.Error()
			return *result
		}

		// full text search
		if c.IndexFullText && query != "" {
			rx, err := regexp.Compile(query)
			if err != nil {
				result.Alert = "Error in query regular expression: " + err.Error()
				return *result
			}
			// If we get maxResults+1 results we know that there are more than
			// maxResults results and thus the result may be incomplete (to be
			// precise, we should remove one result from the result set, but
			// nobody is going to count the results on the result page).
			result.Found, result.Textual = index.LookupRegexp(rx, c.MaxResults+1)
			result.Complete = result.Found <= c.MaxResults
			if !result.Complete {
				result.Found-- // since we looked for maxResults+1
			}
		}
	}

	// is the result accurate?
	if c.IndexEnabled {
		if ts := c.FSModifiedTime(); timestamp.Before(ts) {
			// The index is older than the latest file system change under godoc's observation.
			result.Alert = "Indexing in progress: result may be inaccurate"
		}
	} else {
		result.Alert = "Search index disabled: no results available"
	}

	return *result
}

// SearchResultDoc optionally specifies a function returning an HTML body
// displaying search results matching godoc documentation.
func (p *Presentation) SearchResultDoc(result SearchResult) []byte {
	return applyTemplate(p.SearchDocHTML, "searchDocHTML", result)
}

// SearchResultCode optionally specifies a function returning an HTML body
// displaying search results matching source code.
func (p *Presentation) SearchResultCode(result SearchResult) []byte {
	return applyTemplate(p.SearchCodeHTML, "searchCodeHTML", result)
}

// SearchResultTxt optionally specifies a function returning an HTML body
// displaying search results of textual matches.
func (p *Presentation) SearchResultTxt(result SearchResult) []byte {
	return applyTemplate(p.SearchTxtHTML, "searchTxtHTML", result)
}

// HandleSearch obtains results for the requested search and returns a page
// to display them.
func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) {
	query := strings.TrimSpace(r.FormValue("q"))
	result := p.Corpus.Lookup(query)

	if p.GetPageInfoMode(r)&NoHTML != 0 {
		p.ServeText(w, applyTemplate(p.SearchText, "searchText", result))
		return
	}
	contents := bytes.Buffer{}
	for _, f := range p.SearchResults {
		contents.Write(f(p, result))
	}

	var title string
	if haveResults := contents.Len() > 0; haveResults {
		title = fmt.Sprintf(`Results for query %q`, query)
		if !p.Corpus.IndexEnabled {
			result.Alert = ""
		}
	} else {
		title = fmt.Sprintf(`No results found for query %q`, query)
	}

	body := bytes.NewBuffer(applyTemplate(p.SearchHTML, "searchHTML", result))
	body.Write(contents.Bytes())

	p.ServePage(w, Page{
		Title:    title,
		Tabtitle: query,
		Query:    query,
		Body:     body.Bytes(),
	})
}

func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/opensearchdescription+xml")
	data := map[string]interface{}{
		"BaseURL": fmt.Sprintf("http://%s", r.Host),
	}
	applyTemplateToResponseWriter(w, p.SearchDescXML, &data)
}
<commit_msg>godoc: Fix dereference of nil *SearchResult. Fixes issue 7364.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package godoc

import (
	"bytes"
	"fmt"
	"net/http"
	"regexp"
	"strings"
)

type SearchResult struct {
	Query string
	Alert string // error or warning message

	// identifier matches
	Pak HitList       // packages matching Query
	Hit *LookupResult // identifier matches of Query
	Alt *AltWords     // alternative identifiers to look for

	// textual matches
	Found    int         // number of textual occurrences found
	Textual  []FileLines // textual matches of Query
	Complete bool        // true if all textual occurrences of Query are reported
	Idents   map[SpotKind][]Ident
}

func (c *Corpus) Lookup(query string) SearchResult {
	result := &SearchResult{Query: query}

	index, timestamp := c.CurrentIndex()
	if index != nil {
		// identifier search
		if r, err := index.Lookup(query); err == nil {
			result = r
		} else if err != nil && !c.IndexFullText {
			// ignore the error if full text search is enabled
			// since the query may be a valid regular expression
			result.Alert = "Error in query string: " + err.Error()
			return *result
		}

		// full text search
		if c.IndexFullText && query != "" {
			rx, err := regexp.Compile(query)
			if err != nil {
				result.Alert = "Error in query regular expression: " + err.Error()
				return *result
			}
			// If we get maxResults+1 results we know that there are more than
			// maxResults results and thus the result may be incomplete (to be
			// precise, we should remove one result from the result set, but
			// nobody is going to count the results on the result page).
			result.Found, result.Textual = index.LookupRegexp(rx, c.MaxResults+1)
			result.Complete = result.Found <= c.MaxResults
			if !result.Complete {
				result.Found-- // since we looked for maxResults+1
			}
		}
	}

	// is the result accurate?
	if c.IndexEnabled {
		if ts := c.FSModifiedTime(); timestamp.Before(ts) {
			// The index is older than the latest file system change under godoc's observation.
			result.Alert = "Indexing in progress: result may be inaccurate"
		}
	} else {
		result.Alert = "Search index disabled: no results available"
	}

	return *result
}

// SearchResultDoc optionally specifies a function returning an HTML body
// displaying search results matching godoc documentation.
func (p *Presentation) SearchResultDoc(result SearchResult) []byte {
	return applyTemplate(p.SearchDocHTML, "searchDocHTML", result)
}

// SearchResultCode optionally specifies a function returning an HTML body
// displaying search results matching source code.
func (p *Presentation) SearchResultCode(result SearchResult) []byte {
	return applyTemplate(p.SearchCodeHTML, "searchCodeHTML", result)
}

// SearchResultTxt optionally specifies a function returning an HTML body
// displaying search results of textual matches.
func (p *Presentation) SearchResultTxt(result SearchResult) []byte {
	return applyTemplate(p.SearchTxtHTML, "searchTxtHTML", result)
}

// HandleSearch obtains results for the requested search and returns a page
// to display them.
func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) {
	query := strings.TrimSpace(r.FormValue("q"))
	result := p.Corpus.Lookup(query)

	if p.GetPageInfoMode(r)&NoHTML != 0 {
		p.ServeText(w, applyTemplate(p.SearchText, "searchText", result))
		return
	}
	contents := bytes.Buffer{}
	for _, f := range p.SearchResults {
		contents.Write(f(p, result))
	}

	var title string
	if haveResults := contents.Len() > 0; haveResults {
		title = fmt.Sprintf(`Results for query %q`, query)
		if !p.Corpus.IndexEnabled {
			result.Alert = ""
		}
	} else {
		title = fmt.Sprintf(`No results found for query %q`, query)
	}

	body := bytes.NewBuffer(applyTemplate(p.SearchHTML, "searchHTML", result))
	body.Write(contents.Bytes())

	p.ServePage(w, Page{
		Title:    title,
		Tabtitle: query,
		Query:    query,
		Body:     body.Bytes(),
	})
}

func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/opensearchdescription+xml")
	data := map[string]interface{}{
		"BaseURL": fmt.Sprintf("http://%s", r.Host),
	}
	applyTemplateToResponseWriter(w, p.SearchDescXML, &data)
}
<|endoftext|>


<commit_before>package engine

import (
    "cgl.tideland.biz/applog"
    "net/http"
)

func Main() {
    setupLogger(*logLevel)

    go world.HandleConnections()
    http.HandleFunc("/ws", serveWs)
    applog.Infof("Starting websocket listener on port 8888")
    http.ListenAndServe(":8888", nil)
}

func setupLogger(level int) {
    logger := applog.GoLogger{}
    applog.SetLevel(level)
    applog.SetLogger(logger)
}
<commit_msg>Command line argument parsing for log levels<commit_after>package engine

import (
    "cgl.tideland.biz/applog"
    "flag"
    "net/http"
)

func Main() {
    logLevel := flag.Int("log", applog.LevelDebug, "The Logging Level[0-4]")
    flag.Parse()
    setupLogger(*logLevel)

    go world.HandleConnections()
    http.HandleFunc("/ws", serveWs)
    applog.Infof("Starting websocket listener on port 8888")
    http.ListenAndServe(":8888", nil)
}

func setupLogger(level int) {
    logger := applog.GoLogger{}
    applog.SetLevel(level)
    applog.SetLogger(logger)
}
<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.

package markdown

import (
	"strings"

	"github.com/opennota/byteutil"
	"github.com/opennota/linkify"
)

func isLinkOpen(s string) bool {
	return byteutil.IsLetter(s[1])
}

func isLinkClose(s string) bool {
	return s[1] == '/'
}

func ruleLinkify(s *StateCore) {
	blockTokens := s.Tokens

	if !s.Md.Linkify {
		return
	}

	for _, tok := range blockTokens {
		if tok, ok := tok.(*Inline); ok {
			tokens := tok.Children

			htmlLinkLevel := 0

			for i := len(tokens) - 1; i >= 0; i-- {
				currentTok := tokens[i]

				if _, ok := currentTok.(*LinkClose); ok {
					i--
					for tokens[i].Level() != currentTok.Level() {
						if _, ok := tokens[i].(*LinkOpen); ok {
							break
						}
						i--
					}
					continue
				}

				if currentTok, ok := currentTok.(*HTMLInline); ok {
					if isLinkOpen(currentTok.Content) && htmlLinkLevel > 0 {
						htmlLinkLevel--
					}
					if isLinkClose(currentTok.Content) {
						htmlLinkLevel++
					}
				}
				if htmlLinkLevel > 0 {
					continue
				}

				if currentTok, ok := currentTok.(*Text); ok {
					text := currentTok.Content
					links := linkify.Links(text)
					if len(links) == 0 {
						continue
					}

					var nodes []Token
					level := currentTok.Lvl
					lastPos := 0

					for _, ln := range links {
						urlText := text[ln.Start:ln.End]
						url := urlText
						if ln.Schema == "" {
							url = "http://" + url
						} else if ln.Schema == "mailto:" && !strings.HasPrefix(url, "mailto:") {
							url = "mailto:" + url
						}
						url = normalizeLink(url)
						if !validateLink(url) {
							continue
						}

						urlText = normalizeLinkText(urlText)

						pos := ln.Start

						if pos > lastPos {
							tok := Text{
								Content: text[lastPos:pos],
								Lvl:     level,
							}
							nodes = append(nodes, &tok)
						}

						nodes = append(nodes, &LinkOpen{
							Href: url,
							Lvl:  level,
						})
						nodes = append(nodes, &Text{
							Content: urlText,
							Lvl:     level + 1,
						})
						nodes = append(nodes, &LinkClose{
							Lvl: level,
						})

						lastPos = ln.End
					}

					if lastPos < len(text) {
						tok := Text{
							Content: text[lastPos:],
							Lvl:     level,
						}
						nodes = append(nodes, &tok)
					}

					children := make([]Token, len(tokens)+len(nodes)-1)
					copy(children, tokens[:i])
					copy(children[i:], nodes)
					copy(children[i+len(nodes):], tokens[i+1:])
					tok.Children = children
					tokens = children
				}
			}
		}
	}
}
<commit_msg>Rename struct field due to changes in linkify package<commit_after>// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.

package markdown

import (
	"strings"

	"github.com/opennota/byteutil"
	"github.com/opennota/linkify"
)

func isLinkOpen(s string) bool {
	return byteutil.IsLetter(s[1])
}

func isLinkClose(s string) bool {
	return s[1] == '/'
}

func ruleLinkify(s *StateCore) {
	blockTokens := s.Tokens

	if !s.Md.Linkify {
		return
	}

	for _, tok := range blockTokens {
		if tok, ok := tok.(*Inline); ok {
			tokens := tok.Children

			htmlLinkLevel := 0

			for i := len(tokens) - 1; i >= 0; i-- {
				currentTok := tokens[i]

				if _, ok := currentTok.(*LinkClose); ok {
					i--
					for tokens[i].Level() != currentTok.Level() {
						if _, ok := tokens[i].(*LinkOpen); ok {
							break
						}
						i--
					}
					continue
				}

				if currentTok, ok := currentTok.(*HTMLInline); ok {
					if isLinkOpen(currentTok.Content) && htmlLinkLevel > 0 {
						htmlLinkLevel--
					}
					if isLinkClose(currentTok.Content) {
						htmlLinkLevel++
					}
				}
				if htmlLinkLevel > 0 {
					continue
				}

				if currentTok, ok := currentTok.(*Text); ok {
					text := currentTok.Content
					links := linkify.Links(text)
					if len(links) == 0 {
						continue
					}

					var nodes []Token
					level := currentTok.Lvl
					lastPos := 0

					for _, ln := range links {
						urlText := text[ln.Start:ln.End]
						url := urlText
						if ln.Scheme == "" {
							url = "http://" + url
						} else if ln.Scheme == "mailto:" && !strings.HasPrefix(url, "mailto:") {
							url = "mailto:" + url
						}
						url = normalizeLink(url)
						if !validateLink(url) {
							continue
						}

						urlText = normalizeLinkText(urlText)

						pos := ln.Start

						if pos > lastPos {
							tok := Text{
								Content: text[lastPos:pos],
								Lvl:     level,
							}
							nodes = append(nodes, &tok)
						}

						nodes = append(nodes, &LinkOpen{
							Href: url,
							Lvl:  level,
						})
						nodes = append(nodes, &Text{
							Content: urlText,
							Lvl:     level + 1,
						})
						nodes = append(nodes, &LinkClose{
							Lvl: level,
						})

						lastPos = ln.End
					}

					if lastPos < len(text) {
						tok := Text{
							Content: text[lastPos:],
							Lvl:     level,
						}
						nodes = append(nodes, &tok)
					}

					children := make([]Token, len(tokens)+len(nodes)-1)
					copy(children, tokens[:i])
					copy(children[i:], nodes)
					copy(children[i+len(nodes):], tokens[i+1:])
					tok.Children = children
					tokens = children
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 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 client

import (
	"net/http"
	"time"

	utilnet "k8s.io/apimachinery/pkg/util/net"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
)

type KubeletClientConfig struct {
	// Default port - used if no information about Kubelet port can be found in Node.NodeStatus.DaemonEndpoints.
	Port         uint
	ReadOnlyPort uint
	EnableHttps  bool

	// PreferredAddressTypes - used to select an address from Node.NodeStatus.Addresses
	PreferredAddressTypes []string

	// TLSClientConfig contains settings to enable transport layer security
	restclient.TLSClientConfig

	// Server requires Bearer authentication
	BearerToken string

	// HTTPTimeout is used by the client to timeout http requests to Kubelet.
	HTTPTimeout time.Duration

	// Dial is a custom dialer used for the client
	Dial utilnet.DialFunc
}

func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
	tlsConfig, err := transport.TLSConfigFor(config.transportConfig())
	if err != nil {
		return nil, err
	}

	rt := http.DefaultTransport
	if config.Dial != nil || tlsConfig != nil {
		rt = utilnet.SetOldTransportDefaults(&http.Transport{
			Dial:            config.Dial,
			TLSClientConfig: tlsConfig,
		})
	}

	return transport.HTTPWrappersForConfig(config.transportConfig(), rt)
}

// transportConfig converts a client config to an appropriate transport config.
func (c *KubeletClientConfig) transportConfig() *transport.Config {
	cfg := &transport.Config{
		TLS: transport.TLSConfig{
			CAFile:   c.CAFile,
			CAData:   c.CAData,
			CertFile: c.CertFile,
			CertData: c.CertData,
			KeyFile:  c.KeyFile,
			KeyData:  c.KeyData,
		},
		BearerToken: c.BearerToken,
	}
	if c.EnableHttps && !cfg.HasCA() {
		cfg.TLS.Insecure = true
	}
	return cfg
}
<commit_msg>Avoid passing token when using HTTP<commit_after>// Copyright 2017 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 client

import (
	"net/http"
	"time"

	utilnet "k8s.io/apimachinery/pkg/util/net"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
)

type KubeletClientConfig struct {
	// Default port - used if no information about Kubelet port can be found in Node.NodeStatus.DaemonEndpoints.
	Port         uint
	ReadOnlyPort uint
	EnableHttps  bool

	// PreferredAddressTypes - used to select an address from Node.NodeStatus.Addresses
	PreferredAddressTypes []string

	// TLSClientConfig contains settings to enable transport layer security
	restclient.TLSClientConfig

	// Server requires Bearer authentication
	BearerToken string

	// HTTPTimeout is used by the client to timeout http requests to Kubelet.
	HTTPTimeout time.Duration

	// Dial is a custom dialer used for the client
	Dial utilnet.DialFunc
}

func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
	tlsConfig, err := transport.TLSConfigFor(config.transportConfig())
	if err != nil {
		return nil, err
	}

	rt := http.DefaultTransport
	if config.Dial != nil || tlsConfig != nil {
		rt = utilnet.SetOldTransportDefaults(&http.Transport{
			Dial:            config.Dial,
			TLSClientConfig: tlsConfig,
		})
	}

	return transport.HTTPWrappersForConfig(config.transportConfig(), rt)
}

// transportConfig converts a client config to an appropriate transport config.
func (c *KubeletClientConfig) transportConfig() *transport.Config {
	cfg := &transport.Config{
		TLS: transport.TLSConfig{
			CAFile:   c.CAFile,
			CAData:   c.CAData,
			CertFile: c.CertFile,
			CertData: c.CertData,
			KeyFile:  c.KeyFile,
			KeyData:  c.KeyData,
		},
	}
	if c.EnableHttps {
		cfg.BearerToken = c.BearerToken
		if !cfg.HasCA() {
			cfg.TLS.Insecure = true
		}
	}
	return cfg
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const basePkg = "code.google.com/p/go-tour/"

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
	// the architecture-identifying character of the tool chain, 5, 6, or 8
	archChar string
	// where gc and ld should find the go-tour packages
	pkgDir string
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// set archChar
	var err error
	archChar, err = build.ArchChar(runtime.GOARCH)
	if err != nil {
		log.Fatal(err)
	}

	// find and serve the go tour files
	t, _, err := build.FindTree(basePkg)
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}
	root := filepath.Join(t.SrcDir(), basePkg)
	log.Println("Serving content from", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	// set include path for ld and gc
	pkgDir = t.PkgDir()

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Serving at http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

func compile(req *http.Request) (out []byte, err error) {
	stopRun()

	// x is the base name for .go, .6, executable files
	x := os.TempDir() + "/compile" + strconv.Itoa(<-uniq)
	src := x + ".go"
	obj := x + "." + archChar
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := new(bytes.Buffer)
	if _, err = body.ReadFrom(req.Body); err != nil {
		return
	}
	if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil {
		return
	}

	// build x.go, creating x.6
	out, err = run(archChar+"g", "-I", pkgDir, "-o", obj, src)
	defer os.Remove(obj)
	if err != nil {
		return
	}

	// link x.6, creating x (the program binary)
	out, err = run(archChar+"l", "-L", pkgDir, "-o", bin, obj)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run(bin)
}

// run executes the specified command and returns its output and an error.
func run(args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("already running %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<commit_msg>gotour: update to use 'go build'<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const basePkg = "code.google.com/p/go-tour/"

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
	// the architecture-identifying character of the tool chain, 5, 6, or 8
	archChar string
	// where gc and ld should find the go-tour packages
	pkgDir string
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// set archChar
	var err error
	archChar, err = build.ArchChar(runtime.GOARCH)
	if err != nil {
		log.Fatal(err)
	}

	// find and serve the go tour files
	t, _, err := build.FindTree(basePkg)
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}
	root := filepath.Join(t.SrcDir(), basePkg)
	log.Println("Serving content from", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	// set include path for ld and gc
	pkgDir = t.PkgDir()

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Serving at http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	tmpdir    string
)

func init() {
	// find real temporary directory (for rewriting filename in output)
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

func compile(req *http.Request) (out []byte, err error) {
	stopRun()

	// x is the base name for .go, .6, executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		if err != nil {
			// drop messages from the go tool like '# _/compile0'
			out = commentRe.ReplaceAll(out, nil)
		}
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := new(bytes.Buffer)
	if _, err = body.ReadFrom(req.Body); err != nil {
		return
	}
	defer os.Remove(src)
	if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil {
		return
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	out, err = run(dir, "go", "build", "-o", bin, file)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run("", bin)
}

// run executes the specified command and returns its output and an error.
func run(dir string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("already running %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    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 deployments

import (
	"encoding/json"
	"errors"
	"time"

	"github.com/asaskevich/govalidator"
	"github.com/satori/go.uuid"
)

// Errors
var (
	ErrInvalidDeviceID = errors.New("Invalid device ID")
)

// DeploymentConstructor represent input data needed for creating new Deployment (they differ in fields)
type DeploymentConstructor struct {
	// Deployment name, required
	Name *string `json:"name,omitempty" valid:"length(1|4096),required"`

	// Artifact name to be installed required, associated with image
	ArtifactName *string `json:"artifact_name,omitempty" valid:"length(1|4096),required"`

	// List of device id's targeted for deployments, required
	Devices []string `json:"devices,omitempty" valid:"required" bson:"-"`
}

func NewDeploymentConstructor() *DeploymentConstructor {
	return &DeploymentConstructor{}
}

// Validate checkes structure according to valid tags
// TODO: Add custom validator to check devices array content (such us UUID formatting)
func (c *DeploymentConstructor) Validate() error {
	if _, err := govalidator.ValidateStruct(c); err != nil {
		return err
	}

	for _, id := range c.Devices {
		if govalidator.IsNull(id) {
			return ErrInvalidDeviceID
		}
	}

	return nil
}

type Deployment struct {
	// User provided field set
	*DeploymentConstructor `valid:"required"`

	// Auto set on create, required
	Created *time.Time `json:"created" valid:"required"`

	// Finished deplyment time
	Finished *time.Time `json:"finished,omitempty" valid:"optional"`

	// Deployment id, required
	Id *string `json:"id" bson:"_id" valid:"uuidv4,required"`
}

// NewDeployment creates new deployment object, sets create data by default.
func NewDeployment() *Deployment {
	now := time.Now()
	id := uuid.NewV4().String()

	return &Deployment{
		Created: &now,
		Id:      &id,
		DeploymentConstructor: NewDeploymentConstructor(),
	}
}

// NewDeploymentFromConstructor creates new Deployments object based on constructor data
func NewDeploymentFromConstructor(constructor *DeploymentConstructor) *Deployment {

	deployment := NewDeployment()
	deployment.DeploymentConstructor = constructor

	return deployment
}

// Validate checkes structure according to valid tags
func (d *Deployment) Validate() error {
	_, err := govalidator.ValidateStruct(d)
	return err
}

// To be able to hide devices field, from API output provice custom marshaler
func (d *Deployment) MarshalJSON() ([]byte, error) {

	//Prevents from inheriting original MarshalJSON (if would, infinite loop)
	type Alias Deployment

	slim := struct {
		*Alias
		Devices []string `json:"devices,omitempty"`
	}{
		Alias:   (*Alias)(d),
		Devices: nil,
	}

	return json.Marshal(&slim)
}
<commit_msg>deployments/deployment: introduce aggregate deployment status counters<commit_after>// Copyright 2016 Mender Software AS
//
//    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 deployments

import (
	"encoding/json"
	"errors"
	"time"

	"github.com/asaskevich/govalidator"
	"github.com/satori/go.uuid"
)

// Errors
var (
	ErrInvalidDeviceID = errors.New("Invalid device ID")
)

// DeploymentConstructor represent input data needed for creating new Deployment (they differ in fields)
type DeploymentConstructor struct {
	// Deployment name, required
	Name *string `json:"name,omitempty" valid:"length(1|4096),required"`

	// Artifact name to be installed required, associated with image
	ArtifactName *string `json:"artifact_name,omitempty" valid:"length(1|4096),required"`

	// List of device id's targeted for deployments, required
	Devices []string `json:"devices,omitempty" valid:"required" bson:"-"`
}

func NewDeploymentConstructor() *DeploymentConstructor {
	return &DeploymentConstructor{}
}

// Validate checkes structure according to valid tags
// TODO: Add custom validator to check devices array content (such us UUID formatting)
func (c *DeploymentConstructor) Validate() error {
	if _, err := govalidator.ValidateStruct(c); err != nil {
		return err
	}

	for _, id := range c.Devices {
		if govalidator.IsNull(id) {
			return ErrInvalidDeviceID
		}
	}

	return nil
}

type Deployment struct {
	// User provided field set
	*DeploymentConstructor `valid:"required"`

	// Auto set on create, required
	Created *time.Time `json:"created" valid:"required"`

	// Finished deplyment time
	Finished *time.Time `json:"finished,omitempty" valid:"optional"`

	// Deployment id, required
	Id *string `json:"id" bson:"_id" valid:"uuidv4,required"`

	// Aggregated device status counters.
	// Initialized with the "pending" counter set to total device count for deployment.
	// Individual counter incremented/decremented according to device status updates.
	Stats map[string]int `json:"stats"`
}

// NewDeployment creates new deployment object, sets create data by default.
func NewDeployment() *Deployment {
	now := time.Now()
	id := uuid.NewV4().String()

	return &Deployment{
		Created: &now,
		Id:      &id,
		DeploymentConstructor: NewDeploymentConstructor(),
		Stats: NewDeviceDeploymentStats(),
	}
}

// NewDeploymentFromConstructor creates new Deployments object based on constructor data
func NewDeploymentFromConstructor(constructor *DeploymentConstructor) *Deployment {

	deployment := NewDeployment()
	deployment.DeploymentConstructor = constructor
	if constructor != nil && constructor.Devices != nil {
		deployment.Stats[DeviceDeploymentStatusPending] = len(constructor.Devices)
	}
	return deployment
}

// Validate checkes structure according to valid tags
func (d *Deployment) Validate() error {
	_, err := govalidator.ValidateStruct(d)
	return err
}

// To be able to hide devices field, from API output provice custom marshaler
func (d *Deployment) MarshalJSON() ([]byte, error) {

	//Prevents from inheriting original MarshalJSON (if would, infinite loop)
	type Alias Deployment

	slim := struct {
		*Alias
		Devices []string `json:"devices,omitempty"`
	}{
		Alias:   (*Alias)(d),
		Devices: nil,
	}

	return json.Marshal(&slim)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/logyard-apps/applog_endpoint/wsutil"
	"github.com/gorilla/mux"
	"net/http"
)

func sendRecent(stream *wsutil.WebSocketStream, args *Arguments) error {
	if args.Num <= 0 {
		// First authorize with the CC by fetching something
		_, err := recentLogs(args.Token, args.GUID, 1)
		if err != nil {
			return err
		}
	} else {
		// Recent history requested?
		recentLogs, err := recentLogs(args.Token, args.GUID, args.Num)
		if err != nil {
			return err
		}
		for _, line := range recentLogs {
			err = stream.Send(line)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func recentHandlerWs(
	w http.ResponseWriter, r *http.Request, stream *wsutil.WebSocketStream) {
	args, err := ParseArguments(r)
	if err != nil {
		http.Error(
			w, fmt.Sprintf("Invalid arguments; %v", err), 400)
		return
	}

	if err := sendRecent(stream, args); err != nil {
		stream.Fatalf("%v", err)
		return
	}
}

func tailHandlerWs(
	w http.ResponseWriter, r *http.Request, stream *wsutil.WebSocketStream) {
	args, err := ParseArguments(r)
	if err != nil {
		http.Error(
			w, fmt.Sprintf("Invalid arguments; %v", err), 400)
		return
	}

	if err := sendRecent(stream, args); err != nil {
		stream.Fatalf("%v", err)
		return
	}

	drain, err := NewAppLogDrain(args.GUID)
	if err != nil {
		stream.Fatalf("Unable to create drain: %v", err)
		return
	}
	ch, err := drain.Start()
	if err != nil {
		stream.Fatalf("Unable to start drain: %v", err)
	}

	err = stream.Forward(ch)
	if err != nil {
		log.Infof("%v", err)
		drain.Stop(err)
	}

	// We expect drain.Wait to not block at this point.
	if err := drain.Wait(); err != nil {
		if _, ok := err.(wsutil.WebSocketStreamError); !ok {
			log.Warnf("Error from app log drain server: %v", err)
		}
	}
}

func serve() error {
	addr := fmt.Sprintf(":%d", PORT)
	r := mux.NewRouter()
	r.Handle("/v2/apps/{guid}/tail",
		wsutil.WebSocketHandler(wsutil.HandlerFunc(tailHandlerWs)))
	r.Handle("/v2/apps/{guid}/recent",
		wsutil.WebSocketHandler(wsutil.HandlerFunc(recentHandlerWs)))

	http.Handle("/", r)
	return http.ListenAndServe(addr, nil)
}
<commit_msg>fix a regression in auth error response<commit_after>package main

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/logyard-apps/applog_endpoint/wsutil"
	"github.com/gorilla/mux"
	"net/http"
)

func sendRecent(stream *wsutil.WebSocketStream, args *Arguments) error {
	if args.Num <= 0 {
		// First authorize with the CC by fetching something
		_, err := recentLogs(args.Token, args.GUID, 1)
		if err != nil {
			return err
		}
	} else {
		// Recent history requested?
		recentLogs, err := recentLogs(args.Token, args.GUID, args.Num)
		if err != nil {
			return err
		}
		for _, line := range recentLogs {
			err = stream.Send(line)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func recentHandlerWs(
	w http.ResponseWriter, r *http.Request, stream *wsutil.WebSocketStream) {
	args, err := ParseArguments(r)
	if err != nil {
		stream.Fatalf("Invalid arguments; %v", err)
		return
	}

	if err := sendRecent(stream, args); err != nil {
		stream.Fatalf("%v", err)
		return
	}
}

func tailHandlerWs(
	w http.ResponseWriter, r *http.Request, stream *wsutil.WebSocketStream) {
	args, err := ParseArguments(r)
	if err != nil {
		stream.Fatalf("Invalid arguments; %v", err)
		return
	}

	if err := sendRecent(stream, args); err != nil {
		stream.Fatalf("%v", err)
		return
	}

	drain, err := NewAppLogDrain(args.GUID)
	if err != nil {
		stream.Fatalf("Unable to create drain: %v", err)
		return
	}
	ch, err := drain.Start()
	if err != nil {
		stream.Fatalf("Unable to start drain: %v", err)
	}

	err = stream.Forward(ch)
	if err != nil {
		log.Infof("%v", err)
		drain.Stop(err)
	}

	// We expect drain.Wait to not block at this point.
	if err := drain.Wait(); err != nil {
		if _, ok := err.(wsutil.WebSocketStreamError); !ok {
			log.Warnf("Error from app log drain server: %v", err)
		}
	}
}

func serve() error {
	addr := fmt.Sprintf(":%d", PORT)
	r := mux.NewRouter()
	r.Handle("/v2/apps/{guid}/tail",
		wsutil.WebSocketHandler(wsutil.HandlerFunc(tailHandlerWs)))
	r.Handle("/v2/apps/{guid}/recent",
		wsutil.WebSocketHandler(wsutil.HandlerFunc(recentHandlerWs)))

	http.Handle("/", r)
	return http.ListenAndServe(addr, nil)
}
<|endoftext|>


<commit_before>package ethdb

import (
	"sync"

	"github.com/ethereum/go-ethereum/compression/rle"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

var OpenFileLimit = 64

type LDBDatabase struct {
	fn string

	mu sync.Mutex
	db *leveldb.DB

	queue map[string][]byte

	quit chan struct{}
}

func NewLDBDatabase(file string) (*LDBDatabase, error) {
	// Open the db
	db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
	if err != nil {
		return nil, err
	}
	database := &LDBDatabase{
		fn:   file,
		db:   db,
		quit: make(chan struct{}),
	}
	database.makeQueue()

	return database, nil
}

func (self *LDBDatabase) makeQueue() {
	self.queue = make(map[string][]byte)
}

func (self *LDBDatabase) Put(key []byte, value []byte) {
	self.mu.Lock()
	defer self.mu.Unlock()

	self.queue[string(key)] = value
	/*
		value = rle.Compress(value)

		err := self.db.Put(key, value, nil)
		if err != nil {
			fmt.Println("Error put", err)
		}
	*/
}

func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
	self.mu.Lock()
	defer self.mu.Unlock()

	// Check queue first
	if dat, ok := self.queue[string(key)]; ok {
		return dat, nil
	}

	dat, err := self.db.Get(key, nil)
	if err != nil {
		return nil, err
	}

	return rle.Decompress(dat)
}

func (self *LDBDatabase) Delete(key []byte) error {
	self.mu.Lock()
	defer self.mu.Unlock()

	// make sure it's not in the queue
	delete(self.queue, string(key))

	return self.db.Delete(key, nil)
}

func (self *LDBDatabase) LastKnownTD() []byte {
	data, _ := self.Get([]byte("LTD"))

	if len(data) == 0 {
		data = []byte{0x0}
	}

	return data
}

func (self *LDBDatabase) NewIterator() iterator.Iterator {
	return self.db.NewIterator(nil, nil)
}

func (self *LDBDatabase) Flush() error {
	self.mu.Lock()
	defer self.mu.Unlock()

	batch := new(leveldb.Batch)

	for key, value := range self.queue {
		batch.Put([]byte(key), rle.Compress(value))
	}
	self.makeQueue() // reset the queue

	glog.V(logger.Detail).Infoln("Flush database: ", self.fn)

	return self.db.Write(batch, nil)
}

func (self *LDBDatabase) Close() {
	if err := self.Flush(); err != nil {
		glog.V(logger.Error).Infof("error: flush '%s': %v\n", self.fn, err)
	}

	self.db.Close()
	glog.V(logger.Error).Infoln("flushed and closed db:", self.fn)
}
<commit_msg>ethdb: documentation and corruption recovery<commit_after>package ethdb

import (
	"sync"

	"github.com/ethereum/go-ethereum/compression/rle"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

var OpenFileLimit = 64

type LDBDatabase struct {
	fn string

	mu sync.Mutex
	db *leveldb.DB

	queue map[string][]byte

	quit chan struct{}
}

// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
// it self but requires a background poller which syncs every X. `Flush` should be called
// when data needs to be stored and written to disk.
func NewLDBDatabase(file string) (*LDBDatabase, error) {
	// Open the db
	db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit})
	// check for curruption and attempt to recover
	if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted {
		db, err = leveldb.RecoverFile(file, nil)
	}
	// (re) check for errors and abort if opening of the db failed
	if err != nil {
		return nil, err
	}
	database := &LDBDatabase{
		fn:   file,
		db:   db,
		quit: make(chan struct{}),
	}
	database.makeQueue()

	return database, nil
}

func (self *LDBDatabase) makeQueue() {
	self.queue = make(map[string][]byte)
}

// Put puts the given key / value to the queue
func (self *LDBDatabase) Put(key []byte, value []byte) {
	self.mu.Lock()
	defer self.mu.Unlock()

	self.queue[string(key)] = value
}

// Get returns the given key if it's present.
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
	self.mu.Lock()
	defer self.mu.Unlock()

	// Check queue first
	if dat, ok := self.queue[string(key)]; ok {
		return dat, nil
	}

	dat, err := self.db.Get(key, nil)
	if err != nil {
		return nil, err
	}

	return rle.Decompress(dat)
}

// Delete deletes the key from the queue and database
func (self *LDBDatabase) Delete(key []byte) error {
	self.mu.Lock()
	defer self.mu.Unlock()

	// make sure it's not in the queue
	delete(self.queue, string(key))

	return self.db.Delete(key, nil)
}

func (self *LDBDatabase) LastKnownTD() []byte {
	data, _ := self.Get([]byte("LTD"))

	if len(data) == 0 {
		data = []byte{0x0}
	}

	return data
}

func (self *LDBDatabase) NewIterator() iterator.Iterator {
	return self.db.NewIterator(nil, nil)
}

// Flush flushes out the queue to leveldb
func (self *LDBDatabase) Flush() error {
	self.mu.Lock()
	defer self.mu.Unlock()

	batch := new(leveldb.Batch)

	for key, value := range self.queue {
		batch.Put([]byte(key), rle.Compress(value))
	}
	self.makeQueue() // reset the queue

	glog.V(logger.Detail).Infoln("Flush database: ", self.fn)

	return self.db.Write(batch, nil)
}

func (self *LDBDatabase) Close() {
	if err := self.Flush(); err != nil {
		glog.V(logger.Error).Infof("error: flush '%s': %v\n", self.fn, err)
	}

	self.db.Close()
	glog.V(logger.Error).Infoln("flushed and closed db:", self.fn)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Matthew Collins
 *
 * 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 command implements a system for parsing and executing
// commands
//
// When registering commands a description of the command is
// required. For basic commands the format of this is simple:
//
//     commandname sub1 sub2 sub...
//
// Complex commands can be created by using % to specify
// arguments. The type of the argument will be inferred
// from the type over the passed function pointer. Extra
// constraints can be added after the % to gain finer control
// over the argument.
//
// Executing commands works by treating whitespace at delimiters
// between arguments with the exception of whitespace contained
// within quotes (") as that will be treated as a single argument
package command

// BUG(Think): Complex commands are NYI
<commit_msg>command: remove old bug comment<commit_after>/*
 * Copyright 2015 Matthew Collins
 *
 * 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 command implements a system for parsing and executing
// commands
//
// When registering commands a description of the command is
// required. For basic commands the format of this is simple:
//
//     commandname sub1 sub2 sub...
//
// Complex commands can be created by using % to specify
// arguments. The type of the argument will be inferred
// from the type over the passed function pointer. Extra
// constraints can be added after the % to gain finer control
// over the argument.
//
// Executing commands works by treating whitespace at delimiters
// between arguments with the exception of whitespace contained
// within quotes (") as that will be treated as a single argument
package command
<|endoftext|>