<commit_before>package fritz

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"

	"github.com/bpicode/fritzctl/logger"
)

// Config stores client configuration of your FRITZ!Box
type Config struct {
	Protocol       string `json:"protocol"`        // The protocol to use when communicating with the FRITZ!Box. "http" or "https".
	Host           string `json:"host"`            // Host name or ip address of the FRITZ!Box. In most home setups "fritz.box" can be used. Other possible formats: "192.168.2.200:8080".
	LoginURL       string `json:"loginURL"`        // The URL for the login negotiation.
	Username       string `json:"username"`        // Username to log in. In user-agnostic setups this can be left empty.
	Password       string `json:"password"`        // The password correponding to the Username.
	SkipTLSVerify  bool   `json:"skipTlsVerify"`   // Skip TLS verifcation when using https.
	CerificateFile string `json:"certificateFile"` // Points to a certifiacte file (in PEM format) to verify the integrity of the FRITZ!Box.
}

// FromFile creates a new Config by reading from a file.
func FromFile(filestr string) (*Config, error) {
	logger.Info("Reading config file", filestr)
	file, errOpen := os.Open(filestr)
	if errOpen != nil {
		return nil, errors.New("Cannot open configuration file '" + filestr + "'. Nested error is: " + errOpen.Error())
	}
	conf := Config{}
	errDecode := json.NewDecoder(file).Decode(&conf)
	if errDecode != nil {
		return nil, errors.New("Unable to parse configuration file '" + filestr + "'. Nested error is: " + errDecode.Error())
	}
	return &conf, nil
}

// GetLoginURL returns the URL that is queried for the login challenge
func (config *Config) GetLoginURL() string {
	return fmt.Sprintf("%s://%s%s", config.Protocol, config.Host, config.LoginURL)
}

// GetLoginResponseURL returns the URL that is queried for the login challenge
func (config *Config) GetLoginResponseURL(response string) string {
	return fmt.Sprintf("%s?response=%s&username=%s", config.GetLoginURL(), response, config.Username)
}
<commit_msg>fix typo<commit_after>package fritz

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"

	"github.com/bpicode/fritzctl/logger"
)

// Config stores client configuration of your FRITZ!Box
type Config struct {
	Protocol       string `json:"protocol"`        // The protocol to use when communicating with the FRITZ!Box. "http" or "https".
	Host           string `json:"host"`            // Host name or ip address of the FRITZ!Box. In most home setups "fritz.box" can be used. Other possible formats: "192.168.2.200:8080".
	LoginURL       string `json:"loginURL"`        // The URL for the login negotiation.
	Username       string `json:"username"`        // Username to log in. In user-agnostic setups this can be left empty.
	Password       string `json:"password"`        // The password corresponding to the Username.
	SkipTLSVerify  bool   `json:"skipTlsVerify"`   // Skip TLS verifcation when using https.
	CerificateFile string `json:"certificateFile"` // Points to a certifiacte file (in PEM format) to verify the integrity of the FRITZ!Box.
}

// FromFile creates a new Config by reading from a file.
func FromFile(filestr string) (*Config, error) {
	logger.Info("Reading config file", filestr)
	file, errOpen := os.Open(filestr)
	if errOpen != nil {
		return nil, errors.New("Cannot open configuration file '" + filestr + "'. Nested error is: " + errOpen.Error())
	}
	conf := Config{}
	errDecode := json.NewDecoder(file).Decode(&conf)
	if errDecode != nil {
		return nil, errors.New("Unable to parse configuration file '" + filestr + "'. Nested error is: " + errDecode.Error())
	}
	return &conf, nil
}

// GetLoginURL returns the URL that is queried for the login challenge
func (config *Config) GetLoginURL() string {
	return fmt.Sprintf("%s://%s%s", config.Protocol, config.Host, config.LoginURL)
}

// GetLoginResponseURL returns the URL that is queried for the login challenge
func (config *Config) GetLoginResponseURL(response string) string {
	return fmt.Sprintf("%s?response=%s&username=%s", config.GetLoginURL(), response, config.Username)
}
<|endoftext|>


<commit_before>package configuration

import (
	"encoding/json"
	"errors"
	"io/ioutil"

	"github.com/mdevilliers/redishappy/types"
)

type ConfigurationManager struct {
	config             Configuration
	getChannel         chan GetConfigCommand
	pathToOriginalFile string
}

type Configuration struct {
	Clusters  []types.Cluster  `json:"clusters"`
	HAProxy   types.HAProxy    `json:"haProxy"`
	Sentinels []types.Sentinel `json:"sentinels"`
}

type GetConfigCommand struct {
	returnChannel chan Configuration
}

func (c *ConfigurationManager) GetCurrentConfiguration() Configuration {

	returnChannel := make(chan Configuration)
	c.getChannel <- GetConfigCommand{returnChannel: returnChannel}

	return <-returnChannel
}

func NewConfigurationManager(config Configuration) *ConfigurationManager {
	get := make(chan GetConfigCommand)
	cm := &ConfigurationManager{config: config, getChannel: get}

	go cm.loop(get)
	return cm
}

func (cm *ConfigurationManager) loop(get chan GetConfigCommand) {
	for {
		select {
		case getMessage := <-get:
			getMessage.returnChannel <- cm.config
		}
	}
}

func LoadFromFile(filePath string) (*ConfigurationManager, error) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	configuration, err := parseConfiguration(content)
	if err != nil {
		return nil, err
	}

	cm := NewConfigurationManager(configuration)
	cm.pathToOriginalFile = filePath

	return cm, nil
}

func parseConfiguration(configurationAsJson []byte) (Configuration, error) {

	configuration := Configuration{}
	err := json.Unmarshal(configurationAsJson, &configuration)
	if err != nil {
		return configuration, err
	}

	return configuration, nil
}

func (c Configuration) SanityCheckConfiguration(tests ...SanityCheck) (bool, []string) {

	errorlist := []string{}
	isSane := true

	for _, test := range tests {

		ok, err := test.Check(c)
		if !ok {
			errorlist = append(errorlist, err.Error())
			isSane = false
		}
	}

	return isSane, errorlist
}

func (config Configuration) FindClusterByName(name string) (*types.Cluster, error) {

	for _, cluster := range config.Clusters {
		if cluster.Name == name {
			return &cluster, nil
		}
	}
	return &types.Cluster{}, errors.New("Cluster not found")
}
<commit_msg>fixed casing on json serialisation<commit_after>package configuration

import (
	"encoding/json"
	"errors"
	"io/ioutil"

	"github.com/mdevilliers/redishappy/types"
)

type ConfigurationManager struct {
	config             Configuration
	getChannel         chan GetConfigCommand
	pathToOriginalFile string
}

type Configuration struct {
	Clusters  []types.Cluster  `json:"clusters"`
	HAProxy   types.HAProxy    `json:"HAProxy"`
	Sentinels []types.Sentinel `json:"sentinels"`
}

type GetConfigCommand struct {
	returnChannel chan Configuration
}

func (c *ConfigurationManager) GetCurrentConfiguration() Configuration {

	returnChannel := make(chan Configuration)
	c.getChannel <- GetConfigCommand{returnChannel: returnChannel}

	return <-returnChannel
}

func NewConfigurationManager(config Configuration) *ConfigurationManager {
	get := make(chan GetConfigCommand)
	cm := &ConfigurationManager{config: config, getChannel: get}

	go cm.loop(get)
	return cm
}

func (cm *ConfigurationManager) loop(get chan GetConfigCommand) {
	for {
		select {
		case getMessage := <-get:
			getMessage.returnChannel <- cm.config
		}
	}
}

func LoadFromFile(filePath string) (*ConfigurationManager, error) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	configuration, err := parseConfiguration(content)
	if err != nil {
		return nil, err
	}

	cm := NewConfigurationManager(configuration)
	cm.pathToOriginalFile = filePath

	return cm, nil
}

func parseConfiguration(configurationAsJson []byte) (Configuration, error) {

	configuration := Configuration{}
	err := json.Unmarshal(configurationAsJson, &configuration)
	if err != nil {
		return configuration, err
	}

	return configuration, nil
}

func (c Configuration) SanityCheckConfiguration(tests ...SanityCheck) (bool, []string) {

	errorlist := []string{}
	isSane := true

	for _, test := range tests {

		ok, err := test.Check(c)
		if !ok {
			errorlist = append(errorlist, err.Error())
			isSane = false
		}
	}

	return isSane, errorlist
}

func (config Configuration) FindClusterByName(name string) (*types.Cluster, error) {

	for _, cluster := range config.Clusters {
		if cluster.Name == name {
			return &cluster, nil
		}
	}
	return &types.Cluster{}, errors.New("Cluster not found")
}
<|endoftext|>


<commit_before>package gosql

import "strings"

func (q *QueryRoot) Parse(m map[string]interface{}) error {
	if m == nil || len(m) == 0 {
		return nil
	}
	q.Value = make([]IQuery, 0, len(m))
	for k, v := range m {
		if v == nil {
		} else if IsQueryKey1(k) || IsQueryKey2(k) {
			elem := &QueryElem{anonymous: IsQueryKey2(k), Key: k}
			if err := elem.Parse(v); err == nil {
				q.Value = append(q.Value, elem)
			}
		}
	}
	return nil
}

func (q *QueryElem) Parse(obj interface{}) error {
	if m, ok := obj.(map[string]interface{}); !ok {
		return ErrTypeMap
	} else if m == nil || len(m) == 0 {
		return ErrTypeMap
	} else {
		q.Value = make([]IQuery, 0, len(m))
		for k, v := range m {
			if v == nil {
			} else if IsQueryKey1(k) || IsQueryKey2(k) {
				if !q.IsAnonymous() {
					elem := &QueryElem{anonymous: IsQueryKey2(k), Key: k}
					if err := elem.Parse(v); err == nil {
						q.Value = append(q.Value, elem)
					}
				}
			} else {
				value := &QueryValue{Key: q.Key, Field: k}
				if err := value.Parse(v); err == nil {
					q.Value = append(q.Value, value)
				}
			}
		}
	}
	if q.Value == nil || len(q.Value) == 0 {
		return ErrTypeMap
	}
	return nil
}

func (q *QueryValue) Parse(obj interface{}) error {
	if obj == nil {
		return ErrTypeString
	} else if strings.HasPrefix(q.Field, "%") {
		return ErrTypeString
	}
	switch v := obj.(type) {
	case int:
		q.Value = v
	case int64:
		q.Value = v
	case float32:
		q.Value = v
	case float64:
		q.Value = v
	case string:
		q.Value = v
	default:
		return ErrTypeString
	}
	return nil
}
<commit_msg>feat: query parse json<commit_after>package gosql

import (
	"encoding/json"
	"strings"
)

func (o *QueryRoot) ParseJSONString(str string) error {
	var m map[string]interface{}
	if err := json.Unmarshal([]byte(str), m); err != nil {
		return err
	}
	return o.Parse(m)
}

func (q *QueryRoot) Parse(m map[string]interface{}) error {
	if m == nil || len(m) == 0 {
		return nil
	}
	q.Value = make([]IQuery, 0, len(m))
	for k, v := range m {
		if v == nil {
		} else if IsQueryKey1(k) || IsQueryKey2(k) {
			elem := &QueryElem{anonymous: IsQueryKey2(k), Key: k}
			if err := elem.Parse(v); err == nil {
				q.Value = append(q.Value, elem)
			}
		}
	}
	return nil
}

func (q *QueryElem) Parse(obj interface{}) error {
	if m, ok := obj.(map[string]interface{}); !ok {
		return ErrTypeMap
	} else if m == nil || len(m) == 0 {
		return ErrTypeMap
	} else {
		q.Value = make([]IQuery, 0, len(m))
		for k, v := range m {
			if v == nil {
			} else if IsQueryKey1(k) || IsQueryKey2(k) {
				if !q.IsAnonymous() {
					elem := &QueryElem{anonymous: IsQueryKey2(k), Key: k}
					if err := elem.Parse(v); err == nil {
						q.Value = append(q.Value, elem)
					}
				}
			} else {
				value := &QueryValue{Key: q.Key, Field: k}
				if err := value.Parse(v); err == nil {
					q.Value = append(q.Value, value)
				}
			}
		}
	}
	if q.Value == nil || len(q.Value) == 0 {
		return ErrTypeMap
	}
	return nil
}

func (q *QueryValue) Parse(obj interface{}) error {
	if obj == nil {
		return ErrTypeString
	} else if strings.HasPrefix(q.Field, "%") {
		return ErrTypeString
	}
	switch v := obj.(type) {
	case int:
		q.Value = v
	case int64:
		q.Value = v
	case float32:
		q.Value = v
	case float64:
		q.Value = v
	case string:
		q.Value = v
	default:
		return ErrTypeString
	}
	return nil
}
<|endoftext|>


<commit_before>package caddy

import (
	"context"
	"github.com/dgrijalva/jwt-go"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/tarent/loginsrv/login"
	"github.com/tarent/loginsrv/model"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

//Tests a page while being logged in as a user (doesn't test that the {user} replacer changes)
func Test_ServeHTTP_200(t *testing.T) {
	//Set the ServeHTTP *http.Request
	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatalf("Unable to create request: %v", err)
	}

	// Associate a replacer with the request:
	r = r.WithContext(context.WithValue(context.Background(), httpserver.ReplacerCtxKey, httpserver.NewReplacer(r, nil, "-")))

	//Set the ServeHTTP http.ResponseWriter
	w := httptest.NewRecorder()

	//Set the CaddyHandler config
	configh := login.DefaultConfig()
	configh.Backends = login.Options{"simple": {"bob": "secret"}}
	loginh, err := login.NewHandler(configh)
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set the CaddyHandler that will use ServeHTTP
	h := &CaddyHandler{
		next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return http.StatusOK, nil // not t.Fatalf, or we will not see what other methods yield
		}),
		config:       login.DefaultConfig(),
		loginHandler: loginh,
	}

	//Set user token
	userInfo := model.UserInfo{Sub: "bob", Expiry: time.Now().Add(time.Second).Unix()}
	token := jwt.NewWithClaims(jwt.SigningMethodHS512, userInfo)
	validToken, err := token.SignedString([]byte(h.config.JwtSecret))
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set cookie for user token on the ServeHTTP http.ResponseWriter
	cookie := http.Cookie{Name: "jwt_token", Value: validToken, HttpOnly: true}
	http.SetCookie(w, &cookie)

	//Add the cookie to the request
	r.AddCookie(&cookie)

	//Test that cookie is a valid token
	_, valid := loginh.GetToken(r)
	if !valid {
		t.Errorf("loginHandler cookie is not valid")
	}

	status, err := h.ServeHTTP(w, r)

	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	if status != 200 {
		t.Errorf("Expected returned status code to be %d, got %d", 0, status)
	}

	/**
	TODO: This will only work with the caddy master branch or the next caddy release

		// Check that the replacer now is able to substitute the user variable in log lines
		replacer, replacerOk := r.Context().Value(httpserver.ReplacerCtxKey).(httpserver.Replacer)
		if !replacerOk {
			t.Errorf("no replacer associated with request")

		} else {
			replacement := replacer.Replace("{user}")
			if replacement != "bob" {
				t.Errorf(`wrong replacement: expected "bob", but got %q`, replacement)
			}
		}
	*/
}

//Tests the login page without being logged as a user (doesn't test that the {user} replacer stays as-is)
func Test_ServeHTTP_login(t *testing.T) {
	//Set the ServeHTTP *http.Request
	r, err := http.NewRequest("GET", "/login", nil)
	if err != nil {
		t.Fatalf("Unable to create request: %v", err)
	}

	//Set the ServeHTTP http.ResponseWriter
	w := httptest.NewRecorder()

	//Set the CaddyHandler config
	configh := login.DefaultConfig()
	configh.Backends = login.Options{"simple": {"bob": "secret"}}
	loginh, err := login.NewHandler(configh)
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set the CaddyHandler that will use ServeHTTP
	h := &CaddyHandler{
		next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return http.StatusOK, nil // not t.Fatalf, or we will not see what other methods yield
		}),
		config:       login.DefaultConfig(),
		loginHandler: loginh,
	}

	status, err := h.ServeHTTP(w, r)

	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	if status != 0 {
		t.Errorf("Expected returned status code to be %d, got %d", 0, status)
	}
}
<commit_msg>removed test for {user} log, since it is not in caddy release, yet<commit_after>package caddy

import (
	"context"
	"github.com/dgrijalva/jwt-go"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/tarent/loginsrv/login"
	"github.com/tarent/loginsrv/model"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

//Tests a page while being logged in as a user (doesn't test that the {user} replacer changes)
func Test_ServeHTTP_200(t *testing.T) {
	//Set the ServeHTTP *http.Request
	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatalf("Unable to create request: %v", err)
	}

	/**
	TODO: This will only work with the caddy master branch or the next caddy release

	// Associate a replacer with the request:
	r = r.WithContext(context.WithValue(context.Background(), httpserver.ReplacerCtxKey, httpserver.NewReplacer(r, nil, "-")))
	*/

	//Set the ServeHTTP http.ResponseWriter
	w := httptest.NewRecorder()

	//Set the CaddyHandler config
	configh := login.DefaultConfig()
	configh.Backends = login.Options{"simple": {"bob": "secret"}}
	loginh, err := login.NewHandler(configh)
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set the CaddyHandler that will use ServeHTTP
	h := &CaddyHandler{
		next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return http.StatusOK, nil // not t.Fatalf, or we will not see what other methods yield
		}),
		config:       login.DefaultConfig(),
		loginHandler: loginh,
	}

	//Set user token
	userInfo := model.UserInfo{Sub: "bob", Expiry: time.Now().Add(time.Second).Unix()}
	token := jwt.NewWithClaims(jwt.SigningMethodHS512, userInfo)
	validToken, err := token.SignedString([]byte(h.config.JwtSecret))
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set cookie for user token on the ServeHTTP http.ResponseWriter
	cookie := http.Cookie{Name: "jwt_token", Value: validToken, HttpOnly: true}
	http.SetCookie(w, &cookie)

	//Add the cookie to the request
	r.AddCookie(&cookie)

	//Test that cookie is a valid token
	_, valid := loginh.GetToken(r)
	if !valid {
		t.Errorf("loginHandler cookie is not valid")
	}

	status, err := h.ServeHTTP(w, r)

	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	if status != 200 {
		t.Errorf("Expected returned status code to be %d, got %d", 0, status)
	}

	/**
	TODO: This will only work with the caddy master branch or the next caddy release

		// Check that the replacer now is able to substitute the user variable in log lines
		replacer, replacerOk := r.Context().Value(httpserver.ReplacerCtxKey).(httpserver.Replacer)
		if !replacerOk {
			t.Errorf("no replacer associated with request")

		} else {
			replacement := replacer.Replace("{user}")
			if replacement != "bob" {
				t.Errorf(`wrong replacement: expected "bob", but got %q`, replacement)
			}
		}
	*/
}

//Tests the login page without being logged as a user (doesn't test that the {user} replacer stays as-is)
func Test_ServeHTTP_login(t *testing.T) {
	//Set the ServeHTTP *http.Request
	r, err := http.NewRequest("GET", "/login", nil)
	if err != nil {
		t.Fatalf("Unable to create request: %v", err)
	}

	//Set the ServeHTTP http.ResponseWriter
	w := httptest.NewRecorder()

	//Set the CaddyHandler config
	configh := login.DefaultConfig()
	configh.Backends = login.Options{"simple": {"bob": "secret"}}
	loginh, err := login.NewHandler(configh)
	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	//Set the CaddyHandler that will use ServeHTTP
	h := &CaddyHandler{
		next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return http.StatusOK, nil // not t.Fatalf, or we will not see what other methods yield
		}),
		config:       login.DefaultConfig(),
		loginHandler: loginh,
	}

	status, err := h.ServeHTTP(w, r)

	if err != nil {
		t.Errorf("Expected nil error, got: %v", err)
	}

	if status != 0 {
		t.Errorf("Expected returned status code to be %d, got %d", 0, status)
	}
}
<|endoftext|>


<commit_before>package operator

import (
	"os"
	"strings"
	"testing"
)

func TestVersion(t *testing.T) {
	db, err := NewDatabase(os.Getenv("DATABASE_URL"))
	if err != nil {
		t.Fatal(err)
	}
	version, err := db.Version()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(version, "PostgreSQL") {
		t.Fatal("did not return proper version string")
	}
}
<commit_msg>Test start/stop backup<commit_after>package operator

import (
	"os"
	"strings"
	"testing"
)

func TestVersion(t *testing.T) {
	db, err := NewDatabase(os.Getenv("DATABASE_URL"))
	if err != nil {
		t.Fatal(err)
	}
	version, err := db.Version()
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(version, "PostgreSQL") {
		t.Error("did not return proper version string")
	}
}

func TestBackup(t *testing.T) {
	db, err := NewDatabase(os.Getenv("DATABASE_URL"))
	if err != nil {
		t.Fatal(err)
	}
	start, err := db.StartBackup()
	if err != nil {
		t.Fatal(err)
	}
	stop, err := db.StopBackup()
	if err != nil {
		t.Fatal(err)
	}
	if start.Name != stop.Name {
		t.Error("did not return the same backup name")
	}
}
<|endoftext|>


<commit_before>package conn

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"syscall"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
	reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"

	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {

	maconn, err := d.rawConnDial(ctx, raddr, remote)
	if err != nil {
		return nil, err
	}

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() { done <- struct{}{} }()

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			errOut = err
			return
		}

		if d.PrivateKey == nil {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}
		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		maconn.Close()
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	return connOut, errOut
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (manet.Conn, error) {

	// before doing anything, check we're going to be able to dial.
	// we may not support the given address.
	if _, _, err := manet.DialArgs(raddr); err != nil {
		return nil, err
	}

	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	// get local addr to use.
	laddr := pickLocalAddr(d.LocalAddrs, raddr)
	log.Debugf("%s dialing %s -- %s --> %s", d.LocalPeer, remote, laddr, raddr)

	// make a copy of the manet.Dialer, we may need to change its timeout.
	madialer := d.Dialer

	if laddr != nil && reuseport.Available() {
		// we're perhaps going to dial twice. half the timeout, so we can afford to.
		// otherwise our context would expire right after the first dial.
		madialer.Dialer.Timeout = (madialer.Dialer.Timeout / 2)

		// dial using reuseport.Dialer, because we're probably reusing addrs.
		// this is optimistic, as the reuseDial may fail to bind the port.
		if nconn, retry, reuseErr := reuseDial(madialer.Dialer, laddr, raddr); reuseErr == nil {
			// if it worked, wrap the raw net.Conn with our manet.Conn
			log.Debugf("%s reuse worked! %s %s %s", d.LocalPeer, laddr, nconn.RemoteAddr(), nconn)
			return manet.WrapNetConn(nconn)
		} else if !retry {
			// reuseDial is sure this is a legitimate dial failure, not a reuseport failure.
			return nil, reuseErr
		} else {
			// this is a failure to reuse port. log it.
			log.Debugf("%s port reuse failed: %s --> %s -- %s", d.LocalPeer, laddr, raddr, reuseErr)
		}
	}

	return madialer.Dial(raddr)
}

func reuseDial(dialer net.Dialer, laddr, raddr ma.Multiaddr) (conn net.Conn, retry bool, err error) {
	if laddr == nil {
		// if we're given no local address no sense in using reuseport to dial, dial out as usual.
		return nil, true, reuseport.ErrReuseFailed
	}

	// give reuse.Dialer the manet.Dialer's Dialer.
	// (wow, Dialer should've so been an interface...)
	rd := reuseport.Dialer{dialer}

	// get the local net.Addr manually
	rd.D.LocalAddr, err = manet.ToNetAddr(laddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// get the raddr dial args for rd.dial
	network, netraddr, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
	conn, err = rd.Dial(network, netraddr)
	return conn, reuseErrShouldRetry(err), err // hey! it worked!
}

// reuseErrShouldRetry diagnoses whether to retry after a reuse error.
// if we failed to bind, we should retry. if bind worked and this is a
// real dial error (remote end didnt answer) then we should not retry.
func reuseErrShouldRetry(err error) bool {
	if err == nil {
		return false // hey, it worked! no need to retry.
	}

	// if it's a network timeout error, it's a legitimate failure.
	if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
		return true
	}

	errno, ok := err.(syscall.Errno)
	if !ok { // not an errno? who knows what this is. retry.
		return true
	}

	switch errno {
	case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
		return true // failure to bind. retry.
	case syscall.ECONNREFUSED:
		return false // real dial error
	default:
		return true // optimistically default to retry.
	}
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<commit_msg>p2p/net/conn: reuse timeout is real error<commit_after>package conn

import (
	"fmt"
	"math/rand"
	"net"
	"strings"
	"syscall"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
	reuseport "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"

	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)

// String returns the string rep of d.
func (d *Dialer) String() string {
	return fmt.Sprintf("<Dialer %s %s ...>", d.LocalPeer, d.LocalAddrs[0])
}

// Dial connects to a peer over a particular address
// Ensures raddr is part of peer.Addresses()
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {

	maconn, err := d.rawConnDial(ctx, raddr, remote)
	if err != nil {
		return nil, err
	}

	var connOut Conn
	var errOut error
	done := make(chan struct{})

	// do it async to ensure we respect don contexteone
	go func() {
		defer func() { done <- struct{}{} }()

		c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
		if err != nil {
			errOut = err
			return
		}

		if d.PrivateKey == nil {
			log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
			connOut = c
			return
		}
		c2, err := newSecureConn(ctx, d.PrivateKey, c)
		if err != nil {
			errOut = err
			c.Close()
			return
		}

		connOut = c2
	}()

	select {
	case <-ctx.Done():
		maconn.Close()
		return nil, ctx.Err()
	case <-done:
		// whew, finished.
	}

	return connOut, errOut
}

// rawConnDial dials the underlying net.Conn + manet.Conns
func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (manet.Conn, error) {

	// before doing anything, check we're going to be able to dial.
	// we may not support the given address.
	if _, _, err := manet.DialArgs(raddr); err != nil {
		return nil, err
	}

	if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
		return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
	}

	// get local addr to use.
	laddr := pickLocalAddr(d.LocalAddrs, raddr)
	log.Debugf("%s dialing %s -- %s --> %s", d.LocalPeer, remote, laddr, raddr)

	// make a copy of the manet.Dialer, we may need to change its timeout.
	madialer := d.Dialer

	if laddr != nil && reuseport.Available() {
		// we're perhaps going to dial twice. half the timeout, so we can afford to.
		// otherwise our context would expire right after the first dial.
		madialer.Dialer.Timeout = (madialer.Dialer.Timeout / 2)

		// dial using reuseport.Dialer, because we're probably reusing addrs.
		// this is optimistic, as the reuseDial may fail to bind the port.
		if nconn, retry, reuseErr := reuseDial(madialer.Dialer, laddr, raddr); reuseErr == nil {
			// if it worked, wrap the raw net.Conn with our manet.Conn
			log.Debugf("%s reuse worked! %s %s %s", d.LocalPeer, laddr, nconn.RemoteAddr(), nconn)
			return manet.WrapNetConn(nconn)
		} else if !retry {
			// reuseDial is sure this is a legitimate dial failure, not a reuseport failure.
			return nil, reuseErr
		} else {
			// this is a failure to reuse port. log it.
			log.Debugf("%s port reuse failed: %s --> %s -- %s", d.LocalPeer, laddr, raddr, reuseErr)
		}
	}

	return madialer.Dial(raddr)
}

func reuseDial(dialer net.Dialer, laddr, raddr ma.Multiaddr) (conn net.Conn, retry bool, err error) {
	if laddr == nil {
		// if we're given no local address no sense in using reuseport to dial, dial out as usual.
		return nil, true, reuseport.ErrReuseFailed
	}

	// give reuse.Dialer the manet.Dialer's Dialer.
	// (wow, Dialer should've so been an interface...)
	rd := reuseport.Dialer{dialer}

	// get the local net.Addr manually
	rd.D.LocalAddr, err = manet.ToNetAddr(laddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// get the raddr dial args for rd.dial
	network, netraddr, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, true, err // something wrong with laddr. retry without.
	}

	// rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
	conn, err = rd.Dial(network, netraddr)
	return conn, reuseErrShouldRetry(err), err // hey! it worked!
}

// reuseErrShouldRetry diagnoses whether to retry after a reuse error.
// if we failed to bind, we should retry. if bind worked and this is a
// real dial error (remote end didnt answer) then we should not retry.
func reuseErrShouldRetry(err error) bool {
	if err == nil {
		return false // hey, it worked! no need to retry.
	}

	// if it's a network timeout error, it's a legitimate failure.
	if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
		return false
	}

	errno, ok := err.(syscall.Errno)
	if !ok { // not an errno? who knows what this is. retry.
		return true
	}

	switch errno {
	case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
		return true // failure to bind. retry.
	case syscall.ECONNREFUSED:
		return false // real dial error
	default:
		return true // optimistically default to retry.
	}
}

func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that match the remote addr.
	laddrs = manet.AddrMatch(raddr, laddrs)
	if len(laddrs) < 1 {
		return nil
	}

	// make sure that we ONLY use local addrs that CAN dial the remote addr.
	// filter out all the local addrs that aren't capable
	raddrIPLayer := ma.Split(raddr)[0]
	raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
	raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
	laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
		laddrIPLayer := ma.Split(a)[0]
		laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
		laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
		if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
			return raddrIsLoopback
		}
		if laddrIsLinkLocal {
			return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
		}
		return true
	})

	// TODO pick with a good heuristic
	// we use a random one for now to prevent bad addresses from making nodes unreachable
	// with a random selection, multiple tries may work.
	return laddrs[rand.Intn(len(laddrs))]
}

// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
	ap := a.Protocols()
	bp := b.Protocols()

	if len(ap) != len(bp) {
		return false
	}

	for i, api := range ap {
		if api.Code != bp[i].Code {
			return false
		}
	}

	return true
}

// MultiaddrNetMatch returns the first Multiaddr found to match  network.
func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
	for _, a := range srcs {
		if MultiaddrProtocolsMatch(tgt, a) {
			return a
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package templates

import (
	"archive/tar"
	"compress/gzip"
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/octavore/nagax/util/token"

	"github.com/octavore/press/proto/press/models"
)

const (
	configFileName       = "theme.json"
	fileStoreTemplateDir = "templates"
	fileStoreAssetsDir   = "assets"
)

// FileStore stores and loads templates on the filesystem
type FileStore struct {
	dataDir string
}

func NewFileStore(dataDir string) *FileStore {
	return &FileStore{dataDir: dataDir}
}

// GetTemplate fetches a theme's template from the filesystem. The
// template's Engine is inferred from the extension in templateName
func (f *FileStore) GetTemplate(theme *models.Theme, templateName string) (*models.ThemeTemplate, error) {
	if theme == nil || theme.GetName() == "" {
		return nil, nil
	}
	p := path.Join(f.dataDir, theme.GetName(), fileStoreTemplateDir, templateName)
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	data := string(b)
	ext := strings.TrimLeft(path.Ext(templateName), ".")
	t := &models.ThemeTemplate{
		Theme:  theme.Name,
		Data:   &data,
		Name:   &templateName,
		Engine: &ext,
	}
	return t, nil
}

// GetAsset fetches an asset from the filesystem
func (f *FileStore) GetAsset(theme *models.Theme, assetName string) (*models.ThemeAsset, error) {
	if theme == nil || theme.GetName() == "" {
		return nil, nil
	}
	p := path.Join(f.dataDir, theme.GetName(), fileStoreAssetsDir, assetName)
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	data := string(b)
	t := &models.ThemeAsset{
		Theme: theme.Name,
		Data:  &data,
		Name:  &assetName,
	}
	return t, nil
}

// Get a theme from the file store
func (f *FileStore) Get(themeName string) (*models.Theme, error) {
	if themeName == "" {
		return nil, nil
	}
	themeConfigPath := path.Join(f.dataDir, themeName, configFileName)
	_, err := os.Stat(themeConfigPath)
	if os.IsNotExist(err) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadFile(themeConfigPath)
	if err != nil {
		return nil, err
	}
	t := &models.Theme{
		Templates: map[string]*models.ThemeTemplate{},
		Assets:    map[string]*models.ThemeAsset{},
	}
	err = json.Unmarshal(b, t)
	if err != nil {
		return nil, err
	}

	// get templates (todo: supported subdirs)
	glob := path.Join(f.dataDir, themeName, fileStoreTemplateDir, "*")
	paths, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	for _, p := range paths {
		q := path.Base(p)
		e := strings.TrimLeft(path.Ext(p), ".")
		t.Templates[q] = &models.ThemeTemplate{Name: &q, Engine: &e}
	}

	// get assets (todo: supported subdirs)
	glob = path.Join(f.dataDir, themeName, fileStoreAssetsDir, "*")
	paths, err = filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	for _, p := range paths {
		q := path.Base(p)
		t.Assets[q] = &models.ThemeAsset{Name: &q}
	}
	return t, nil
}

func themeNameFromPath(p string) string {
	dir, _ := path.Split(p)
	return path.Base(dir)
}

// List all themes in the store
func (f *FileStore) List() ([]*models.Theme, error) {
	glob := path.Join(f.dataDir, "*", configFileName)
	paths, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	themes := []*models.Theme{}
	for _, p := range paths {
		b, err := ioutil.ReadFile(p)
		if err != nil {
			return nil, err
		}
		theme := &models.Theme{}
		err = json.Unmarshal(b, theme)
		if err != nil {
			return nil, err
		}
		dir := themeNameFromPath(p)
		theme.Name = &dir
		themes = append(themes, theme)
	}
	return themes, nil
}

// Add a new theme to the store
func (f *FileStore) Add(data io.Reader) (*models.Theme, error) {
	tmpDir := token.New32()
	pth, err := f.extract(data, tmpDir)
	if err != nil {
		return nil, err
	}
	theme, err := f.Get(pth)
	if err != nil {
		return nil, err
	}
	return theme, nil
}

// extract tar.gz from reader into dir
func (f *FileStore) extract(r io.Reader, dir string) (string, error) {
	templateDir := path.Join(f.dataDir, dir)
	gr, err := gzip.NewReader(r)
	if err != nil {
		return "", err
	}
	defer gr.Close()

	tr := tar.NewReader(gr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}

		// ignore links
		if hdr.Mode == tar.TypeSymlink {
			continue
		}

		p := path.Clean(path.Join(templateDir, hdr.Name))
		if strings.HasPrefix(p, "..") {
			// no relative paths
			continue
		}
		err = os.MkdirAll(path.Dir(p), os.FileMode(0700))
		if err != nil {
			return "", err
		}

		f, err := os.Create(p)
		if err != nil {
			return "", err
		}

		defer f.Close()
		_, err = io.Copy(f, tr)
		if err != nil {
			return "", err
		}
	}
	return templateDir, nil
}
<commit_msg>server: filestore: Preserve metadata when loading template.<commit_after>package templates

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/golang/protobuf/jsonpb"
	"github.com/octavore/nagax/util/token"

	"github.com/octavore/press/proto/press/models"
)

const (
	configFileName       = "theme.json"
	fileStoreTemplateDir = "templates"
	fileStoreAssetsDir   = "assets"
)

// FileStore stores and loads templates on the filesystem
type FileStore struct {
	dataDir string
}

func NewFileStore(dataDir string) *FileStore {
	return &FileStore{dataDir: dataDir}
}

// GetTemplate fetches a theme's template from the filesystem. The
// template's Engine is inferred from the extension in templateName
func (f *FileStore) GetTemplate(theme *models.Theme, templateName string) (*models.ThemeTemplate, error) {
	if theme == nil || theme.GetName() == "" {
		return nil, nil
	}
	p := path.Join(f.dataDir, theme.GetName(), fileStoreTemplateDir, templateName)
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	data := string(b)
	ext := strings.TrimLeft(path.Ext(templateName), ".")
	t := &models.ThemeTemplate{
		Theme:  theme.Name,
		Data:   &data,
		Name:   &templateName,
		Engine: &ext,
	}
	return t, nil
}

// GetAsset fetches an asset from the filesystem
func (f *FileStore) GetAsset(theme *models.Theme, assetName string) (*models.ThemeAsset, error) {
	if theme == nil || theme.GetName() == "" {
		return nil, nil
	}
	p := path.Join(f.dataDir, theme.GetName(), fileStoreAssetsDir, assetName)
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	data := string(b)
	t := &models.ThemeAsset{
		Theme: theme.Name,
		Data:  &data,
		Name:  &assetName,
	}
	return t, nil
}

// Get a theme from the file store
func (f *FileStore) Get(themeName string) (*models.Theme, error) {
	if themeName == "" {
		return nil, nil
	}
	themeConfigPath := path.Join(f.dataDir, themeName, configFileName)
	_, err := os.Stat(themeConfigPath)
	if os.IsNotExist(err) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadFile(themeConfigPath)
	if err != nil {
		return nil, err
	}
	t := &models.Theme{
		Templates: map[string]*models.ThemeTemplate{},
		Assets:    map[string]*models.ThemeAsset{},
	}
	err = jsonpb.Unmarshal(bytes.NewBuffer(b), t)
	if err != nil {
		return nil, err
	}

	// get templates (todo: supported subdirs)
	glob := path.Join(f.dataDir, themeName, fileStoreTemplateDir, "*")
	paths, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	for _, p := range paths {
		q := path.Base(p)
		e := strings.TrimLeft(path.Ext(p), ".")
		if t.Templates[q] == nil {
			t.Templates[q] = &models.ThemeTemplate{}
		}
		t.Templates[q].Name = &q
		t.Templates[q].Engine = &e
	}

	// get assets (todo: supported subdirs)
	glob = path.Join(f.dataDir, themeName, fileStoreAssetsDir, "*")
	paths, err = filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	for _, p := range paths {
		q := path.Base(p)
		t.Assets[q] = &models.ThemeAsset{Name: &q}
	}
	return t, nil
}

func themeNameFromPath(p string) string {
	dir, _ := path.Split(p)
	return path.Base(dir)
}

// List all themes in the store
func (f *FileStore) List() ([]*models.Theme, error) {
	glob := path.Join(f.dataDir, "*", configFileName)
	paths, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	themes := []*models.Theme{}
	for _, p := range paths {
		b, err := ioutil.ReadFile(p)
		if err != nil {
			return nil, err
		}
		theme := &models.Theme{}
		err = jsonpb.Unmarshal(bytes.NewBuffer(b), theme)
		if err != nil {
			return nil, err
		}
		dir := themeNameFromPath(p)
		theme.Name = &dir
		themes = append(themes, theme)
	}
	return themes, nil
}

// Add a new theme to the store
func (f *FileStore) Add(data io.Reader) (*models.Theme, error) {
	tmpDir := token.New32()
	pth, err := f.extract(data, tmpDir)
	if err != nil {
		return nil, err
	}
	theme, err := f.Get(pth)
	if err != nil {
		return nil, err
	}
	return theme, nil
}

// extract tar.gz from reader into dir
func (f *FileStore) extract(r io.Reader, dir string) (string, error) {
	templateDir := path.Join(f.dataDir, dir)
	gr, err := gzip.NewReader(r)
	if err != nil {
		return "", err
	}
	defer gr.Close()

	tr := tar.NewReader(gr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		}

		// ignore links
		if hdr.Mode == tar.TypeSymlink {
			continue
		}

		p := path.Clean(path.Join(templateDir, hdr.Name))
		if strings.HasPrefix(p, "..") {
			// no relative paths
			continue
		}
		err = os.MkdirAll(path.Dir(p), os.FileMode(0700))
		if err != nil {
			return "", err
		}

		f, err := os.Create(p)
		if err != nil {
			return "", err
		}

		defer f.Close()
		_, err = io.Copy(f, tr)
		if err != nil {
			return "", err
		}
	}
	return templateDir, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"fmt"
	"io"
	"path"
	"time"

	"github.com/juju/errors"
	"github.com/juju/utils"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"

	"github.com/juju/juju/resource"
)

type resourcePersistence interface {
	// ListResources returns the resource data for the given service ID.
	// None of the resources will be pending.
	ListResources(serviceID string) (resource.ServiceResources, error)

	// ListModelResources returns the resource data for the given
	// service ID. None of the resources will be pending.
	ListModelResources(serviceID string) ([]resource.ModelResource, error)

	// StageResource adds the resource in a separate staging area
	// if the resource isn't already staged. If the resource already
	// exists then it is treated as unavailable as long as the new one
	// is staged.
	//
	// A separate staging area is necessary because we are dealing with
	// the DB and storage at the same time for the same resource in some
	// operations (e.g. SetResource).  Resources are staged in the DB,
	// added to storage, and then finalized in the DB.
	StageResource(resource.ModelResource) error

	// UnstageResource ensures that the resource is removed
	// from the staging area. If it isn't in the staging area
	// then this is a noop.
	UnstageResource(id, serviceID string) error

	// SetResource stores the resource info. If the resource
	// is already staged then it is unstaged.
	SetResource(resource.ModelResource) error

	// SetUnitResource stores the resource info for a unit.
	SetUnitResource(unitID string, args resource.ModelResource) error
}

type resourceStorage interface {
	// PutAndCheckHash stores the content of the reader into the storage.
	PutAndCheckHash(path string, r io.Reader, length int64, hash string) error

	// Remove removes the identified data from the storage.
	Remove(path string) error

	// Get returns a reader for the resource at path. The size of the
	// data is also returned.
	Get(path string) (io.ReadCloser, int64, error)
}

type resourceState struct {
	persist resourcePersistence
	storage resourceStorage

	newPendingID     func() (string, error)
	currentTimestamp func() time.Time
}

// ListResources returns the resource data for the given service ID.
func (st resourceState) ListResources(serviceID string) (resource.ServiceResources, error) {
	resources, err := st.persist.ListResources(serviceID)
	if err != nil {
		return resource.ServiceResources{}, errors.Trace(err)
	}

	return resources, nil
}

// GetResource returns the resource data for the identified resource.
func (st resourceState) GetResource(serviceID, name string) (resource.Resource, error) {
	res, err := st.getResource(serviceID, name)
	if err != nil {
		return res.Resource, errors.Trace(err)
	}
	return res.Resource, nil
}

func (st resourceState) getResource(serviceID, name string) (resource.ModelResource, error) {
	var res resource.ModelResource

	resources, err := st.persist.ListModelResources(serviceID)
	if err != nil {
		return res, errors.Trace(err)
	}

	for _, res := range resources {
		if res.Resource.Name == name {
			return res, nil
		}
	}
	return res, errors.NotFoundf("resource %q", name)
}

// TODO(ericsnow) Separate setting the metadata from storing the blob?

// SetResource stores the resource in the Juju model.
func (st resourceState) SetResource(serviceID, userID string, chRes charmresource.Resource, r io.Reader) (resource.Resource, error) {
	logger.Tracef("adding resource %q for service %q", chRes.Name, serviceID)
	pendingID := ""
	res, err := st.setResource(pendingID, serviceID, userID, chRes, r)
	if err != nil {
		return res, errors.Trace(err)
	}
	return res, nil
}

func (st resourceState) setResource(pendingID, serviceID, userID string, chRes charmresource.Resource, r io.Reader) (resource.Resource, error) {
	res := resource.Resource{
		Resource: chRes,
	}
	if r != nil {
		res.Username = userID
		res.Timestamp = st.currentTimestamp()
	}

	if err := res.Validate(); err != nil {
		return res, errors.Annotate(err, "bad resource metadata")
	}

	id := newResourceID(pendingID, serviceID, res)

	args := resource.ModelResource{
		ID:        id,
		PendingID: pendingID,
		ServiceID: serviceID,
		Resource:  res,
	}
	if r == nil {
		err := st.setResourceInfo(args)
		return res, errors.Trace(err)
	}

	// We use a staging approach for adding the resource metadata
	// to the model. This is necessary because the resource data
	// is stored separately and adding to both should be an atomic
	// operation.

	path := storagePath(res.Name, serviceID, pendingID)
	args.StoragePath = path
	if err := st.persist.StageResource(args); err != nil {
		return res, errors.Trace(err)
	}

	hash := res.Fingerprint.String()
	if err := st.storage.PutAndCheckHash(path, r, res.Size, hash); err != nil {
		if err := st.persist.UnstageResource(id, serviceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", res.Name, serviceID, err)
		}
		return res, errors.Trace(err)
	}

	if err := st.persist.SetResource(args); err != nil {
		if err := st.storage.Remove(path); err != nil {
			logger.Errorf("could not remove resource %q (service %q) from storage: %v", res.Name, serviceID, err)
		}
		if err := st.persist.UnstageResource(id, serviceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", res.Name, serviceID, err)
		}
		return res, errors.Trace(err)
	}

	return res, nil
}

func (st resourceState) setResourceInfo(args resource.ModelResource) error {
	if err := st.persist.StageResource(args); err != nil {
		return errors.Trace(err)
	}

	if err := st.persist.SetResource(args); err != nil {
		if err := st.persist.UnstageResource(args.ID, args.ServiceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", args.Resource.Name, args.ServiceID, err)
		}
		return errors.Trace(err)
	}
	return nil
}

// AddPendingResource stores the resource in the Juju model.
func (st resourceState) AddPendingResource(serviceID, userID string, chRes charmresource.Resource, r io.Reader) (pendingID string, err error) {
	pendingID, err = st.newPendingID()
	if err != nil {
		return "", errors.Annotate(err, "could not generate resource ID")
	}
	logger.Tracef("adding pending resource %q for service %q (ID: %s)", chRes.Name, serviceID, pendingID)

	if _, err := st.setResource(pendingID, serviceID, userID, chRes, r); err != nil {
		return "", errors.Trace(err)
	}

	return pendingID, nil
}

// TODO(ericsnow) Add ResolvePendingResource().

// SetUnitResource records the resource being used by a unit in the Juju model.
func (st resourceState) SetUnitResource(unit resource.Unit, res resource.Resource) error {
	logger.Tracef("adding resource %q for unit %q", res.Name, unit.Name())
	if err := res.Validate(); err != nil {
		return errors.Annotate(err, "bad resource metadata")
	}

	pendingID := ""
	serviceID := unit.ServiceName()
	id := newResourceID(pendingID, serviceID, res)
	args := resource.ModelResource{
		ID:          id,
		ServiceID:   serviceID,
		Resource:    res,
		StoragePath: storagePath(res.Name, serviceID, pendingID),
	}
	err := st.persist.SetUnitResource(unit.Name(), args)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// OpenResource returns metadata about the resource, and a reader for
// the resource.
func (st resourceState) OpenResource(unit resource.Unit, name string) (resource.Resource, io.ReadCloser, error) {
	serviceID := unit.ServiceName()

	modelResource, err := st.getResource(serviceID, name)
	if err != nil {
		return resource.Resource{}, nil, errors.Trace(err)
	}
	resourceInfo := modelResource.Resource
	if resourceInfo.IsPlaceholder() {
		return resource.Resource{}, nil, errors.NotFoundf("resource %q", name)
	}

	path := modelResource.StoragePath
	resourceReader, resSize, err := st.storage.Get(path)
	if err != nil {
		return resource.Resource{}, nil, errors.Trace(err)
	}
	if resSize != resourceInfo.Size {
		msg := "storage returned a size (%d) which doesn't match resource metadata (%d)"
		return resource.Resource{}, nil, errors.Errorf(msg, resSize, resourceInfo.Size)
	}

	id := newResourceID(modelResource.PendingID, serviceID, resourceInfo)
	resourceReader = unitSetter{
		ReadCloser: resourceReader,
		persist:    st.persist,
		unit:       unit,
		args: resource.ModelResource{
			ID:        id,
			ServiceID: serviceID,
			Resource:  resourceInfo,
		},
	}

	return resourceInfo, resourceReader, nil
}

// TODO(ericsnow) Incorporate the service and resource name into the ID
// instead of just using a UUID?

// newPendingID generates a new unique identifier for a resource.
func newPendingID() (string, error) {
	uuid, err := utils.NewUUID()
	if err != nil {
		return "", errors.Annotate(err, "could not create new resource ID")
	}
	return uuid.String(), nil
}

// newResourceID produces a new ID to use for the resource in the model.
func newResourceID(pendingID, serviceID string, res resource.Resource) string {
	id := res.Name
	if pendingID != "" {
		id += "-" + pendingID
	}
	return fmt.Sprintf("service-%s/%s", serviceID, id)
}

// storagePath returns the path used as the location where the resource
// is stored in state storage. This requires that the returned string
// be unique and that it be organized in a structured way. In this case
// we start with a top-level (the service), then under that service use
// the "resources" section. The provided ID is located under there.
func storagePath(name, serviceID, pendingID string) string {
	// TODO(ericsnow) Use services/<service>/resources/<resource>?
	id := name
	if pendingID != "" {
		// TODO(ericsnow) How to resolve this later?
		id += "-" + pendingID
	}
	return path.Join("service-"+serviceID, "resources", id)
}

// unitSetter records the resource as in use by a unit when the wrapped
// reader has been fully read.
type unitSetter struct {
	io.ReadCloser
	persist resourcePersistence
	unit    resource.Unit
	args    resource.ModelResource
}

// Read implements io.Reader.
func (u unitSetter) Read(p []byte) (n int, err error) {
	n, err = u.ReadCloser.Read(p)
	if err == io.EOF {
		// record that the unit is now using this version of the resource
		if err := u.persist.SetUnitResource(u.unit.Name(), u.args); err != nil {
			msg := "Failed to record that unit %q is using resource %q revision %v"
			logger.Errorf(msg, u.unit.Name(), u.args.Resource.Name, u.args.Resource.RevisionString())
		}
	}
	return n, err
}
<commit_msg>Add a TODO.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"fmt"
	"io"
	"path"
	"time"

	"github.com/juju/errors"
	"github.com/juju/utils"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"

	"github.com/juju/juju/resource"
)

type resourcePersistence interface {
	// ListResources returns the resource data for the given service ID.
	// None of the resources will be pending.
	ListResources(serviceID string) (resource.ServiceResources, error)

	// ListModelResources returns the resource data for the given
	// service ID. None of the resources will be pending.
	ListModelResources(serviceID string) ([]resource.ModelResource, error)

	// StageResource adds the resource in a separate staging area
	// if the resource isn't already staged. If the resource already
	// exists then it is treated as unavailable as long as the new one
	// is staged.
	//
	// A separate staging area is necessary because we are dealing with
	// the DB and storage at the same time for the same resource in some
	// operations (e.g. SetResource).  Resources are staged in the DB,
	// added to storage, and then finalized in the DB.
	StageResource(resource.ModelResource) error

	// UnstageResource ensures that the resource is removed
	// from the staging area. If it isn't in the staging area
	// then this is a noop.
	UnstageResource(id, serviceID string) error

	// SetResource stores the resource info. If the resource
	// is already staged then it is unstaged.
	SetResource(resource.ModelResource) error

	// SetUnitResource stores the resource info for a unit.
	SetUnitResource(unitID string, args resource.ModelResource) error
}

type resourceStorage interface {
	// PutAndCheckHash stores the content of the reader into the storage.
	PutAndCheckHash(path string, r io.Reader, length int64, hash string) error

	// Remove removes the identified data from the storage.
	Remove(path string) error

	// Get returns a reader for the resource at path. The size of the
	// data is also returned.
	Get(path string) (io.ReadCloser, int64, error)
}

type resourceState struct {
	persist resourcePersistence
	storage resourceStorage

	newPendingID     func() (string, error)
	currentTimestamp func() time.Time
}

// ListResources returns the resource data for the given service ID.
func (st resourceState) ListResources(serviceID string) (resource.ServiceResources, error) {
	resources, err := st.persist.ListResources(serviceID)
	if err != nil {
		return resource.ServiceResources{}, errors.Trace(err)
	}

	return resources, nil
}

// GetResource returns the resource data for the identified resource.
func (st resourceState) GetResource(serviceID, name string) (resource.Resource, error) {
	res, err := st.getResource(serviceID, name)
	if err != nil {
		return res.Resource, errors.Trace(err)
	}
	return res.Resource, nil
}

func (st resourceState) getResource(serviceID, name string) (resource.ModelResource, error) {
	var res resource.ModelResource

	resources, err := st.persist.ListModelResources(serviceID)
	if err != nil {
		return res, errors.Trace(err)
	}

	for _, res := range resources {
		if res.Resource.Name == name {
			return res, nil
		}
	}
	return res, errors.NotFoundf("resource %q", name)
}

// TODO(ericsnow) Separate setting the metadata from storing the blob?

// SetResource stores the resource in the Juju model.
func (st resourceState) SetResource(serviceID, userID string, chRes charmresource.Resource, r io.Reader) (resource.Resource, error) {
	logger.Tracef("adding resource %q for service %q", chRes.Name, serviceID)
	pendingID := ""
	res, err := st.setResource(pendingID, serviceID, userID, chRes, r)
	if err != nil {
		return res, errors.Trace(err)
	}
	return res, nil
}

func (st resourceState) setResource(pendingID, serviceID, userID string, chRes charmresource.Resource, r io.Reader) (resource.Resource, error) {
	res := resource.Resource{
		Resource: chRes,
	}
	if r != nil {
		// TODO(ericsnow) Validate the user ID (or use a tag).
		res.Username = userID
		res.Timestamp = st.currentTimestamp()
	}

	if err := res.Validate(); err != nil {
		return res, errors.Annotate(err, "bad resource metadata")
	}

	id := newResourceID(pendingID, serviceID, res)

	args := resource.ModelResource{
		ID:        id,
		PendingID: pendingID,
		ServiceID: serviceID,
		Resource:  res,
	}
	if r == nil {
		err := st.setResourceInfo(args)
		return res, errors.Trace(err)
	}

	// We use a staging approach for adding the resource metadata
	// to the model. This is necessary because the resource data
	// is stored separately and adding to both should be an atomic
	// operation.

	path := storagePath(res.Name, serviceID, pendingID)
	args.StoragePath = path
	if err := st.persist.StageResource(args); err != nil {
		return res, errors.Trace(err)
	}

	hash := res.Fingerprint.String()
	if err := st.storage.PutAndCheckHash(path, r, res.Size, hash); err != nil {
		if err := st.persist.UnstageResource(id, serviceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", res.Name, serviceID, err)
		}
		return res, errors.Trace(err)
	}

	if err := st.persist.SetResource(args); err != nil {
		if err := st.storage.Remove(path); err != nil {
			logger.Errorf("could not remove resource %q (service %q) from storage: %v", res.Name, serviceID, err)
		}
		if err := st.persist.UnstageResource(id, serviceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", res.Name, serviceID, err)
		}
		return res, errors.Trace(err)
	}

	return res, nil
}

func (st resourceState) setResourceInfo(args resource.ModelResource) error {
	if err := st.persist.StageResource(args); err != nil {
		return errors.Trace(err)
	}

	if err := st.persist.SetResource(args); err != nil {
		if err := st.persist.UnstageResource(args.ID, args.ServiceID); err != nil {
			logger.Errorf("could not unstage resource %q (service %q): %v", args.Resource.Name, args.ServiceID, err)
		}
		return errors.Trace(err)
	}
	return nil
}

// AddPendingResource stores the resource in the Juju model.
func (st resourceState) AddPendingResource(serviceID, userID string, chRes charmresource.Resource, r io.Reader) (pendingID string, err error) {
	pendingID, err = st.newPendingID()
	if err != nil {
		return "", errors.Annotate(err, "could not generate resource ID")
	}
	logger.Tracef("adding pending resource %q for service %q (ID: %s)", chRes.Name, serviceID, pendingID)

	if _, err := st.setResource(pendingID, serviceID, userID, chRes, r); err != nil {
		return "", errors.Trace(err)
	}

	return pendingID, nil
}

// TODO(ericsnow) Add ResolvePendingResource().

// SetUnitResource records the resource being used by a unit in the Juju model.
func (st resourceState) SetUnitResource(unit resource.Unit, res resource.Resource) error {
	logger.Tracef("adding resource %q for unit %q", res.Name, unit.Name())
	if err := res.Validate(); err != nil {
		return errors.Annotate(err, "bad resource metadata")
	}

	pendingID := ""
	serviceID := unit.ServiceName()
	id := newResourceID(pendingID, serviceID, res)
	args := resource.ModelResource{
		ID:          id,
		ServiceID:   serviceID,
		Resource:    res,
		StoragePath: storagePath(res.Name, serviceID, pendingID),
	}
	err := st.persist.SetUnitResource(unit.Name(), args)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// OpenResource returns metadata about the resource, and a reader for
// the resource.
func (st resourceState) OpenResource(unit resource.Unit, name string) (resource.Resource, io.ReadCloser, error) {
	serviceID := unit.ServiceName()

	modelResource, err := st.getResource(serviceID, name)
	if err != nil {
		return resource.Resource{}, nil, errors.Trace(err)
	}
	resourceInfo := modelResource.Resource
	if resourceInfo.IsPlaceholder() {
		return resource.Resource{}, nil, errors.NotFoundf("resource %q", name)
	}

	path := modelResource.StoragePath
	resourceReader, resSize, err := st.storage.Get(path)
	if err != nil {
		return resource.Resource{}, nil, errors.Trace(err)
	}
	if resSize != resourceInfo.Size {
		msg := "storage returned a size (%d) which doesn't match resource metadata (%d)"
		return resource.Resource{}, nil, errors.Errorf(msg, resSize, resourceInfo.Size)
	}

	id := newResourceID(modelResource.PendingID, serviceID, resourceInfo)
	resourceReader = unitSetter{
		ReadCloser: resourceReader,
		persist:    st.persist,
		unit:       unit,
		args: resource.ModelResource{
			ID:        id,
			ServiceID: serviceID,
			Resource:  resourceInfo,
		},
	}

	return resourceInfo, resourceReader, nil
}

// TODO(ericsnow) Incorporate the service and resource name into the ID
// instead of just using a UUID?

// newPendingID generates a new unique identifier for a resource.
func newPendingID() (string, error) {
	uuid, err := utils.NewUUID()
	if err != nil {
		return "", errors.Annotate(err, "could not create new resource ID")
	}
	return uuid.String(), nil
}

// newResourceID produces a new ID to use for the resource in the model.
func newResourceID(pendingID, serviceID string, res resource.Resource) string {
	id := res.Name
	if pendingID != "" {
		id += "-" + pendingID
	}
	return fmt.Sprintf("service-%s/%s", serviceID, id)
}

// storagePath returns the path used as the location where the resource
// is stored in state storage. This requires that the returned string
// be unique and that it be organized in a structured way. In this case
// we start with a top-level (the service), then under that service use
// the "resources" section. The provided ID is located under there.
func storagePath(name, serviceID, pendingID string) string {
	// TODO(ericsnow) Use services/<service>/resources/<resource>?
	id := name
	if pendingID != "" {
		// TODO(ericsnow) How to resolve this later?
		id += "-" + pendingID
	}
	return path.Join("service-"+serviceID, "resources", id)
}

// unitSetter records the resource as in use by a unit when the wrapped
// reader has been fully read.
type unitSetter struct {
	io.ReadCloser
	persist resourcePersistence
	unit    resource.Unit
	args    resource.ModelResource
}

// Read implements io.Reader.
func (u unitSetter) Read(p []byte) (n int, err error) {
	n, err = u.ReadCloser.Read(p)
	if err == io.EOF {
		// record that the unit is now using this version of the resource
		if err := u.persist.SetUnitResource(u.unit.Name(), u.args); err != nil {
			msg := "Failed to record that unit %q is using resource %q revision %v"
			logger.Errorf(msg, u.unit.Name(), u.args.Resource.Name, u.args.Resource.RevisionString())
		}
	}
	return n, err
}
<|endoftext|>


<commit_before>package pack

import (
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/crypto"
)

type BlobType uint8

const (
	Data BlobType = 0
	Tree          = 1
)

func (t BlobType) String() string {
	switch t {
	case Data:
		return "data"
	case Tree:
		return "tree"
	}

	return fmt.Sprintf("<BlobType %d>", t)
}

func (t BlobType) MarshalJSON() ([]byte, error) {
	switch t {
	case Data:
		return []byte(`"data"`), nil
	case Tree:
		return []byte(`"tree"`), nil
	}

	return nil, errors.New("unknown blob type")
}

func (t *BlobType) UnmarshalJSON(buf []byte) error {
	switch string(buf) {
	case `"data"`:
		*t = Data
	case `"tree"`:
		*t = Tree
	default:
		return errors.New("unknown blob type")
	}

	return nil
}

// Blob is a blob within a pack.
type Blob struct {
	Type   BlobType
	Length uint32
	ID     backend.ID
	Offset uint
}

// GetReader returns an io.Reader for the blob entry e.
func (e Blob) GetReader(rd io.ReadSeeker) (io.Reader, error) {
	// seek to the correct location
	_, err := rd.Seek(int64(e.Offset), 0)
	if err != nil {
		return nil, err
	}

	return io.LimitReader(rd, int64(e.Length)), nil
}

// Packer is used to create a new Pack.
type Packer struct {
	blobs []Blob

	bytes uint
	k     *crypto.Key
	wr    io.Writer
	hw    *backend.HashingWriter

	m sync.Mutex
}

// NewPacker returns a new Packer that can be used to pack blobs
// together.
func NewPacker(k *crypto.Key, w io.Writer) *Packer {
	return &Packer{k: k, wr: w, hw: backend.NewHashingWriter(w, sha256.New())}
}

// Add saves the data read from rd as a new blob to the packer. Returned is the
// number of bytes written to the pack.
func (p *Packer) Add(t BlobType, id backend.ID, rd io.Reader) (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	c := Blob{Type: t, ID: id}

	n, err := io.Copy(p.hw, rd)
	c.Length = uint32(n)
	c.Offset = p.bytes
	p.bytes += uint(n)
	p.blobs = append(p.blobs, c)

	return n, err
}

var entrySize = binary.Size(BlobType(0)) + binary.Size(uint32(0)) + backend.IDSize

// headerEntry is used with encoding/binary to read and write header entries
type headerEntry struct {
	Type   BlobType
	Length uint32
	ID     [backend.IDSize]byte
}

// Finalize writes the header for all added blobs and finalizes the pack.
// Returned are the complete number of bytes written, including the header.
// After Finalize() has finished, the ID of this pack can be obtained by
// calling ID().
func (p *Packer) Finalize() (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	// n tracks the number of bytes written for the header
	var n int64 = int64(p.bytes)

	// create writer to encrypt header
	wr := crypto.EncryptTo(p.k, p.hw)

	// write header
	for _, b := range p.blobs {
		entry := headerEntry{
			Type:   b.Type,
			Length: b.Length,
		}
		copy(entry.ID[:], b.ID)

		err := binary.Write(wr, binary.LittleEndian, entry)
		if err != nil {
			return int64(n), err
		}

		n += int64(entrySize)
	}

	// finalize encrypted header
	err := wr.Close()
	if err != nil {
		return int64(n), err
	}

	// account for crypto overhead
	n += crypto.Extension

	// write length
	err = binary.Write(p.hw, binary.LittleEndian, uint32(len(p.blobs)*entrySize+crypto.Extension))
	if err != nil {
		return int64(n), err
	}
	n += int64(binary.Size(uint32(0)))

	p.bytes = uint(n)

	return n, nil
}

// ID returns the ID of all data written so far.
func (p *Packer) ID() backend.ID {
	p.m.Lock()
	defer p.m.Unlock()

	return p.hw.Sum(nil)
}

// Size returns the number of bytes written so far.
func (p *Packer) Size() uint {
	p.m.Lock()
	defer p.m.Unlock()

	return p.bytes
}

// Count returns the number of blobs in this packer.
func (p *Packer) Count() int {
	p.m.Lock()
	defer p.m.Unlock()

	return len(p.blobs)
}

// Blobs returns the slice of blobs that have been written.
func (p *Packer) Blobs() []Blob {
	p.m.Lock()
	defer p.m.Unlock()

	return p.blobs
}

// Writer returns the underlying writer.
func (p *Packer) Writer() io.Writer {
	return p.wr
}

func (p *Packer) String() string {
	return fmt.Sprintf("<Packer %d blobs, %d bytes>", len(p.blobs), p.bytes)
}

// Unpacker is used to read individual blobs from a pack.
type Unpacker struct {
	rd      io.ReadSeeker
	Entries []Blob
	k       *crypto.Key
}

// NewUnpacker returns a pointer to Unpacker which can be used to read
// individual Blobs from a pack.
func NewUnpacker(k *crypto.Key, entries []Blob, rd io.ReadSeeker) (*Unpacker, error) {
	var err error
	ls := binary.Size(uint32(0))

	// reset to the end to read header length
	_, err = rd.Seek(-int64(ls), 2)
	if err != nil {
		return nil, fmt.Errorf("seeking to read header length failed: %v", err)
	}

	// read length
	var l uint32
	err = binary.Read(rd, binary.LittleEndian, &l)
	if err != nil {
		return nil, fmt.Errorf("reading header length failed: %v", err)
	}

	// reset to the beginning of the header
	_, err = rd.Seek(-int64(ls)-int64(l), 2)
	if err != nil {
		return nil, fmt.Errorf("seeking to read header length failed: %v", err)
	}

	// read header
	hrd, err := crypto.DecryptFrom(k, io.LimitReader(rd, int64(l)))
	if err != nil {
		return nil, err
	}

	if entries == nil {
		pos := uint(0)
		for {
			e := headerEntry{}
			err = binary.Read(hrd, binary.LittleEndian, &e)
			if err == io.EOF {
				break
			}

			if err != nil {
				return nil, err
			}

			entries = append(entries, Blob{
				Type:   e.Type,
				Length: e.Length,
				ID:     e.ID[:],
				Offset: pos,
			})

			pos += uint(e.Length)
		}
	}

	p := &Unpacker{
		rd:      rd,
		k:       k,
		Entries: entries,
	}

	return p, nil
}
<commit_msg>pack: Close encrypting writer on error<commit_after>package pack

import (
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/crypto"
)

type BlobType uint8

const (
	Data BlobType = 0
	Tree          = 1
)

func (t BlobType) String() string {
	switch t {
	case Data:
		return "data"
	case Tree:
		return "tree"
	}

	return fmt.Sprintf("<BlobType %d>", t)
}

func (t BlobType) MarshalJSON() ([]byte, error) {
	switch t {
	case Data:
		return []byte(`"data"`), nil
	case Tree:
		return []byte(`"tree"`), nil
	}

	return nil, errors.New("unknown blob type")
}

func (t *BlobType) UnmarshalJSON(buf []byte) error {
	switch string(buf) {
	case `"data"`:
		*t = Data
	case `"tree"`:
		*t = Tree
	default:
		return errors.New("unknown blob type")
	}

	return nil
}

// Blob is a blob within a pack.
type Blob struct {
	Type   BlobType
	Length uint32
	ID     backend.ID
	Offset uint
}

// GetReader returns an io.Reader for the blob entry e.
func (e Blob) GetReader(rd io.ReadSeeker) (io.Reader, error) {
	// seek to the correct location
	_, err := rd.Seek(int64(e.Offset), 0)
	if err != nil {
		return nil, err
	}

	return io.LimitReader(rd, int64(e.Length)), nil
}

// Packer is used to create a new Pack.
type Packer struct {
	blobs []Blob

	bytes uint
	k     *crypto.Key
	wr    io.Writer
	hw    *backend.HashingWriter

	m sync.Mutex
}

// NewPacker returns a new Packer that can be used to pack blobs
// together.
func NewPacker(k *crypto.Key, w io.Writer) *Packer {
	return &Packer{k: k, wr: w, hw: backend.NewHashingWriter(w, sha256.New())}
}

// Add saves the data read from rd as a new blob to the packer. Returned is the
// number of bytes written to the pack.
func (p *Packer) Add(t BlobType, id backend.ID, rd io.Reader) (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	c := Blob{Type: t, ID: id}

	n, err := io.Copy(p.hw, rd)
	c.Length = uint32(n)
	c.Offset = p.bytes
	p.bytes += uint(n)
	p.blobs = append(p.blobs, c)

	return n, err
}

var entrySize = binary.Size(BlobType(0)) + binary.Size(uint32(0)) + backend.IDSize

// headerEntry is used with encoding/binary to read and write header entries
type headerEntry struct {
	Type   BlobType
	Length uint32
	ID     [backend.IDSize]byte
}

// Finalize writes the header for all added blobs and finalizes the pack.
// Returned are the complete number of bytes written, including the header.
// After Finalize() has finished, the ID of this pack can be obtained by
// calling ID().
func (p *Packer) Finalize() (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	// n tracks the number of bytes written for the header
	var n int64 = int64(p.bytes)

	// create writer to encrypt header
	wr := crypto.EncryptTo(p.k, p.hw)

	// write header
	for _, b := range p.blobs {
		entry := headerEntry{
			Type:   b.Type,
			Length: b.Length,
		}
		copy(entry.ID[:], b.ID)

		err := binary.Write(wr, binary.LittleEndian, entry)
		if err != nil {
			wr.Close()
			return int64(n), err
		}

		n += int64(entrySize)
	}

	// finalize encrypted header
	err := wr.Close()
	if err != nil {
		return int64(n), err
	}

	// account for crypto overhead
	n += crypto.Extension

	// write length
	err = binary.Write(p.hw, binary.LittleEndian, uint32(len(p.blobs)*entrySize+crypto.Extension))
	if err != nil {
		return int64(n), err
	}
	n += int64(binary.Size(uint32(0)))

	p.bytes = uint(n)

	return n, nil
}

// ID returns the ID of all data written so far.
func (p *Packer) ID() backend.ID {
	p.m.Lock()
	defer p.m.Unlock()

	return p.hw.Sum(nil)
}

// Size returns the number of bytes written so far.
func (p *Packer) Size() uint {
	p.m.Lock()
	defer p.m.Unlock()

	return p.bytes
}

// Count returns the number of blobs in this packer.
func (p *Packer) Count() int {
	p.m.Lock()
	defer p.m.Unlock()

	return len(p.blobs)
}

// Blobs returns the slice of blobs that have been written.
func (p *Packer) Blobs() []Blob {
	p.m.Lock()
	defer p.m.Unlock()

	return p.blobs
}

// Writer returns the underlying writer.
func (p *Packer) Writer() io.Writer {
	return p.wr
}

func (p *Packer) String() string {
	return fmt.Sprintf("<Packer %d blobs, %d bytes>", len(p.blobs), p.bytes)
}

// Unpacker is used to read individual blobs from a pack.
type Unpacker struct {
	rd      io.ReadSeeker
	Entries []Blob
	k       *crypto.Key
}

// NewUnpacker returns a pointer to Unpacker which can be used to read
// individual Blobs from a pack.
func NewUnpacker(k *crypto.Key, entries []Blob, rd io.ReadSeeker) (*Unpacker, error) {
	var err error
	ls := binary.Size(uint32(0))

	// reset to the end to read header length
	_, err = rd.Seek(-int64(ls), 2)
	if err != nil {
		return nil, fmt.Errorf("seeking to read header length failed: %v", err)
	}

	// read length
	var l uint32
	err = binary.Read(rd, binary.LittleEndian, &l)
	if err != nil {
		return nil, fmt.Errorf("reading header length failed: %v", err)
	}

	// reset to the beginning of the header
	_, err = rd.Seek(-int64(ls)-int64(l), 2)
	if err != nil {
		return nil, fmt.Errorf("seeking to read header length failed: %v", err)
	}

	// read header
	hrd, err := crypto.DecryptFrom(k, io.LimitReader(rd, int64(l)))
	if err != nil {
		return nil, err
	}

	if entries == nil {
		pos := uint(0)
		for {
			e := headerEntry{}
			err = binary.Read(hrd, binary.LittleEndian, &e)
			if err == io.EOF {
				break
			}

			if err != nil {
				return nil, err
			}

			entries = append(entries, Blob{
				Type:   e.Type,
				Length: e.Length,
				ID:     e.ID[:],
				Offset: pos,
			})

			pos += uint(e.Length)
		}
	}

	p := &Unpacker{
		rd:      rd,
		k:       k,
		Entries: entries,
	}

	return p, nil
}
<|endoftext|>


<commit_before>package v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
)

const (
	GroupVersion              = "v1alpha1" // version used in the Scheme for subscriptions
	SubscriptionKind          = "Subscription-v1"
	SubscriptionListKind      = "SubscriptionList-v1"
	SubscriptionCRDName       = "subscription-v1s.app.coreos.com"
	SubscriptionCRDAPIVersion = "apiextensions.k8s.io/v1beta1" // API version w/ CRD support
)

// SubscriptionState tracks when updates are available, installing, or service is up to date
type SubscriptionState string

const (
	SubscriptionStateNone             = ""
	SubscriptionStateUpgradeAvailable = "UpgradeAvailable"
	SubscriptionStateUpgradePending   = "UpgradePending"
	SubscriptionStateAtLatest         = "AtLatestKnown"
)

// SubscriptionSpec defines an Application that can be installed
type SubscriptionSpec struct {
	CatalogSource string `json:"source"`
	Package       string `json:"name"`
	Channel       string `json:"channel,omitempty"`

	StartingCSV string `json:"nextCSV,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Custom Resource of type "SubscriptionSpec"
type Subscription struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`

	Spec   *SubscriptionSpec  `json:"spec"`
	Status SubscriptionStatus `json:"status"`
}

type SubscriptionStatus struct {
	metav1.Status `json:",inline"`

	CurrentCSV string                `json:"installedCSV"`
	Install    *InstallPlanReference `json:"installplan"`

	State       SubscriptionState `json:"state"`
	LastUpdated metav1.Time       `json:"lastUpdated"`
}

type InstallPlanReference struct {
	APIVersion string    `json:"apiVersion"`
	Kind       string    `json:"kind"`
	Name       string    `json:"name"`
	UID        types.UID `json:"uuid"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type SubscriptionList struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`

	Items []*SubscriptionSpec `json:"items"`
}
<commit_msg>fixup(apis/subscription): use the sane json tag<commit_after>package v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
)

const (
	GroupVersion              = "v1alpha1" // version used in the Scheme for subscriptions
	SubscriptionKind          = "Subscription-v1"
	SubscriptionListKind      = "SubscriptionList-v1"
	SubscriptionCRDName       = "subscription-v1s.app.coreos.com"
	SubscriptionCRDAPIVersion = "apiextensions.k8s.io/v1beta1" // API version w/ CRD support
)

// SubscriptionState tracks when updates are available, installing, or service is up to date
type SubscriptionState string

const (
	SubscriptionStateNone             = ""
	SubscriptionStateUpgradeAvailable = "UpgradeAvailable"
	SubscriptionStateUpgradePending   = "UpgradePending"
	SubscriptionStateAtLatest         = "AtLatestKnown"
)

// SubscriptionSpec defines an Application that can be installed
type SubscriptionSpec struct {
	CatalogSource string `json:"source"`
	Package       string `json:"name"`
	Channel       string `json:"channel,omitempty"`

	StartingCSV string `json:"startingCSV,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Custom Resource of type "SubscriptionSpec"
type Subscription struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`

	Spec   *SubscriptionSpec  `json:"spec"`
	Status SubscriptionStatus `json:"status"`
}

type SubscriptionStatus struct {
	metav1.Status `json:",inline"`

	CurrentCSV string                `json:"installedCSV"`
	Install    *InstallPlanReference `json:"installplan"`

	State       SubscriptionState `json:"state"`
	LastUpdated metav1.Time       `json:"lastUpdated"`
}

type InstallPlanReference struct {
	APIVersion string    `json:"apiVersion"`
	Kind       string    `json:"kind"`
	Name       string    `json:"name"`
	UID        types.UID `json:"uuid"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type SubscriptionList struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`

	Items []*SubscriptionSpec `json:"items"`
}
<|endoftext|>


<commit_before><commit_msg>fix description of command kubectl cluster-info dump<commit_after><|endoftext|>


<commit_before>package kproc

import (
	"context"
	"os/exec"
)

func CommandContext(ctx context.Context, name string, arg ...string) *KCmd {
	return &KCmd{
		Cmd: cmd,
		ctx: ctx,
	}
}

func (k *KCmd) KillAll() {
	if k.Process == nil {
		return
	}
	c := exec.Command("taskkill", "/t", "/f", "/pid", k.Process.Pid)
	c.Stdout = k.Cmd.Stdout
	c.Stderr = k.Cmd.Stderr
}

func (k *KCmd) Wait() error {
	defer k.KillAll()
	go func() {
		select {
		case <-k.ctx.Done():
			k.KillAll()
		}
	}()
	return k.Cmd.Wait()
}
<commit_msg>更新windows编译<commit_after>package kproc

import (
	"context"
	"fmt"
	"os/exec"
)

func CommandContext(ctx context.Context, name string, arg ...string) *KCmd {
	return &KCmd{
		Cmd: cmd,
		ctx: ctx,
	}
}

func (k *KCmd) KillAll() {
	if k.Process == nil {
		return
	}
	c := exec.Command("taskkill", "/t", "/f", "/pid", fmt.Sprint(k.Process.Pid))
	c.Stdout = k.Cmd.Stdout
	c.Stderr = k.Cmd.Stderr
}

func (k *KCmd) Wait() error {
	defer k.KillAll()
	go func() {
		select {
		case <-k.ctx.Done():
			k.KillAll()
		}
	}()
	return k.Cmd.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"github.com/pterodactyl/wings/server"
	"net/http"
)

type Router struct {
	Servers []*server.Server
}

func (r *Router) routeIndex(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
	fmt.Fprint(w, "Welcome!\n")
}

func (r *Router) routeAllServers(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
	enc := json.NewEncoder(w)
	enc.Encode(r.Servers)
}

func (r *Router) ConfigureRouter() *httprouter.Router {
	router := httprouter.New()

	router.GET("/", r.routeIndex)

	router.GET("/api/servers", r.routeAllServers)
	// router.GET("/api/servers/:server", r.routeServer)

	return router
}<commit_msg>Add basic API endpoints to get server data<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"github.com/pterodactyl/wings/server"
	"net/http"
)

type ServerCollection []*server.Server

// Retrieves a server out of the collection by UUID.
func (sc *ServerCollection) Get(uuid string) *server.Server {
	for _, s := range *sc {
		if s.Uuid == uuid {
			return s
		}
	}

	return nil
}

type Router struct {
	Servers ServerCollection
}

// Middleware to protect server specific routes. This will ensure that the server exists and
// is in a state that allows it to be exposed to the API.
func (rt *Router) AuthenticateServer(h httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		if rt.Servers.Get(ps.ByName("server")) != nil {
			h(w, r, ps)
			return
		}

		http.NotFound(w, r)
	}
}

// Returns the basic Wings index page without anything else.
func (rt *Router) routeIndex(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
	fmt.Fprint(w, "Welcome!\n")
}

// Returns all of the servers that exist on the Daemon. This route is only accessible to
// requests that include an administrative control key, otherwise a 404 is returned. This
// authentication is handled by a middleware.
func (rt *Router) routeAllServers(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
	json.NewEncoder(w).Encode(rt.Servers)
}

// Returns basic information about a single server found on the Daemon.
func (rt *Router) routeServer(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) {
	s := rt.Servers.Get(ps.ByName("server"))

	json.NewEncoder(w).Encode(s)
}

func (rt *Router) ConfigureRouter() *httprouter.Router {
	router := httprouter.New()

	router.GET("/", rt.routeIndex)
	router.GET("/api/servers", rt.routeAllServers)
	router.GET("/api/servers/:server", rt.AuthenticateServer(rt.routeServer))

	return router
}<|endoftext|>


<commit_before>package data

import "reflect"

// Value is an interface to represent
// the type of a value for a key/value store.
type Value interface {
	//	IsBool() bool
	Bool() bool
	IsInt() bool
	Int() int64
	IsUint() bool
	Uint() uint64
	IsFloat() bool
	Float() float64
	IsString() bool
	String() string
	Interface() interface{}
	ReflectValue() *reflect.Value
}

func IsSimpleData(v Value) bool {
	switch {
	//	case v.IsInt():
	//		return true
	case v.IsFloat():
		return true
	case v.IsString():
		return true
	default:
		return false
	}
}

// A ComparableValue is composed of a Comparable and a Value.
type ComparableValue interface {
	Comparable
	Value
}
<commit_msg>Fixed.<commit_after>package data

import (
	"reflect"
)

// Value is an interface to represent
// the type of a value for a key/value store.
// TODO: (Maybe) either ...
// 1) Throw away completely and just use reflect.Value or ...
// 2) Convert to a struct embedding reflect.Value and just add
//    IsSimpleData
type Value interface {
	IsBool() bool
	Bool() bool
	IsInt() bool
	Int() int64
	IsUint() bool
	Uint() uint64
	IsFloat() bool
	Float() float64
	IsString() bool
	String() string
	Interface() interface{}
	ReflectValue() *reflect.Value
}

func IsSimpleData(v Value) bool {
	switch {
	case v.IsBool():
		return true
	case v.IsInt():
		return true
	case v.IsUint():
		return true
	case v.IsFloat():
		return true
	case v.IsString():
		return true
	default:
		return false
	}
}

// A ComparableValue is composed of a Comparable and a Value.
type ComparableValue interface {
	Comparable
	Value
}
<|endoftext|>