<commit_before>package beertasting

import (
	"appengine"
	"appengine/datastore"
	"appengine/urlfetch"
	"appengine/user"
	"encoding/json"
	"fmt"
	"github.com/ant0ine/go-json-rest/rest"
	"html/template"
	"io/ioutil"
	"net/http"
	"net/url"
)

func init() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/search", searchHandler)
	http.HandleFunc("/feed", feedHandler)
	http.HandleFunc("/admin/untappd/client_id", clientIdHandler)
	http.HandleFunc("/admin/untappd/client_secret", clientSecretHandler)
	http.HandleFunc("/oauth/untappd", oauthUntappdHandler)
	restHandler := rest.ResourceHandler{}
	restHandler.SetRoutes(
		&rest.Route{"GET", "/admin/whitelist", getAdminWhitelist},
		&rest.Route{"PUT", "/admin/whitelist", putAdminWhitelist},
	)
	http.Handle("/admin/whitelist", &restHandler)
}

const (
	endpoint = "http://api.untappd.com/v4"
)

type ClientId struct {
	Value string
}

type ClientSecret struct {
	Value string
}

type Whitelist struct {
	Value []string
}

func clientIdKey(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "ClientId", "default", 0, nil)
}

func clientSecretKey(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "ClientSecret", "default", 0, nil)
}

func whitelistKey(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "Whitelist", "default", 0, nil)
}

func getClientId(c appengine.Context) (ClientId, error) {
	var clientId ClientId
	err := datastore.Get(c, clientIdKey(c), &clientId)
	return clientId, err
}

func getClientSecret(c appengine.Context) (ClientSecret, error) {
	var clientSecret ClientSecret
	err := datastore.Get(c, clientSecretKey(c), &clientSecret)
	return clientSecret, err
}

func getWhitelist(c appengine.Context) (Whitelist, error) {
	var whitelist Whitelist
	err := datastore.Get(c, whitelistKey(c), &whitelist)
	return whitelist, err
}

func oauthCallback(c appengine.Context, svc string) string {
	var u url.URL
	u.Scheme = "http"
	u.Host = appengine.DefaultVersionHostname(c)
	u.Path = fmt.Sprintf("oauth/%s", svc)
	return u.String()
}

func userLoggedIn(c appengine.Context, curUrl *url.URL, w http.ResponseWriter) (*user.User, bool) {
	u := user.Current(c)
	if u != nil {
		return u, true
	}
	url, err := user.LoginURL(c, curUrl.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return nil, false
	}
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusFound)
	return nil, false
}

func handler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	user, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	fmt.Fprintf(w, "Welcome, %s", user)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	user, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	var err error
	var whitelist Whitelist
	if err = datastore.Get(c, whitelistKey(c), &whitelist); err != nil {
		if err == datastore.ErrNoSuchEntity {
			c.Infof("whitelist not found, using test@example.com")
			whitelist.Value = []string{"test@example.com"}
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
	//	records, err := csv.NewReader(strings.NewReader(whitelist.Value)).Read()
	records := []string{}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	found := false
	for _, record := range records {
		if record == user.Email {
			found = true
			break
		}
	}
	if !found {
		http.Error(w, fmt.Sprintf("user %s not in whitelist", user), http.StatusInternalServerError)
		return
	}

	var clientId ClientId
	if clientId, err = getClientId(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	t, err := template.ParseFiles("templates/trial1.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	var clientSecret ClientSecret
	if clientSecret, err = getClientSecret(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	s := struct{ Name, Endpoint, ClientId, ClientSecret string }{user.String(), endpoint, clientId.Value, clientSecret.Value}
	if err := t.Execute(w, s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func oauthUntappdHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	_, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	if len(r.FormValue("code")) == 0 {
		http.Error(w, "missing code parameter", http.StatusInternalServerError)
	}
	clientId, err := getClientId(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	clientSecret, err := getClientSecret(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	u := url.URL{Scheme: "https", Host: "untappd.com", Path: "oauth/authorize/"}
	q := u.Query()
	q.Add("client_id", clientId.Value)
	q.Add("client_secret", clientSecret.Value)
	q.Add("response_type", "code")
	q.Add("code", r.FormValue("code"))
	q.Add("redirect_url", oauthCallback(c, "untappd"))
	u.RawQuery = q.Encode()
	resp, err := urlfetch.Client(c).Get(u.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	oauthResponse := struct {
		Response struct {
			AccessToken string `json:"access_token"`
		}
	}{}
	err = json.Unmarshal(buf, &oauthResponse)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	u = url.URL{Scheme: "https", Host: "api.untappd.com", Path: "/v4/checkin/recent"}
	q = u.Query()
	q.Add("access_token", oauthResponse.Response.AccessToken)
	u.RawQuery = q.Encode()
	client := urlfetch.Client(c)
	resp, err = client.Get(u.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	resp.Write(w)
}

func feedHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	_, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	var err error
	var clientId ClientId
	if clientId, err = getClientId(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var untappdOath url.URL
	untappdOath.Scheme = "https"
	untappdOath.Host = "untappd.com"
	untappdOath.Path = "oauth/authenticate/"
	q := untappdOath.Query()
	q.Add("client_id", clientId.Value)
	q.Add("response_type", "code")
	q.Add("redirect_url", oauthCallback(c, "untappd"))
	untappdOath.RawQuery = q.Encode()
	http.Redirect(w, r, untappdOath.String(), http.StatusFound)
	return
}

func clientIdHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	switch r.Method {
	case "PUT":
		var clientId ClientId
		clientId.Value = r.FormValue("value")
		if _, err := datastore.Put(c, clientIdKey(c), &clientId); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	case "GET":
		var clientId ClientId
		if err := datastore.Get(c, clientIdKey(c), &clientId); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintln(w, clientId)
	default:
		http.Error(w, fmt.Sprintf("Unhandled method: %s", r.Method), http.StatusInternalServerError)
	}
}

func clientSecretHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	switch r.Method {
	case "PUT":
		var clientSecret ClientSecret
		clientSecret.Value = r.FormValue("value")
		if _, err := datastore.Put(c, clientSecretKey(c), &clientSecret); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	case "GET":
		var clientSecret ClientSecret
		if err := datastore.Get(c, clientSecretKey(c), &clientSecret); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintln(w, clientSecret)
	default:
		http.Error(w, fmt.Sprintf("Unhandled method: %s", r.Method), http.StatusInternalServerError)
	}
}

func putAdminWhitelist(w rest.ResponseWriter, r *rest.Request) {
	c := appengine.NewContext(r.Request)
	var wl []string
	err := r.DecodeJsonPayload(&wl)
	if err != nil {
		err = fmt.Errorf("DecodeJsonPayload(): %s", err)
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var whitelist Whitelist
	whitelist.Value = wl
	if _, err := datastore.Put(c, whitelistKey(c), &whitelist); err != nil {
		err = fmt.Errorf("datastore.Put(): %s", err)
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteJson(wl)
}

func getAdminWhitelist(w rest.ResponseWriter, r *rest.Request) {
	c := appengine.NewContext(r.Request)
	var whitelist Whitelist
	if err := datastore.Get(c, whitelistKey(c), &whitelist); err != nil {
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteJson(whitelist.Value)
}
<commit_msg>simplify configuration<commit_after>package beertasting

import (
	"appengine"
	"appengine/datastore"
	"appengine/urlfetch"
	"appengine/user"
	"encoding/json"
	"fmt"
	"github.com/ant0ine/go-json-rest/rest"
	"html/template"
	"io/ioutil"
	"net/http"
	"net/url"
)

func init() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/search", searchHandler)
	http.HandleFunc("/feed", feedHandler)
	http.HandleFunc("/oauth/untappd", oauthUntappdHandler)
	restHandler := rest.ResourceHandler{}
	restHandler.SetRoutes(
		&rest.Route{"GET", "/admin/config", getAdminConfig},
		&rest.Route{"PUT", "/admin/config", putAdminConfig},
	)
	http.Handle("/admin/config", &restHandler)
}

const (
	endpoint = "http://api.untappd.com/v4"
)

type Config struct {
	ClientId     string
	ClientSecret string
	Whitelist    []string
}

func configKey(c appengine.Context) *datastore.Key {
	return datastore.NewKey(c, "Config", "default", 0, nil)
}

func getConfig(c appengine.Context) (Config, error) {
	var cfg Config
	err := datastore.Get(c, configKey(c), &cfg)
	return cfg, err
}

func oauthCallback(c appengine.Context, svc string) string {
	var u url.URL
	u.Scheme = "http"
	u.Host = appengine.DefaultVersionHostname(c)
	u.Path = fmt.Sprintf("oauth/%s", svc)
	return u.String()
}

func userLoggedIn(c appengine.Context, curUrl *url.URL, w http.ResponseWriter) (*user.User, bool) {
	u := user.Current(c)
	if u != nil {
		return u, true
	}
	url, err := user.LoginURL(c, curUrl.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return nil, false
	}
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusFound)
	return nil, false
}

func handler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	user, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	fmt.Fprintf(w, "Welcome, %s", user)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	user, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	var err error
	var config Config
	if config, err = getConfig(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if len(config.Whitelist) == 0 {
		c.Infof("whitelist not found, using test@example.com")
		config.Whitelist = []string{"test@example.com"}
	}
	found := false
	for _, record := range config.Whitelist {
		if record == user.Email {
			found = true
			break
		}
	}
	if !found {
		http.Error(w, fmt.Sprintf("user %s not in whitelist", user), http.StatusInternalServerError)
		return
	}

	t, err := template.ParseFiles("templates/trial1.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	s := struct{ Name, Endpoint, ClientId, ClientSecret string }{
		user.String(),
		endpoint,
		config.ClientId,
		config.ClientSecret,
	}
	if err := t.Execute(w, s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func oauthUntappdHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	_, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	if len(r.FormValue("code")) == 0 {
		http.Error(w, "missing code parameter", http.StatusInternalServerError)
	}
	var config Config
	var err error
	if config, err = getConfig(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	u := url.URL{Scheme: "https", Host: "untappd.com", Path: "oauth/authorize/"}
	q := u.Query()
	q.Add("client_id", config.ClientId)
	q.Add("client_secret", config.ClientSecret)
	q.Add("response_type", "code")
	q.Add("code", r.FormValue("code"))
	q.Add("redirect_url", oauthCallback(c, "untappd"))
	u.RawQuery = q.Encode()
	resp, err := urlfetch.Client(c).Get(u.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	oauthResponse := struct {
		Response struct {
			AccessToken string `json:"access_token"`
		}
	}{}
	err = json.Unmarshal(buf, &oauthResponse)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	u = url.URL{Scheme: "https", Host: "api.untappd.com", Path: "/v4/checkin/recent"}
	q = u.Query()
	q.Add("access_token", oauthResponse.Response.AccessToken)
	u.RawQuery = q.Encode()
	client := urlfetch.Client(c)
	resp, err = client.Get(u.String())
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	resp.Write(w)
}

func feedHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	_, ok := userLoggedIn(c, r.URL, w)
	if !ok {
		return
	}
	var config Config
	var err error
	if config, err = getConfig(c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	var untappdOath url.URL
	untappdOath.Scheme = "https"
	untappdOath.Host = "untappd.com"
	untappdOath.Path = "oauth/authenticate/"
	q := untappdOath.Query()
	q.Add("client_id", config.ClientId)
	q.Add("response_type", "code")
	q.Add("redirect_url", oauthCallback(c, "untappd"))
	untappdOath.RawQuery = q.Encode()
	http.Redirect(w, r, untappdOath.String(), http.StatusFound)
	return
}

func putAdminConfig(w rest.ResponseWriter, r *rest.Request) {
	c := appengine.NewContext(r.Request)
	var config Config
	err := r.DecodeJsonPayload(&config)
	if err != nil {
		err = fmt.Errorf("DecodeJsonPayload(): %s", err)
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := datastore.Put(c, configKey(c), &config); err != nil {
		err = fmt.Errorf("datastore.Put(): %s", err)
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err = w.WriteJson(config); err != nil {
		rest.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func getAdminConfig(w rest.ResponseWriter, r *rest.Request) {
	c := appengine.NewContext(r.Request)
	var config Config
	if err := datastore.Get(c, configKey(c), &config); err != nil {
		rest.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err := w.WriteJson(config); err != nil {
		rest.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package config

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"strings"

	"github.com/juju/persistent-cookiejar"
	schemaform "gopkg.in/juju/environschema.v1/form"
	"gopkg.in/macaroon-bakery.v2/httpbakery"
	"gopkg.in/macaroon-bakery.v2/httpbakery/form"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared"
)

// Remote holds details for communication with a remote daemon
type Remote struct {
	Addr     string `yaml:"addr"`
	AuthType string `yaml:"auth_type,omitempty"`
	Domain   string `yaml:"domain,omitempty"`
	Project  string `yaml:"project,omitempty"`
	Protocol string `yaml:"protocol,omitempty"`
	Public   bool   `yaml:"public"`
	Static   bool   `yaml:"-"`
}

// ParseRemote splits remote and object
func (c *Config) ParseRemote(raw string) (string, string, error) {
	result := strings.SplitN(raw, ":", 2)
	if len(result) == 1 {
		return c.DefaultRemote, raw, nil
	}

	_, ok := c.Remotes[result[0]]
	if !ok {
		// Attempt to play nice with snapshots containing ":"
		if shared.IsSnapshot(raw) && strings.Contains(result[0], "/") {
			return c.DefaultRemote, raw, nil
		}

		return "", "", fmt.Errorf("The remote \"%s\" doesn't exist", result[0])
	}

	return result[0], result[1], nil
}

// GetContainerServer returns a ContainerServer struct for the remote
func (c *Config) GetContainerServer(name string) (lxd.ContainerServer, error) {
	// Get the remote
	remote, ok := c.Remotes[name]
	if !ok {
		return nil, fmt.Errorf("The remote \"%s\" doesn't exist", name)
	}

	// Sanity checks
	if remote.Public || remote.Protocol == "simplestreams" {
		return nil, fmt.Errorf("The remote isn't a private LXD server")
	}

	// Get connection arguments
	args, err := c.getConnectionArgs(name)
	if err != nil {
		return nil, err
	}

	// Unix socket
	if strings.HasPrefix(remote.Addr, "unix:") {
		d, err := lxd.ConnectLXDUnix(strings.TrimPrefix(strings.TrimPrefix(remote.Addr, "unix:"), "//"), args)
		if err != nil {
			return nil, err
		}

		if remote.Project != "" && remote.Project != "default" {
			d = d.UseProject(remote.Project)
		}

		if c.ProjectOverride != "" {
			d = d.UseProject(c.ProjectOverride)
		}

		return d, nil
	}

	// HTTPs
	if remote.AuthType != "candid" && (args.TLSClientCert == "" || args.TLSClientKey == "") {
		return nil, fmt.Errorf("Missing TLS client certificate and key")
	}

	d, err := lxd.ConnectLXD(remote.Addr, args)
	if err != nil {
		return nil, err
	}

	if remote.Project != "" && remote.Project != "default" {
		d = d.UseProject(remote.Project)
	}

	if c.ProjectOverride != "" {
		d = d.UseProject(c.ProjectOverride)
	}

	return d, nil
}

// GetImageServer returns a ImageServer struct for the remote
func (c *Config) GetImageServer(name string) (lxd.ImageServer, error) {
	// Get the remote
	remote, ok := c.Remotes[name]
	if !ok {
		return nil, fmt.Errorf("The remote \"%s\" doesn't exist", name)
	}

	// Get connection arguments
	args, err := c.getConnectionArgs(name)
	if err != nil {
		return nil, err
	}

	// Unix socket
	if strings.HasPrefix(remote.Addr, "unix:") {
		d, err := lxd.ConnectLXDUnix(strings.TrimPrefix(strings.TrimPrefix(remote.Addr, "unix:"), "//"), args)
		if err != nil {
			return nil, err
		}

		if remote.Project != "" && remote.Project != "default" {
			d = d.UseProject(remote.Project)
		}

		if c.ProjectOverride != "" {
			d = d.UseProject(c.ProjectOverride)
		}

		return d, nil
	}

	// HTTPs (simplestreams)
	if remote.Protocol == "simplestreams" {
		d, err := lxd.ConnectSimpleStreams(remote.Addr, args)
		if err != nil {
			return nil, err
		}

		return d, nil
	}

	// HTTPs (public LXD)
	if remote.Public {
		d, err := lxd.ConnectPublicLXD(remote.Addr, args)
		if err != nil {
			return nil, err
		}

		return d, nil
	}

	// HTTPs (private LXD)
	d, err := lxd.ConnectLXD(remote.Addr, args)
	if err != nil {
		return nil, err
	}

	if remote.Project != "" && remote.Project != "default" {
		d = d.UseProject(remote.Project)
	}

	if c.ProjectOverride != "" {
		d = d.UseProject(c.ProjectOverride)
	}

	return d, nil
}

func (c *Config) getConnectionArgs(name string) (*lxd.ConnectionArgs, error) {
	remote, _ := c.Remotes[name]
	args := lxd.ConnectionArgs{
		UserAgent: c.UserAgent,
		AuthType:  remote.AuthType,
	}

	if args.AuthType == "candid" {
		args.AuthInteractor = []httpbakery.Interactor{
			form.Interactor{Filler: schemaform.IOFiller{}},
			httpbakery.WebBrowserInteractor{
				OpenWebBrowser: func(uri *url.URL) error {
					if remote.Domain != "" {
						query := uri.Query()
						query.Set("domain", remote.Domain)
						uri.RawQuery = query.Encode()
					}

					return httpbakery.OpenWebBrowser(uri)
				},
			},
		}

		if c.cookieJars == nil || c.cookieJars[name] == nil {
			if !shared.PathExists(c.ConfigPath("jars")) {
				err := os.MkdirAll(c.ConfigPath("jars"), 0700)
				if err != nil {
					return nil, err
				}
			}

			if !shared.PathExists(c.CookiesPath(name)) {
				if shared.PathExists(c.ConfigPath("cookies")) {
					err := shared.FileCopy(c.ConfigPath("cookies"), c.CookiesPath(name))
					if err != nil {
						return nil, err
					}
				}
			}

			jar, err := cookiejar.New(
				&cookiejar.Options{
					Filename: c.CookiesPath(name),
				})
			if err != nil {
				return nil, err
			}

			if c.cookieJars == nil {
				c.cookieJars = map[string]*cookiejar.Jar{}
			}
			c.cookieJars[name] = jar
		}

		args.CookieJar = c.cookieJars[name]
	}

	// Stop here if no TLS involved
	if strings.HasPrefix(remote.Addr, "unix:") {
		return &args, nil
	}

	// Server certificate
	if shared.PathExists(c.ServerCertPath(name)) {
		content, err := ioutil.ReadFile(c.ServerCertPath(name))
		if err != nil {
			return nil, err
		}

		args.TLSServerCert = string(content)
	}

	// Stop here if no client certificate involved
	if remote.Protocol == "simplestreams" || remote.AuthType == "candid" {
		return &args, nil
	}

	// Client certificate
	if shared.PathExists(c.ConfigPath("client.crt")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.crt"))
		if err != nil {
			return nil, err
		}

		args.TLSClientCert = string(content)
	}

	// Client CA
	if shared.PathExists(c.ConfigPath("client.ca")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.ca"))
		if err != nil {
			return nil, err
		}

		args.TLSCA = string(content)
	}

	// Client key
	if shared.PathExists(c.ConfigPath("client.key")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.key"))
		if err != nil {
			return nil, err
		}

		pemKey, _ := pem.Decode(content)
		if x509.IsEncryptedPEMBlock(pemKey) {
			if c.PromptPassword == nil {
				return nil, fmt.Errorf("Private key is password protected and no helper was configured")
			}

			password, err := c.PromptPassword("client.crt")
			if err != nil {
				return nil, err
			}

			derKey, err := x509.DecryptPEMBlock(pemKey, []byte(password))
			if err != nil {
				return nil, err
			}

			content = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: derKey})
		}

		args.TLSClientKey = string(content)
	}

	return &args, nil
}
<commit_msg>lxc/config: Use shared.IsSnapshot<commit_after>package config

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"strings"

	"github.com/juju/persistent-cookiejar"
	schemaform "gopkg.in/juju/environschema.v1/form"
	"gopkg.in/macaroon-bakery.v2/httpbakery"
	"gopkg.in/macaroon-bakery.v2/httpbakery/form"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared"
)

// Remote holds details for communication with a remote daemon
type Remote struct {
	Addr     string `yaml:"addr"`
	AuthType string `yaml:"auth_type,omitempty"`
	Domain   string `yaml:"domain,omitempty"`
	Project  string `yaml:"project,omitempty"`
	Protocol string `yaml:"protocol,omitempty"`
	Public   bool   `yaml:"public"`
	Static   bool   `yaml:"-"`
}

// ParseRemote splits remote and object
func (c *Config) ParseRemote(raw string) (string, string, error) {
	result := strings.SplitN(raw, ":", 2)
	if len(result) == 1 {
		return c.DefaultRemote, raw, nil
	}

	_, ok := c.Remotes[result[0]]
	if !ok {
		// Attempt to play nice with snapshots containing ":"
		if shared.IsSnapshot(raw) && shared.IsSnapshot(result[0]) {
			return c.DefaultRemote, raw, nil
		}

		return "", "", fmt.Errorf("The remote \"%s\" doesn't exist", result[0])
	}

	return result[0], result[1], nil
}

// GetContainerServer returns a ContainerServer struct for the remote
func (c *Config) GetContainerServer(name string) (lxd.ContainerServer, error) {
	// Get the remote
	remote, ok := c.Remotes[name]
	if !ok {
		return nil, fmt.Errorf("The remote \"%s\" doesn't exist", name)
	}

	// Sanity checks
	if remote.Public || remote.Protocol == "simplestreams" {
		return nil, fmt.Errorf("The remote isn't a private LXD server")
	}

	// Get connection arguments
	args, err := c.getConnectionArgs(name)
	if err != nil {
		return nil, err
	}

	// Unix socket
	if strings.HasPrefix(remote.Addr, "unix:") {
		d, err := lxd.ConnectLXDUnix(strings.TrimPrefix(strings.TrimPrefix(remote.Addr, "unix:"), "//"), args)
		if err != nil {
			return nil, err
		}

		if remote.Project != "" && remote.Project != "default" {
			d = d.UseProject(remote.Project)
		}

		if c.ProjectOverride != "" {
			d = d.UseProject(c.ProjectOverride)
		}

		return d, nil
	}

	// HTTPs
	if remote.AuthType != "candid" && (args.TLSClientCert == "" || args.TLSClientKey == "") {
		return nil, fmt.Errorf("Missing TLS client certificate and key")
	}

	d, err := lxd.ConnectLXD(remote.Addr, args)
	if err != nil {
		return nil, err
	}

	if remote.Project != "" && remote.Project != "default" {
		d = d.UseProject(remote.Project)
	}

	if c.ProjectOverride != "" {
		d = d.UseProject(c.ProjectOverride)
	}

	return d, nil
}

// GetImageServer returns a ImageServer struct for the remote
func (c *Config) GetImageServer(name string) (lxd.ImageServer, error) {
	// Get the remote
	remote, ok := c.Remotes[name]
	if !ok {
		return nil, fmt.Errorf("The remote \"%s\" doesn't exist", name)
	}

	// Get connection arguments
	args, err := c.getConnectionArgs(name)
	if err != nil {
		return nil, err
	}

	// Unix socket
	if strings.HasPrefix(remote.Addr, "unix:") {
		d, err := lxd.ConnectLXDUnix(strings.TrimPrefix(strings.TrimPrefix(remote.Addr, "unix:"), "//"), args)
		if err != nil {
			return nil, err
		}

		if remote.Project != "" && remote.Project != "default" {
			d = d.UseProject(remote.Project)
		}

		if c.ProjectOverride != "" {
			d = d.UseProject(c.ProjectOverride)
		}

		return d, nil
	}

	// HTTPs (simplestreams)
	if remote.Protocol == "simplestreams" {
		d, err := lxd.ConnectSimpleStreams(remote.Addr, args)
		if err != nil {
			return nil, err
		}

		return d, nil
	}

	// HTTPs (public LXD)
	if remote.Public {
		d, err := lxd.ConnectPublicLXD(remote.Addr, args)
		if err != nil {
			return nil, err
		}

		return d, nil
	}

	// HTTPs (private LXD)
	d, err := lxd.ConnectLXD(remote.Addr, args)
	if err != nil {
		return nil, err
	}

	if remote.Project != "" && remote.Project != "default" {
		d = d.UseProject(remote.Project)
	}

	if c.ProjectOverride != "" {
		d = d.UseProject(c.ProjectOverride)
	}

	return d, nil
}

func (c *Config) getConnectionArgs(name string) (*lxd.ConnectionArgs, error) {
	remote, _ := c.Remotes[name]
	args := lxd.ConnectionArgs{
		UserAgent: c.UserAgent,
		AuthType:  remote.AuthType,
	}

	if args.AuthType == "candid" {
		args.AuthInteractor = []httpbakery.Interactor{
			form.Interactor{Filler: schemaform.IOFiller{}},
			httpbakery.WebBrowserInteractor{
				OpenWebBrowser: func(uri *url.URL) error {
					if remote.Domain != "" {
						query := uri.Query()
						query.Set("domain", remote.Domain)
						uri.RawQuery = query.Encode()
					}

					return httpbakery.OpenWebBrowser(uri)
				},
			},
		}

		if c.cookieJars == nil || c.cookieJars[name] == nil {
			if !shared.PathExists(c.ConfigPath("jars")) {
				err := os.MkdirAll(c.ConfigPath("jars"), 0700)
				if err != nil {
					return nil, err
				}
			}

			if !shared.PathExists(c.CookiesPath(name)) {
				if shared.PathExists(c.ConfigPath("cookies")) {
					err := shared.FileCopy(c.ConfigPath("cookies"), c.CookiesPath(name))
					if err != nil {
						return nil, err
					}
				}
			}

			jar, err := cookiejar.New(
				&cookiejar.Options{
					Filename: c.CookiesPath(name),
				})
			if err != nil {
				return nil, err
			}

			if c.cookieJars == nil {
				c.cookieJars = map[string]*cookiejar.Jar{}
			}
			c.cookieJars[name] = jar
		}

		args.CookieJar = c.cookieJars[name]
	}

	// Stop here if no TLS involved
	if strings.HasPrefix(remote.Addr, "unix:") {
		return &args, nil
	}

	// Server certificate
	if shared.PathExists(c.ServerCertPath(name)) {
		content, err := ioutil.ReadFile(c.ServerCertPath(name))
		if err != nil {
			return nil, err
		}

		args.TLSServerCert = string(content)
	}

	// Stop here if no client certificate involved
	if remote.Protocol == "simplestreams" || remote.AuthType == "candid" {
		return &args, nil
	}

	// Client certificate
	if shared.PathExists(c.ConfigPath("client.crt")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.crt"))
		if err != nil {
			return nil, err
		}

		args.TLSClientCert = string(content)
	}

	// Client CA
	if shared.PathExists(c.ConfigPath("client.ca")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.ca"))
		if err != nil {
			return nil, err
		}

		args.TLSCA = string(content)
	}

	// Client key
	if shared.PathExists(c.ConfigPath("client.key")) {
		content, err := ioutil.ReadFile(c.ConfigPath("client.key"))
		if err != nil {
			return nil, err
		}

		pemKey, _ := pem.Decode(content)
		if x509.IsEncryptedPEMBlock(pemKey) {
			if c.PromptPassword == nil {
				return nil, fmt.Errorf("Private key is password protected and no helper was configured")
			}

			password, err := c.PromptPassword("client.crt")
			if err != nil {
				return nil, err
			}

			derKey, err := x509.DecryptPEMBlock(pemKey, []byte(password))
			if err != nil {
				return nil, err
			}

			content = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: derKey})
		}

		args.TLSClientKey = string(content)
	}

	return &args, nil
}
<|endoftext|>


<commit_before>package questions

import (
	"fmt"
	"math/bits"
	"math/rand"
)

// QuestionOne performs addition without using arithmetic operators
func QuestionOne(x, y int64) int64 {
	/*
		 No arithmetic, so binary operations required
		 addition:
			 0 + 0 = 00
			 0 + 1 = 01
			 1 + 0 = 01
			 1 + 1 = 10
		can split addition into adding the result without carrying one
		with the result of carrying the one, without the addition
		this is adding an XOR of the two numbers with and AND shifted by one bit
		101 + 011 = 110 + 010 = 100 + 100 = 000 + 1000

		Alternatively you can iterate through the bits in increasing order of significance and perform AND, carrying the one to the next bit if required.
	*/

	if y == 0 {
		return x
	}
	addition := x ^ y
	carry := (x & y) << 1
	return QuestionOne(addition, carry)
}

const (
	Spade = iota
	Club
	Diamond
	Heart
)

type Card struct {
	suit  int
	value int
}

func (c Card) Print() string {
	switch c.suit {
	case Spade:
		return fmt.Sprintf("S%d ", c.value)
	case Club:
		return fmt.Sprintf("C%d ", c.value)
	case Diamond:
		return fmt.Sprintf("D%d ", c.value)
	case Heart:
		return fmt.Sprintf("H%d ", c.value)
	default:
		return "nope"
	}
}

// QuestionTwo performs a shuffle of a deck of cards, using a perfect random number generator
func QuestionTwo(deck []*Card, position int) []*Card {
	for i := len(deck) - 1; i > 1; i-- {
		k := random(i)
		temp := deck[k]
		deck[k] = deck[i]
		deck[i] = temp
	}
	return deck
}

func initDeck() []*Card {
	deck := []*Card{}
	for _, suit := range []int{Spade, Club, Diamond, Heart} {
		for i := 1; i < 14; i++ {
			deck = append(deck, &Card{suit: suit, value: i})
		}
	}
	return deck
}

// random returns a random int between the 0 and x
func random(x int) int64 {
	return rand.Int63n(int64(x))
}

// QuestionThree generates a random subset of the provided set
func QuestionThree(set []int, count int) []int {
	subset := make([]int, count)
	copy(subset, set[:count])

	for i := count; i < len(set); i++ {
		random := random(len(set))
		if random < int64(count) {
			subset[random] = set[i]
		}
	}
	return subset
}

// Question Four,
func QuestionFour(list []*IntMod, column int64) int64 {
	/*
		An array contains integers from 0 to N, except one is missing
		the integers cannot be accessed directly, but only by the jth bit of array[i]
		find the missing integer in O(n) time

		the missing number will be revealed based on
	*/
	if column >= bits.UintSize {
		return 0
	}

	zeroes := []*IntMod{}
	ones := []*IntMod{}

	for _, i := range list {
		if i.Get(column) {
			// column bit is 1
			ones = append(ones, i)
		} else {
			zeroes = append(zeroes, i)
		}
	}

	if len(zeroes) > len(ones) {
		return (QuestionFour(ones, column+1) << 1) | 1
	} else {
		return (QuestionFour(zeroes, column+1) << 1) | 0
	}
}

type IntMod struct {
	value int64
}

func (i *IntMod) Get(j int64) bool {
	return bits.OnesCount(uint((1<<j)&i.value)) > 0
}

/*
QuestionFive

Given an array of A and B, build the longest sublist containing an equal
number of letters and numbers
*/
func QuestionFive(list []string) []string {
	/*
		Sub string must be even in length
		brute force by checking all subarrays, with some optimisations to allow for early exit

		complexity: N3
	*/
	var subArray []string
	differences := map[int]int{0: -1}
	aCount := 0
	bCount := 0
	for i, element := range list {
		if element == "A" {
			aCount++
		} else {
			bCount++
		}
		difference := aCount - bCount
		marker, ok := differences[difference]
		if !ok {
			differences[difference] = i
		} else {
			subLength := i - marker
			if len(subArray) < subLength {
				subArray = list[marker+1 : i+1]
			}
		}
	}
	return subArray
}

func CheckSubLength(list []string, length int) []string {
	for i := 0; i <= len(list)-length; i++ {
		if CheckEven(list[i : i+length]) {
			return list[i : i+length]
		}
	}
	return nil
}

func CheckEven(list []string) bool {
	aCount := 0
	bCount := 0
	for _, element := range list {
		if element == "A" {
			aCount++
		} else {
			bCount++
		}
	}
	return aCount == bCount
}
<commit_msg>Remove previous code<commit_after>package questions

import (
	"fmt"
	"math/bits"
	"math/rand"
)

// QuestionOne performs addition without using arithmetic operators
func QuestionOne(x, y int64) int64 {
	/*
		 No arithmetic, so binary operations required
		 addition:
			 0 + 0 = 00
			 0 + 1 = 01
			 1 + 0 = 01
			 1 + 1 = 10
		can split addition into adding the result without carrying one
		with the result of carrying the one, without the addition
		this is adding an XOR of the two numbers with and AND shifted by one bit
		101 + 011 = 110 + 010 = 100 + 100 = 000 + 1000

		Alternatively you can iterate through the bits in increasing order of significance and perform AND, carrying the one to the next bit if required.
	*/

	if y == 0 {
		return x
	}
	addition := x ^ y
	carry := (x & y) << 1
	return QuestionOne(addition, carry)
}

const (
	Spade = iota
	Club
	Diamond
	Heart
)

type Card struct {
	suit  int
	value int
}

func (c Card) Print() string {
	switch c.suit {
	case Spade:
		return fmt.Sprintf("S%d ", c.value)
	case Club:
		return fmt.Sprintf("C%d ", c.value)
	case Diamond:
		return fmt.Sprintf("D%d ", c.value)
	case Heart:
		return fmt.Sprintf("H%d ", c.value)
	default:
		return "nope"
	}
}

// QuestionTwo performs a shuffle of a deck of cards, using a perfect random number generator
func QuestionTwo(deck []*Card, position int) []*Card {
	for i := len(deck) - 1; i > 1; i-- {
		k := random(i)
		temp := deck[k]
		deck[k] = deck[i]
		deck[i] = temp
	}
	return deck
}

func initDeck() []*Card {
	deck := []*Card{}
	for _, suit := range []int{Spade, Club, Diamond, Heart} {
		for i := 1; i < 14; i++ {
			deck = append(deck, &Card{suit: suit, value: i})
		}
	}
	return deck
}

// random returns a random int between the 0 and x
func random(x int) int64 {
	return rand.Int63n(int64(x))
}

// QuestionThree generates a random subset of the provided set
func QuestionThree(set []int, count int) []int {
	subset := make([]int, count)
	copy(subset, set[:count])

	for i := count; i < len(set); i++ {
		random := random(len(set))
		if random < int64(count) {
			subset[random] = set[i]
		}
	}
	return subset
}

// Question Four,
func QuestionFour(list []*IntMod, column int64) int64 {
	/*
		An array contains integers from 0 to N, except one is missing
		the integers cannot be accessed directly, but only by the jth bit of array[i]
		find the missing integer in O(n) time

		the missing number will be revealed based on
	*/
	if column >= bits.UintSize {
		return 0
	}

	zeroes := []*IntMod{}
	ones := []*IntMod{}

	for _, i := range list {
		if i.Get(column) {
			// column bit is 1
			ones = append(ones, i)
		} else {
			zeroes = append(zeroes, i)
		}
	}

	if len(zeroes) > len(ones) {
		return (QuestionFour(ones, column+1) << 1) | 1
	} else {
		return (QuestionFour(zeroes, column+1) << 1) | 0
	}
}

type IntMod struct {
	value int64
}

func (i *IntMod) Get(j int64) bool {
	return bits.OnesCount(uint((1<<j)&i.value)) > 0
}

/*
QuestionFive

Given an array of A and B, build the longest sublist containing an equal
number of letters and numbers
*/
func QuestionFive(list []string) []string {
	/*
		Sub string must be even in length
		brute force by checking all subarrays, with some optimisations to allow for early exit

		complexity: N3
	*/
	var subArray []string
	differences := map[int]int{0: -1}
	aCount := 0
	bCount := 0
	for i, element := range list {
		if element == "A" {
			aCount++
		} else {
			bCount++
		}
		difference := aCount - bCount
		marker, ok := differences[difference]
		if !ok {
			differences[difference] = i
		} else {
			subLength := i - marker
			if len(subArray) < subLength {
				subArray = list[marker+1 : i+1]
			}
		}
	}
	return subArray
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

// A variation of the standard tls.Listener that supports atomically swapping
// the underlying TLS configuration. Requests served before the swap will
// continue using the old configuration.
type networkListener struct {
	net.Listener
	mu     sync.RWMutex
	config *tls.Config
}

func networkTLSListener(inner net.Listener, config *tls.Config) *networkListener {
	listener := &networkListener{
		Listener: inner,
		config:   config,
	}

	return listener
}

// Accept waits for and returns the next incoming TLS connection then use the
// current TLS configuration to handle it.
func (l *networkListener) Accept() (net.Conn, error) {
	var c net.Conn
	var err error

	// Accept() is non-blocking in go < 1.12 hence the loop and error check.
	for {
		c, err = l.Listener.Accept()
		if err == nil {
			break
		}

		if err.(net.Error).Temporary() {
			time.Sleep(100 * time.Millisecond)
			continue
		}

		return nil, err
	}

	l.mu.RLock()
	defer l.mu.RUnlock()

	return tls.Server(c, l.config), nil
}

func serverTLSConfig() (*tls.Config, error) {
	certInfo, err := shared.KeyPairAndCA(".", "agent", shared.CertServer, false)
	if err != nil {
		return nil, err
	}

	tlsConfig := util.ServerTLSConfig(certInfo)
	return tlsConfig, nil
}

// reconfigureNetworkInterfaces checks for the existence of files under NICConfigDir in the config share.
// Each file is named <device>.json and contains the Device Name, NIC Name, MTU and MAC address.
func reconfigureNetworkInterfaces() {
	nicDirEntries, err := ioutil.ReadDir(deviceConfig.NICConfigDir)
	if err != nil {
		// Abort if configuration folder does not exist (nothing to do), otherwise log and return.
		if os.IsNotExist(err) {
			return
		}

		logger.Error("Could not read network interface configuration directory", logger.Ctx{"err": err})
		return
	}

	// nicData is a map of MAC address to NICConfig.
	nicData := make(map[string]deviceConfig.NICConfig, len(nicDirEntries))

	for _, f := range nicDirEntries {
		nicBytes, err := ioutil.ReadFile(filepath.Join(deviceConfig.NICConfigDir, f.Name()))
		if err != nil {
			logger.Error("Could not read network interface configuration file", logger.Ctx{"err": err})
		}

		var conf deviceConfig.NICConfig
		err = json.Unmarshal(nicBytes, &conf)
		if err != nil {
			logger.Error("Could not parse network interface configuration file", logger.Ctx{"err": err})
			return
		}

		if conf.MACAddress != "" {
			nicData[conf.MACAddress] = conf
		}
	}

	// configureNIC applies any config specified for the interface based on its current MAC address.
	configureNIC := func(currentNIC net.Interface) error {
		reverter := revert.New()
		defer reverter.Fail()

		// Look for a NIC config entry for this interface based on its MAC address.
		nic, ok := nicData[currentNIC.HardwareAddr.String()]
		if !ok {
			return nil
		}

		var changeName, changeMTU bool
		if nic.NICName != "" && currentNIC.Name != nic.NICName {
			changeName = true
		}

		if nic.MTU > 0 && currentNIC.MTU != int(nic.MTU) {
			changeMTU = true
		}

		if !changeName && !changeMTU {
			return nil // Nothing to do.
		}

		link := ip.Link{
			Name: currentNIC.Name,
			MTU:  fmt.Sprintf("%d", currentNIC.MTU),
		}

		err := link.SetDown()
		if err != nil {
			return err
		}
		reverter.Add(func() {
			_ = link.SetUp()
		})

		// Apply the name from the NIC config if needed.
		if changeName {
			err = link.SetName(nic.NICName)
			if err != nil {
				return err
			}
			reverter.Add(func() {
				err := link.SetName(currentNIC.Name)
				if err != nil {
					return
				}

				link.Name = currentNIC.Name
			})

			link.Name = nic.NICName
		}

		// Apply the MTU from the NIC config if needed.
		if changeMTU {
			newMTU := fmt.Sprintf("%d", nic.MTU)
			err = link.SetMTU(newMTU)
			if err != nil {
				return err
			}
			reverter.Add(func() {
				currentMTU := fmt.Sprintf("%d", currentNIC.MTU)
				err := link.SetMTU(currentMTU)
				if err != nil {
					return
				}

				link.MTU = currentMTU
			})

			link.MTU = newMTU
		}

		err = link.SetUp()
		if err != nil {
			return err
		}

		reverter.Success()
		return nil
	}

	ifaces, err := net.Interfaces()
	if err != nil {
		logger.Error("Unable to read network interfaces", logger.Ctx{"err": err})
	}

	for _, iface := range ifaces {
		err = configureNIC(iface)
		if err != nil {
			logger.Error("Unable to reconfigure network interface", logger.Ctx{"interface": iface.Name, "err": err})
		}
	}

	return
}
<commit_msg>lxd-agent: Consistent use of revert name<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

// A variation of the standard tls.Listener that supports atomically swapping
// the underlying TLS configuration. Requests served before the swap will
// continue using the old configuration.
type networkListener struct {
	net.Listener
	mu     sync.RWMutex
	config *tls.Config
}

func networkTLSListener(inner net.Listener, config *tls.Config) *networkListener {
	listener := &networkListener{
		Listener: inner,
		config:   config,
	}

	return listener
}

// Accept waits for and returns the next incoming TLS connection then use the
// current TLS configuration to handle it.
func (l *networkListener) Accept() (net.Conn, error) {
	var c net.Conn
	var err error

	// Accept() is non-blocking in go < 1.12 hence the loop and error check.
	for {
		c, err = l.Listener.Accept()
		if err == nil {
			break
		}

		if err.(net.Error).Temporary() {
			time.Sleep(100 * time.Millisecond)
			continue
		}

		return nil, err
	}

	l.mu.RLock()
	defer l.mu.RUnlock()

	return tls.Server(c, l.config), nil
}

func serverTLSConfig() (*tls.Config, error) {
	certInfo, err := shared.KeyPairAndCA(".", "agent", shared.CertServer, false)
	if err != nil {
		return nil, err
	}

	tlsConfig := util.ServerTLSConfig(certInfo)
	return tlsConfig, nil
}

// reconfigureNetworkInterfaces checks for the existence of files under NICConfigDir in the config share.
// Each file is named <device>.json and contains the Device Name, NIC Name, MTU and MAC address.
func reconfigureNetworkInterfaces() {
	nicDirEntries, err := ioutil.ReadDir(deviceConfig.NICConfigDir)
	if err != nil {
		// Abort if configuration folder does not exist (nothing to do), otherwise log and return.
		if os.IsNotExist(err) {
			return
		}

		logger.Error("Could not read network interface configuration directory", logger.Ctx{"err": err})
		return
	}

	// nicData is a map of MAC address to NICConfig.
	nicData := make(map[string]deviceConfig.NICConfig, len(nicDirEntries))

	for _, f := range nicDirEntries {
		nicBytes, err := ioutil.ReadFile(filepath.Join(deviceConfig.NICConfigDir, f.Name()))
		if err != nil {
			logger.Error("Could not read network interface configuration file", logger.Ctx{"err": err})
		}

		var conf deviceConfig.NICConfig
		err = json.Unmarshal(nicBytes, &conf)
		if err != nil {
			logger.Error("Could not parse network interface configuration file", logger.Ctx{"err": err})
			return
		}

		if conf.MACAddress != "" {
			nicData[conf.MACAddress] = conf
		}
	}

	// configureNIC applies any config specified for the interface based on its current MAC address.
	configureNIC := func(currentNIC net.Interface) error {
		revert := revert.New()
		defer revert.Fail()

		// Look for a NIC config entry for this interface based on its MAC address.
		nic, ok := nicData[currentNIC.HardwareAddr.String()]
		if !ok {
			return nil
		}

		var changeName, changeMTU bool
		if nic.NICName != "" && currentNIC.Name != nic.NICName {
			changeName = true
		}

		if nic.MTU > 0 && currentNIC.MTU != int(nic.MTU) {
			changeMTU = true
		}

		if !changeName && !changeMTU {
			return nil // Nothing to do.
		}

		link := ip.Link{
			Name: currentNIC.Name,
			MTU:  fmt.Sprintf("%d", currentNIC.MTU),
		}

		err := link.SetDown()
		if err != nil {
			return err
		}
		revert.Add(func() {
			_ = link.SetUp()
		})

		// Apply the name from the NIC config if needed.
		if changeName {
			err = link.SetName(nic.NICName)
			if err != nil {
				return err
			}
			revert.Add(func() {
				err := link.SetName(currentNIC.Name)
				if err != nil {
					return
				}

				link.Name = currentNIC.Name
			})

			link.Name = nic.NICName
		}

		// Apply the MTU from the NIC config if needed.
		if changeMTU {
			newMTU := fmt.Sprintf("%d", nic.MTU)
			err = link.SetMTU(newMTU)
			if err != nil {
				return err
			}
			revert.Add(func() {
				currentMTU := fmt.Sprintf("%d", currentNIC.MTU)
				err := link.SetMTU(currentMTU)
				if err != nil {
					return
				}

				link.MTU = currentMTU
			})

			link.MTU = newMTU
		}

		err = link.SetUp()
		if err != nil {
			return err
		}

		revert.Success()
		return nil
	}

	ifaces, err := net.Interfaces()
	if err != nil {
		logger.Error("Unable to read network interfaces", logger.Ctx{"err": err})
	}

	for _, iface := range ifaces {
		err = configureNIC(iface)
		if err != nil {
			logger.Error("Unable to reconfigure network interface", logger.Ctx{"interface": iface.Name, "err": err})
		}
	}

	return
}
<|endoftext|>


<commit_before>package query

import (
	"context"
	"database/sql"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// Dump returns a SQL text dump of all rows across all tables, similar to
// sqlite3's dump feature.
func Dump(ctx context.Context, tx *sql.Tx, schemaOnly bool) (string, error) {
	tablesSchemas, tableNames, err := getTablesSchemas(ctx, tx)
	if err != nil {
		return "", err
	}

	// Begin dump string.
	var builder strings.Builder
	builder.WriteString("PRAGMA foreign_keys=OFF;\n")
	builder.WriteString("BEGIN TRANSACTION;\n")

	// For each table, write the schema and optionally write the data.
	for _, tableName := range tableNames {
		builder.WriteString(tablesSchemas[tableName] + "\n")

		if !schemaOnly {
			tableData, err := getTableData(ctx, tx, tableName)
			if err != nil {
				return "", err
			}

			for _, stmt := range tableData {
				builder.WriteString(stmt + "\n")
			}
		}
	}

	// Sequences (unless the schemaOnly flag is true).
	if !schemaOnly {
		builder.WriteString("DELETE FROM sqlite_sequence;\n")

		tableData, err := getTableData(ctx, tx, "sqlite_sequence")
		if err != nil {
			return "", fmt.Errorf("Failed to dump table sqlite_sequence: %w", err)
		}

		for _, stmt := range tableData {
			builder.WriteString(stmt + "\n")
		}
	}

	// Commit.
	builder.WriteString("COMMIT;\n")

	return builder.String(), nil
}

// getTablesSchemas gets all the tables and their schema, as well as a list of table names in their default order from
// the sqlite_master table.
func getTablesSchemas(ctx context.Context, tx *sql.Tx) (map[string]string, []string, error) {
	rows, err := tx.QueryContext(ctx, `SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY rowid`)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get table names and their schema: %w", err)
	}

	defer rows.Close()

	tablesSchemas := make(map[string]string)
	var names []string
	for rows.Next() {
		var name string
		var schema string
		err := rows.Scan(&name, &schema)
		if err != nil {
			return nil, nil, fmt.Errorf("Could not scan table name and schema: %w", err)
		}

		names = append(names, name)

		// Whether a table name is quoted or not can depend on if it was quoted when originally created, or if it
		// collides with a keyword (and maybe more). Regardless, sqlite3 quotes table names in create statements when
		// executing a dump. If the table name is already quoted, add the "IF NOT EXISTS" clause, else quote it and add
		// the same clause.
		isQuoted := strings.Contains(schema, fmt.Sprintf("TABLE %q", name))
		if isQuoted {
			schema = strings.Replace(schema, "TABLE", "TABLE IF NOT EXISTS", 1)
		} else {
			schema = strings.Replace(schema, name, fmt.Sprintf("IF NOT EXISTS %q", name), 1)
		}

		tablesSchemas[name] = schema + ";"
	}

	return tablesSchemas, names, nil
}

// getTableData gets all the data for a single table, returning a string slice where each element is an insert statement
// for the data.
func getTableData(ctx context.Context, tx *sql.Tx, table string) ([]string, error) {
	var statements []string

	// Query all rows.
	rows, err := tx.QueryContext(ctx, fmt.Sprintf("SELECT * FROM %s ORDER BY rowid", table))
	if err != nil {
		return nil, fmt.Errorf("Failed to fetch rows for table %q: %w", table, err)
	}

	defer rows.Close()

	// Get the column names.
	columns, err := rows.Columns()
	if err != nil {
		return nil, fmt.Errorf("Failed to get columns for table %q: %w", table, err)
	}

	// Generate an INSERT statement for each row.
	for i := 0; rows.Next(); i++ {
		raw := make([]any, len(columns)) // Raw column values
		row := make([]any, len(columns))
		for i := range raw {
			row[i] = &raw[i]
		}

		err := rows.Scan(row...)
		if err != nil {
			return nil, fmt.Errorf("Failed to scan row %d in table %q: %w", i, table, err)
		}

		values := make([]string, len(columns))
		for j, v := range raw {
			switch v := v.(type) {
			case int64:
				values[j] = strconv.FormatInt(v, 10)
			case string:
				values[j] = fmt.Sprintf("'%s'", v)
			case []byte:
				values[j] = fmt.Sprintf("'%s'", string(v))
			case time.Time:
				values[j] = strconv.FormatInt(v.Unix(), 10)
			default:
				if v != nil {
					return nil, fmt.Errorf("Bad type in column %q of row %d in table %q", columns[j], i, table)
				}

				values[j] = "NULL"
			}
		}

		statement := fmt.Sprintf("INSERT INTO %s VALUES(%s);", table, strings.Join(values, ","))
		statements = append(statements, statement)
	}

	return statements, nil
}
<commit_msg>lxd/db/query: Return the table schema sql verbatim from sqlite_master.<commit_after>package query

import (
	"context"
	"database/sql"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// Dump returns a SQL text dump of all rows across all tables, similar to
// sqlite3's dump feature.
func Dump(ctx context.Context, tx *sql.Tx, schemaOnly bool) (string, error) {
	tablesSchemas, tableNames, err := getTablesSchemas(ctx, tx)
	if err != nil {
		return "", err
	}

	// Begin dump string.
	var builder strings.Builder
	builder.WriteString("PRAGMA foreign_keys=OFF;\n")
	builder.WriteString("BEGIN TRANSACTION;\n")

	// For each table, write the schema and optionally write the data.
	for _, tableName := range tableNames {
		builder.WriteString(tablesSchemas[tableName] + "\n")

		if !schemaOnly {
			tableData, err := getTableData(ctx, tx, tableName)
			if err != nil {
				return "", err
			}

			for _, stmt := range tableData {
				builder.WriteString(stmt + "\n")
			}
		}
	}

	// Sequences (unless the schemaOnly flag is true).
	if !schemaOnly {
		builder.WriteString("DELETE FROM sqlite_sequence;\n")

		tableData, err := getTableData(ctx, tx, "sqlite_sequence")
		if err != nil {
			return "", fmt.Errorf("Failed to dump table sqlite_sequence: %w", err)
		}

		for _, stmt := range tableData {
			builder.WriteString(stmt + "\n")
		}
	}

	// Commit.
	builder.WriteString("COMMIT;\n")

	return builder.String(), nil
}

// getTablesSchemas gets all the tables and their schema, as well as a list of table names in their default order from
// the sqlite_master table.
func getTablesSchemas(ctx context.Context, tx *sql.Tx) (map[string]string, []string, error) {
	rows, err := tx.QueryContext(ctx, `SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY rowid`)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get table names and their schema: %w", err)
	}

	defer rows.Close()

	tablesSchemas := make(map[string]string)
	var names []string
	for rows.Next() {
		var name string
		var schema string
		err := rows.Scan(&name, &schema)
		if err != nil {
			return nil, nil, fmt.Errorf("Could not scan table name and schema: %w", err)
		}

		names = append(names, name)
		tablesSchemas[name] = schema + ";"
	}

	return tablesSchemas, names, nil
}

// getTableData gets all the data for a single table, returning a string slice where each element is an insert statement
// for the data.
func getTableData(ctx context.Context, tx *sql.Tx, table string) ([]string, error) {
	var statements []string

	// Query all rows.
	rows, err := tx.QueryContext(ctx, fmt.Sprintf("SELECT * FROM %s ORDER BY rowid", table))
	if err != nil {
		return nil, fmt.Errorf("Failed to fetch rows for table %q: %w", table, err)
	}

	defer rows.Close()

	// Get the column names.
	columns, err := rows.Columns()
	if err != nil {
		return nil, fmt.Errorf("Failed to get columns for table %q: %w", table, err)
	}

	// Generate an INSERT statement for each row.
	for i := 0; rows.Next(); i++ {
		raw := make([]any, len(columns)) // Raw column values
		row := make([]any, len(columns))
		for i := range raw {
			row[i] = &raw[i]
		}

		err := rows.Scan(row...)
		if err != nil {
			return nil, fmt.Errorf("Failed to scan row %d in table %q: %w", i, table, err)
		}

		values := make([]string, len(columns))
		for j, v := range raw {
			switch v := v.(type) {
			case int64:
				values[j] = strconv.FormatInt(v, 10)
			case string:
				values[j] = fmt.Sprintf("'%s'", v)
			case []byte:
				values[j] = fmt.Sprintf("'%s'", string(v))
			case time.Time:
				values[j] = strconv.FormatInt(v.Unix(), 10)
			default:
				if v != nil {
					return nil, fmt.Errorf("Bad type in column %q of row %d in table %q", columns[j], i, table)
				}

				values[j] = "NULL"
			}
		}

		statement := fmt.Sprintf("INSERT INTO %s VALUES(%s);", table, strings.Join(values, ","))
		statements = append(statements, statement)
	}

	return statements, nil
}
<|endoftext|>


<commit_before>package device

import (
	"fmt"

	"github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/state"
)

// devTypes defines supported top-level device type creation functions.
var devTypes = map[string]func(config.Device) device{
	"nic": nicLoadByType,
}

// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD
// config for this instance. It should add the volatile device name prefix to each key when saving.
type VolatileSetter func(map[string]string) error

// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database
// config for this instance. It should only return keys that match the volatile device name prefix,
// and should remove the prefix before being returned.
type VolatileGetter func() map[string]string

// Device represents a device that can be added to an instance.
type Device interface {
	// CanHotPlug returns true if device can be managed whilst instance is running.
	// It also returns a slice of config fields that can be live updated. If only fields in this
	// list have changed then Update() is called rather than triggering a device remove & add.
	CanHotPlug() (bool, []string)

	// Add performs any host-side setup when a device is added to an instance.
	// It is called irrespective of whether the instance is running or not.
	Add() error

	// Start peforms any host-side configuration required to start the device for the instance.
	// This can be when a device is plugged into a running instance or the instance is starting.
	// Returns run-time configuration needed for configuring the instance with the new device.
	Start() (*RunConfig, error)

	// Update performs host-side modifications for a device based on the difference between the
	// current config and previous config supplied as an argument. This called if the only
	// config fields that have changed are supplied in the list returned from CanHotPlug().
	// The function also accepts a boolean indicating whether the instance is running or not.
	Update(oldConfig config.Device, running bool) error

	// Stop performs any host-side cleanup required when a device is removed from an instance,
	// either due to unplugging it from a running instance or instance is being shutdown.
	Stop() error

	// Remove performs any host-side cleanup when an instance is removed from an instance.
	Remove() error
}

// device represents a sealed interface that implements Device, but also contains some internal
// setup functions for a Device that should only be called by device.New() to avoid exposing devices
// that are not in a known configured state. This is separate from the Device interface so that
// Devices created outside of the device package can be used by LXD, but ensures that any devices
// created by the device package will only be accessible after being configured properly by New().
type device interface {
	Device

	// init stores the InstanceIdentifier, daemon State and Config into device and performs any setup.
	init(InstanceIdentifier, *state.State, config.Device, VolatileGetter, VolatileSetter)

	// validateConfig checks Config stored by init() is valid for the instance type.
	validateConfig() error
}

// deviceCommon represents the common struct for all devices.
type deviceCommon struct {
	instance    InstanceIdentifier
	config      map[string]string
	state       *state.State
	volatileGet func() map[string]string
	volatileSet func(map[string]string) error
}

// init stores the InstanceIdentifier, daemon state and Config into device. It can also be provided
// with volatile get and set functions for the device to allow persistent data to be accessed.
// This is implemented as part of deviceCommon so that the majority of devices don't need to
// implement it and can just embed deviceCommon.
func (d *deviceCommon) init(instance InstanceIdentifier, state *state.State, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) {
	d.instance = instance
	d.config = conf
	d.state = state
	d.volatileGet = volatileGet
	d.volatileSet = volatileSet
}

// Add returns nil error as majority of devices don't need to do any host-side setup.
func (d *deviceCommon) Add() error {
	return nil
}

// CanHotPlug returns true as majority of devices can be started/stopped when instance is running.
// Also returns an empty list of update fields as most devices do not support live updates.
func (d *deviceCommon) CanHotPlug() (bool, []string) {
	return true, []string{}
}

// Update returns an error as most devices do not support live updates without being restarted.
func (d *deviceCommon) Update(oldConfig config.Device, isRunning bool) error {
	return fmt.Errorf("Device does not support updates whilst started")
}

// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete.
func (d *deviceCommon) Remove() error {
	return nil
}

// New instantiates a new device struct, validates the supplied config and sets it into the device.
func New(instance InstanceIdentifier, state *state.State, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) {
	devFunc := devTypes[conf["type"]]

	// Check if top-level type is recognised, if it is known type it will return a function.
	if devFunc == nil {
		return nil, ErrUnsupportedDevType
	}

	// Run the device create function and check it succeeds.
	dev := devFunc(conf)
	if dev == nil {
		return nil, ErrUnsupportedDevType
	}

	// Init the device and run validation of supplied config.
	dev.init(instance, state, conf, volatileGet, volatileSet)
	err := dev.validateConfig()
	if err != nil {
		return nil, err
	}

	return dev, nil
}
<commit_msg>device: Adds device name to device structure<commit_after>package device

import (
	"fmt"

	"github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/state"
)

// devTypes defines supported top-level device type creation functions.
var devTypes = map[string]func(config.Device) device{
	"nic": nicLoadByType,
}

// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD
// config for this instance. It should add the volatile device name prefix to each key when saving.
type VolatileSetter func(map[string]string) error

// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database
// config for this instance. It should only return keys that match the volatile device name prefix,
// and should remove the prefix before being returned.
type VolatileGetter func() map[string]string

// Device represents a device that can be added to an instance.
type Device interface {
	// CanHotPlug returns true if device can be managed whilst instance is running.
	// It also returns a slice of config fields that can be live updated. If only fields in this
	// list have changed then Update() is called rather than triggering a device remove & add.
	CanHotPlug() (bool, []string)

	// Add performs any host-side setup when a device is added to an instance.
	// It is called irrespective of whether the instance is running or not.
	Add() error

	// Start peforms any host-side configuration required to start the device for the instance.
	// This can be when a device is plugged into a running instance or the instance is starting.
	// Returns run-time configuration needed for configuring the instance with the new device.
	Start() (*RunConfig, error)

	// Update performs host-side modifications for a device based on the difference between the
	// current config and previous config supplied as an argument. This called if the only
	// config fields that have changed are supplied in the list returned from CanHotPlug().
	// The function also accepts a boolean indicating whether the instance is running or not.
	Update(oldConfig config.Device, running bool) error

	// Stop performs any host-side cleanup required when a device is removed from an instance,
	// either due to unplugging it from a running instance or instance is being shutdown.
	Stop() error

	// Remove performs any host-side cleanup when an instance is removed from an instance.
	Remove() error
}

// device represents a sealed interface that implements Device, but also contains some internal
// setup functions for a Device that should only be called by device.New() to avoid exposing devices
// that are not in a known configured state. This is separate from the Device interface so that
// Devices created outside of the device package can be used by LXD, but ensures that any devices
// created by the device package will only be accessible after being configured properly by New().
type device interface {
	Device

	// init stores the InstanceIdentifier, daemon State and Config into device and performs any setup.
	init(InstanceIdentifier, *state.State, string, config.Device, VolatileGetter, VolatileSetter)

	// validateConfig checks Config stored by init() is valid for the instance type.
	validateConfig() error
}

// deviceCommon represents the common struct for all devices.
type deviceCommon struct {
	instance    InstanceIdentifier
	name        string
	config      map[string]string
	state       *state.State
	volatileGet func() map[string]string
	volatileSet func(map[string]string) error
}

// init stores the InstanceIdentifier, daemon state, device name and config into device.
// It also needs to be provided with volatile get and set functions for the device to allow
// persistent data to be accessed. This is implemented as part of deviceCommon so that the majority
// of devices don't need to implement it and can just embed deviceCommon.
func (d *deviceCommon) init(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) {
	d.instance = instance
	d.name = name
	d.config = conf
	d.state = state
	d.volatileGet = volatileGet
	d.volatileSet = volatileSet
}

// Add returns nil error as majority of devices don't need to do any host-side setup.
func (d *deviceCommon) Add() error {
	return nil
}

// CanHotPlug returns true as majority of devices can be started/stopped when instance is running.
// Also returns an empty list of update fields as most devices do not support live updates.
func (d *deviceCommon) CanHotPlug() (bool, []string) {
	return true, []string{}
}

// Update returns an error as most devices do not support live updates without being restarted.
func (d *deviceCommon) Update(oldConfig config.Device, isRunning bool) error {
	return fmt.Errorf("Device does not support updates whilst started")
}

// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete.
func (d *deviceCommon) Remove() error {
	return nil
}

// New instantiates a new device struct, validates the supplied config and sets it into the device.
func New(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) {
	devFunc := devTypes[conf["type"]]

	// Check if top-level type is recognised, if it is known type it will return a function.
	if devFunc == nil {
		return nil, ErrUnsupportedDevType
	}

	// Run the device create function and check it succeeds.
	dev := devFunc(conf)
	if dev == nil {
		return nil, ErrUnsupportedDevType
	}

	// Init the device and run validation of supplied config.
	dev.init(instance, state, name, conf, volatileGet, volatileSet)
	err := dev.validateConfig()
	if err != nil {
		return nil, err
	}

	return dev, nil
}
<|endoftext|>


<commit_before>package lzbase

// Maximum and minimum values for individual parameters.
const (
	MinLC       = 0
	MaxLC       = 8
	MinLP       = 0
	MaxLP       = 4
	MinPB       = 0
	MaxPB       = 4
	MinDictSize = 1 << 12
	MaxDictSize = 1<<32 - 1
)

// Properties contains the parametes lc, lp and pb.
type Properties byte

// NewProperties returns a new properties value. It verifies the validity of
// the arguments.
func NewProperties(lc, lp, pb int) (p Properties, err error) {
	if err = verifyProperties(lc, lp, pb); err != nil {
		return
	}
	return Properties((pb*5+lp)*9 + lc), nil
}

// LC returns the number of literal context bits.
func (p Properties) LC() int {
	return int(p) % 9
}

// LP returns the number of literal position bits.
func (p Properties) LP() int {
	return (int(p) / 9) % 5
}

// PB returns the number of position bits.
func (p Properties) PB() int {
	return int(p) / 45
}

// verifyProperties checks the argument for any errors.
func verifyProperties(lc, lp, pb int) error {
	if !(MinLC <= lc && lc <= MaxLC) {
		return newError("lc out of range")
	}
	if !(MinLP <= lp && lp <= MaxLC) {
		return newError("lp out of range")
	}
	if !(MinPB <= pb && pb <= MaxPB) {
		return newError("pb out of range")
	}
	return nil
}
<commit_msg>lzbase: export VerifyProperties<commit_after>package lzbase

// Maximum and minimum values for individual parameters.
const (
	MinLC       = 0
	MaxLC       = 8
	MinLP       = 0
	MaxLP       = 4
	MinPB       = 0
	MaxPB       = 4
	MinDictSize = 1 << 12
	MaxDictSize = 1<<32 - 1
)

// Properties contains the parametes lc, lp and pb.
type Properties byte

// NewProperties returns a new properties value. It verifies the validity of
// the arguments.
func NewProperties(lc, lp, pb int) (p Properties, err error) {
	if err = VerifyProperties(lc, lp, pb); err != nil {
		return
	}
	return Properties((pb*5+lp)*9 + lc), nil
}

// LC returns the number of literal context bits.
func (p Properties) LC() int {
	return int(p) % 9
}

// LP returns the number of literal position bits.
func (p Properties) LP() int {
	return (int(p) / 9) % 5
}

// PB returns the number of position bits.
func (p Properties) PB() int {
	return int(p) / 45
}

// VerifyProperties checks the argument for any errors.
func VerifyProperties(lc, lp, pb int) error {
	if !(MinLC <= lc && lc <= MaxLC) {
		return newError("lc out of range")
	}
	if !(MinLP <= lp && lp <= MaxLC) {
		return newError("lp out of range")
	}
	if !(MinPB <= pb && pb <= MaxPB) {
		return newError("pb out of range")
	}
	return nil
}
<|endoftext|>


<commit_before>package build

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"

	"github.com/stellar/go-stellar-base/hash"
	"github.com/stellar/go-stellar-base/xdr"
)

// Transaction groups the creation of a new TransactionBuilder with a call
// to Mutate.
func Transaction(muts ...TransactionMutator) (result *TransactionBuilder) {
	result = &TransactionBuilder{}
	result.Mutate(muts...)
	result.Mutate(Defaults{})
	return
}

// TransactionMutator is a interface that wraps the
// MutateTransaction operation.  types may implement this interface to
// specify how they modify an xdr.Transaction object
type TransactionMutator interface {
	MutateTransaction(*TransactionBuilder) error
}

// TransactionBuilder represents a Transaction that is being constructed.
type TransactionBuilder struct {
	TX        *xdr.Transaction
	NetworkID [32]byte
	Err       error
}

// Mutate applies the provided TransactionMutators to this builder's transaction
func (b *TransactionBuilder) Mutate(muts ...TransactionMutator) {
	if b.TX == nil {
		b.TX = &xdr.Transaction{}
	}

	for _, m := range muts {
		err := m.MutateTransaction(b)
		if err != nil {
			b.Err = err
			return
		}
	}
}

// Hash returns the hash of this builder's transaction.
func (b *TransactionBuilder) Hash() ([32]byte, error) {
	var txBytes bytes.Buffer

	_, err := fmt.Fprintf(&txBytes, "%s", b.NetworkID)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, xdr.EnvelopeTypeEnvelopeTypeTx)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, b.TX)
	if err != nil {
		return [32]byte{}, err
	}

	return hash.Hash(txBytes.Bytes()), nil
}

// HashHex returns the hex-encoded hash of this builder's transaction
func (b *TransactionBuilder) HashHex() (string, error) {
	hash, err := b.Hash()
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(hash[:]), nil
}

// Sign returns an new TransactionEnvelopeBuilder using this builder's
// transaction as the basis and with signatures of that transaction from the
// provided Signers.
func (b *TransactionBuilder) Sign(signers ...string) (result TransactionEnvelopeBuilder) {
	result.Mutate(b)

	for _, s := range signers {
		result.Mutate(Sign{s})
	}

	return
}

// ------------------------------------------------------------
//
//   Mutator implementations
//
// ------------------------------------------------------------

// MutateTransaction for CreateAccountBuilder causes the underylying
// CreateAccountOp to be added to the operation list for the provided
// transaction
func (m CreateAccountBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreateAccount, m.CA)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Defaults sets reasonable defaults on the transaction being built
func (m Defaults) MutateTransaction(o *TransactionBuilder) error {

	if o.TX.Fee == 0 {
		o.TX.Fee = xdr.Uint32(100 * len(o.TX.Operations))
	}

	if o.NetworkID == [32]byte{} {
		o.NetworkID = DefaultNetwork.ID()
	}
	return nil
}

// MutateTransaction for MemoHash sets the memo.
func (m MemoHash) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoHash, m.Value)
	return
}

// MutateTransaction for MemoID sets the memo.
func (m MemoID) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoId, xdr.Uint64(m.Value))
	return
}

// MutateTransaction for MemoReturn sets the memo.
func (m MemoReturn) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoReturn, m.Value)
	return
}

// MutateTransaction for MemoText sets the memo.
func (m MemoText) MutateTransaction(o *TransactionBuilder) (err error) {

	if len([]byte(m.Value)) > MemoTextMaxLength {
		err = errors.New("Memo too long; over 28 bytes")
		return
	}

	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoText, m.Value)
	return
}

// MutateTransaction for Network sets the Network ID to use when signing this transaction
func (m Network) MutateTransaction(o *TransactionBuilder) error {
	o.NetworkID = m.ID()
	return nil
}

// MutateTransaction for PaymentBuilder causes the underylying PaymentOp
// to be added to the operation list for the provided transaction
func (m PaymentBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePayment, m.P)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Sequence sets the SeqNum on the transaction.
func (m Sequence) MutateTransaction(o *TransactionBuilder) error {
	o.TX.SeqNum = xdr.SequenceNumber(m.Sequence)
	return nil
}

// MutateTransaction for SourceAccount sets the transaction's SourceAccount
// to the pubilic key for the address provided
func (m SourceAccount) MutateTransaction(o *TransactionBuilder) error {
	return setAccountId(m.AddressOrSeed, &o.TX.SourceAccount)
}
<commit_msg>AllowTrustBuilder.MutateTransaction<commit_after>package build

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"

	"github.com/stellar/go-stellar-base/hash"
	"github.com/stellar/go-stellar-base/xdr"
)

// Transaction groups the creation of a new TransactionBuilder with a call
// to Mutate.
func Transaction(muts ...TransactionMutator) (result *TransactionBuilder) {
	result = &TransactionBuilder{}
	result.Mutate(muts...)
	result.Mutate(Defaults{})
	return
}

// TransactionMutator is a interface that wraps the
// MutateTransaction operation.  types may implement this interface to
// specify how they modify an xdr.Transaction object
type TransactionMutator interface {
	MutateTransaction(*TransactionBuilder) error
}

// TransactionBuilder represents a Transaction that is being constructed.
type TransactionBuilder struct {
	TX        *xdr.Transaction
	NetworkID [32]byte
	Err       error
}

// Mutate applies the provided TransactionMutators to this builder's transaction
func (b *TransactionBuilder) Mutate(muts ...TransactionMutator) {
	if b.TX == nil {
		b.TX = &xdr.Transaction{}
	}

	for _, m := range muts {
		err := m.MutateTransaction(b)
		if err != nil {
			b.Err = err
			return
		}
	}
}

// Hash returns the hash of this builder's transaction.
func (b *TransactionBuilder) Hash() ([32]byte, error) {
	var txBytes bytes.Buffer

	_, err := fmt.Fprintf(&txBytes, "%s", b.NetworkID)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, xdr.EnvelopeTypeEnvelopeTypeTx)
	if err != nil {
		return [32]byte{}, err
	}

	_, err = xdr.Marshal(&txBytes, b.TX)
	if err != nil {
		return [32]byte{}, err
	}

	return hash.Hash(txBytes.Bytes()), nil
}

// HashHex returns the hex-encoded hash of this builder's transaction
func (b *TransactionBuilder) HashHex() (string, error) {
	hash, err := b.Hash()
	if err != nil {
		return "", err
	}

	return hex.EncodeToString(hash[:]), nil
}

// Sign returns an new TransactionEnvelopeBuilder using this builder's
// transaction as the basis and with signatures of that transaction from the
// provided Signers.
func (b *TransactionBuilder) Sign(signers ...string) (result TransactionEnvelopeBuilder) {
	result.Mutate(b)

	for _, s := range signers {
		result.Mutate(Sign{s})
	}

	return
}

// ------------------------------------------------------------
//
//   Mutator implementations
//
// ------------------------------------------------------------

// MutateTransaction for AllowTrustBuilder causes the underylying AllowTrustOp
// to be added to the operation list for the provided transaction
func (m AllowTrustBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeAllowTrust, m.AT)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for CreateAccountBuilder causes the underylying
// CreateAccountOp to be added to the operation list for the provided
// transaction
func (m CreateAccountBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreateAccount, m.CA)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Defaults sets reasonable defaults on the transaction being built
func (m Defaults) MutateTransaction(o *TransactionBuilder) error {

	if o.TX.Fee == 0 {
		o.TX.Fee = xdr.Uint32(100 * len(o.TX.Operations))
	}

	if o.NetworkID == [32]byte{} {
		o.NetworkID = DefaultNetwork.ID()
	}
	return nil
}

// MutateTransaction for MemoHash sets the memo.
func (m MemoHash) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoHash, m.Value)
	return
}

// MutateTransaction for MemoID sets the memo.
func (m MemoID) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoId, xdr.Uint64(m.Value))
	return
}

// MutateTransaction for MemoReturn sets the memo.
func (m MemoReturn) MutateTransaction(o *TransactionBuilder) (err error) {
	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoReturn, m.Value)
	return
}

// MutateTransaction for MemoText sets the memo.
func (m MemoText) MutateTransaction(o *TransactionBuilder) (err error) {

	if len([]byte(m.Value)) > MemoTextMaxLength {
		err = errors.New("Memo too long; over 28 bytes")
		return
	}

	o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoText, m.Value)
	return
}

// MutateTransaction for Network sets the Network ID to use when signing this transaction
func (m Network) MutateTransaction(o *TransactionBuilder) error {
	o.NetworkID = m.ID()
	return nil
}

// MutateTransaction for PaymentBuilder causes the underylying PaymentOp
// to be added to the operation list for the provided transaction
func (m PaymentBuilder) MutateTransaction(o *TransactionBuilder) error {
	if m.Err != nil {
		return m.Err
	}

	m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePayment, m.P)
	o.TX.Operations = append(o.TX.Operations, m.O)
	return m.Err
}

// MutateTransaction for Sequence sets the SeqNum on the transaction.
func (m Sequence) MutateTransaction(o *TransactionBuilder) error {
	o.TX.SeqNum = xdr.SequenceNumber(m.Sequence)
	return nil
}

// MutateTransaction for SourceAccount sets the transaction's SourceAccount
// to the pubilic key for the address provided
func (m SourceAccount) MutateTransaction(o *TransactionBuilder) error {
	return setAccountId(m.AddressOrSeed, &o.TX.SourceAccount)
}
<|endoftext|>


<commit_before>package api

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/sessions"
	"io/ioutil"
	"net/http"
)

/*
//API Register
router := api.Default()
apiRouter := router.Group("/api")
apiRouter.RequirePermission(true)
apiStoragesRouter := apiRouter.Group("/storages")
apiStoragesRouter.RequirePermission(true)
apiStoragesRouter.PUT("/", func(c *api.Context, s *sessions.Session) {
	c.Abort(http.StatusOK)
})
apiStoragesRouter.GET("/", func(c *api.Context, s *sessions.Session) {
	c.Resolve(http.StatusOK, "123")
})
apiStoragesRouter.POST("/", func(c *api.Context, s *sessions.Session) {
	c.Resolve(http.StatusOK, nil)
})
apiStoragesRouter.DELETE("/", func(c *api.Context, s *sessions.Session) {
	c.Abort(http.StatusOK)
})
*/
type Engine struct {
	gin   *gin.Engine
	store *sessions.CookieStore
	addr  string
}

type EngineGroup struct {
	engine      *Engine
	children    []*EngineGroup
	routerGroup *gin.RouterGroup
	path        string
	handlerHash map[string][]localAPIHandler
}

type localAPIHandler func(*Context)

type APIHandler func(*Context, *sessions.Session)

func Default(name string, addr string) *EngineGroup {
	engine := &Engine{
		gin:   gin.Default(),
		store: sessions.NewCookieStore([]byte(fmt.Sprintf("%s-Server-Store", name))),
		addr:  addr,
	}
	router := &EngineGroup{
		engine:      engine,
		children:    make([]*EngineGroup, 0, 16),
		routerGroup: nil,
		path:        "",
		handlerHash: make(map[string][]localAPIHandler),
	}
	engine.gin.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS")//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")//TEMP
        c.Next()
    })
	engine.gin.OPTIONS("/*all", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)//TEMP
	})
	apiLocalSupportRegister(addr, router)
	return router
}

func (this *EngineGroup) Group(path string) *EngineGroup {
	var routerGroup *gin.RouterGroup
	if this.routerGroup != nil {
		routerGroup = this.routerGroup.Group(path)
	} else {
		routerGroup = this.engine.gin.Group(path)
	}
	child := &EngineGroup{
		engine:      this.engine,
		routerGroup: routerGroup,
		path:        path,
		handlerHash: make(map[string][]localAPIHandler),
	}
	this.children = append(this.children, child)
	return child
}

const (
	METHOD_PUT    = iota
	METHOD_GET    = iota
	METHOD_POST   = iota
	METHOD_DELETE = iota
	method_COUNT  = iota
)

func (this *EngineGroup) register(method int, path string, handler APIHandler) {
	apiList, has := this.handlerHash[path]
	if !has {
		apiList = make([]localAPIHandler, method_COUNT)
		this.handlerHash[path] = apiList
	}
	apiList[method] = func(c *Context) {
		session, _ := this.engine.store.Get(c.Request, API_SESSION_NAME)
		handler(c, session)
		session.Save(c.Request, c.Writer)
	}

	handlerImp := this.getHandlerImp(handler)
	switch method {
	case METHOD_PUT:
		if this.routerGroup != nil {
			this.routerGroup.PUT(path, handlerImp)
		} else {
			this.engine.gin.PUT(path, handlerImp)
		}
	case METHOD_GET:
		if this.routerGroup != nil {
			this.routerGroup.GET(path, handlerImp)
		} else {
			this.engine.gin.GET(path, handlerImp)
		}
	case METHOD_POST:
		if this.routerGroup != nil {
			this.routerGroup.POST(path, handlerImp)
		} else {
			this.engine.gin.POST(path, handlerImp)
		}
	case METHOD_DELETE:
		if this.routerGroup != nil {
			this.routerGroup.DELETE(path, handlerImp)
		} else {
			this.engine.gin.DELETE(path, handlerImp)
		}
	}
}

func (this *EngineGroup) PUT(path string, handler APIHandler) {
	this.register(METHOD_PUT, path, handler)
}

func (this *EngineGroup) GET(path string, handler APIHandler) {
	this.register(METHOD_GET, path, handler)
}

func (this *EngineGroup) POST(path string, handler APIHandler) {
	this.register(METHOD_POST, path, handler)
}

func (this *EngineGroup) DELETE(path string, handler APIHandler) {
	this.register(METHOD_DELETE, path, handler)
}

func (this *EngineGroup) getHandlerImp(handler APIHandler) gin.HandlerFunc {
	return func(c *gin.Context) {
		var data interface{}
		body, _ := ioutil.ReadAll(c.Request.Body)
		err := json.Unmarshal(body, &data)
		if err != nil {
			var buffer bytes.Buffer
			buffer.Write(body)
			c.Request.Body = ioutil.NopCloser(bufio.NewReader(&buffer))
		}
		context := &Context{
			code:    unresolvedCode,
			ret:     nil,
			Data:    data,
			Params:  c.Params,
			QParams: c.Request.URL.Query(),
			Request: c.Request,
			Writer:  c.Writer,
		}
		session, _ := this.engine.store.Get(c.Request, API_SESSION_NAME)
		handler(context, session)
		session.Save(c.Request, c.Writer)
		switch context.code {
		case unresolvedCode:
			c.AbortWithStatus(http.StatusInternalServerError)
		case http.StatusMovedPermanently:
			c.Redirect(context.code, context.ret.(string))
		case http.StatusTemporaryRedirect:
			c.Redirect(context.code, context.ret.(string))
		default:
			switch context.ret.(type) {
			case nil:
				c.AbortWithStatus(context.code)
			case string:
				c.HTMLString(context.code, context.ret.(string))
				//c.String(context.code, context.ret.(string))
			default:
				c.JSON(context.code, context.ret)
			}
		}
	}
}

func (this *EngineGroup) Run() error {
	return this.engine.gin.Run(this.engine.addr)
}

func (this *EngineGroup) RunTLS(cert string, key string) error {
	return this.engine.gin.RunTLS(this.engine.addr, cert, key)
}
<commit_msg>add existance check for router.Group<commit_after>package api

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/sessions"
	"io/ioutil"
	"net/http"
)

/*
//API Register
router := api.Default()
apiRouter := router.Group("/api")
apiRouter.RequirePermission(true)
apiStoragesRouter := apiRouter.Group("/storages")
apiStoragesRouter.RequirePermission(true)
apiStoragesRouter.PUT("/", func(c *api.Context, s *sessions.Session) {
	c.Abort(http.StatusOK)
})
apiStoragesRouter.GET("/", func(c *api.Context, s *sessions.Session) {
	c.Resolve(http.StatusOK, "123")
})
apiStoragesRouter.POST("/", func(c *api.Context, s *sessions.Session) {
	c.Resolve(http.StatusOK, nil)
})
apiStoragesRouter.DELETE("/", func(c *api.Context, s *sessions.Session) {
	c.Abort(http.StatusOK)
})
*/
type Engine struct {
	gin   *gin.Engine
	store *sessions.CookieStore
	addr  string
}

type EngineGroup struct {
	engine      *Engine
	children    []*EngineGroup
	routerGroup *gin.RouterGroup
	path        string
	handlerHash map[string][]localAPIHandler
}

type localAPIHandler func(*Context)

type APIHandler func(*Context, *sessions.Session)

func Default(name string, addr string) *EngineGroup {
	engine := &Engine{
		gin:   gin.Default(),
		store: sessions.NewCookieStore([]byte(fmt.Sprintf("%s-Server-Store", name))),
		addr:  addr,
	}
	router := &EngineGroup{
		engine:      engine,
		children:    make([]*EngineGroup, 0, 16),
		routerGroup: nil,
		path:        "",
		handlerHash: make(map[string][]localAPIHandler),
	}
	engine.gin.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", c.Request.Header.Get("Origin"))//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS")//TEMP
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")//TEMP
        c.Next()
    })
	engine.gin.OPTIONS("/*all", func(c *gin.Context) {
		c.AbortWithStatus(http.StatusOK)//TEMP
	})
	apiLocalSupportRegister(addr, router)
	return router
}

func (this *EngineGroup) Group(path string) *EngineGroup {
	var routerGroup *gin.RouterGroup
	for _, child := range this.children {
		if path == child.path {
			return child
		}
	}
	if this.routerGroup != nil {
		routerGroup = this.routerGroup.Group(path)
	} else {
		routerGroup = this.engine.gin.Group(path)
	}
	child := &EngineGroup{
		engine:      this.engine,
		routerGroup: routerGroup,
		path:        path,
		handlerHash: make(map[string][]localAPIHandler),
	}
	this.children = append(this.children, child)
	return child
}

const (
	METHOD_PUT    = iota
	METHOD_GET    = iota
	METHOD_POST   = iota
	METHOD_DELETE = iota
	method_COUNT  = iota
)

func (this *EngineGroup) register(method int, path string, handler APIHandler) {
	apiList, has := this.handlerHash[path]
	if !has {
		apiList = make([]localAPIHandler, method_COUNT)
		this.handlerHash[path] = apiList
	}
	apiList[method] = func(c *Context) {
		session, _ := this.engine.store.Get(c.Request, API_SESSION_NAME)
		handler(c, session)
		session.Save(c.Request, c.Writer)
	}

	handlerImp := this.getHandlerImp(handler)
	switch method {
	case METHOD_PUT:
		if this.routerGroup != nil {
			this.routerGroup.PUT(path, handlerImp)
		} else {
			this.engine.gin.PUT(path, handlerImp)
		}
	case METHOD_GET:
		if this.routerGroup != nil {
			this.routerGroup.GET(path, handlerImp)
		} else {
			this.engine.gin.GET(path, handlerImp)
		}
	case METHOD_POST:
		if this.routerGroup != nil {
			this.routerGroup.POST(path, handlerImp)
		} else {
			this.engine.gin.POST(path, handlerImp)
		}
	case METHOD_DELETE:
		if this.routerGroup != nil {
			this.routerGroup.DELETE(path, handlerImp)
		} else {
			this.engine.gin.DELETE(path, handlerImp)
		}
	}
}

func (this *EngineGroup) PUT(path string, handler APIHandler) {
	this.register(METHOD_PUT, path, handler)
}

func (this *EngineGroup) GET(path string, handler APIHandler) {
	this.register(METHOD_GET, path, handler)
}

func (this *EngineGroup) POST(path string, handler APIHandler) {
	this.register(METHOD_POST, path, handler)
}

func (this *EngineGroup) DELETE(path string, handler APIHandler) {
	this.register(METHOD_DELETE, path, handler)
}

func (this *EngineGroup) getHandlerImp(handler APIHandler) gin.HandlerFunc {
	return func(c *gin.Context) {
		var data interface{}
		body, _ := ioutil.ReadAll(c.Request.Body)
		err := json.Unmarshal(body, &data)
		if err != nil {
			var buffer bytes.Buffer
			buffer.Write(body)
			c.Request.Body = ioutil.NopCloser(bufio.NewReader(&buffer))
		}
		context := &Context{
			code:    unresolvedCode,
			ret:     nil,
			Data:    data,
			Params:  c.Params,
			QParams: c.Request.URL.Query(),
			Request: c.Request,
			Writer:  c.Writer,
		}
		session, _ := this.engine.store.Get(c.Request, API_SESSION_NAME)
		handler(context, session)
		session.Save(c.Request, c.Writer)
		switch context.code {
		case unresolvedCode:
			c.AbortWithStatus(http.StatusInternalServerError)
		case http.StatusMovedPermanently:
			c.Redirect(context.code, context.ret.(string))
		case http.StatusTemporaryRedirect:
			c.Redirect(context.code, context.ret.(string))
		default:
			switch context.ret.(type) {
			case nil:
				c.AbortWithStatus(context.code)
			case string:
				c.HTMLString(context.code, context.ret.(string))
				//c.String(context.code, context.ret.(string))
			default:
				c.JSON(context.code, context.ret)
			}
		}
	}
}

func (this *EngineGroup) Run() error {
	return this.engine.gin.Run(this.engine.addr)
}

func (this *EngineGroup) RunTLS(cert string, key string) error {
	return this.engine.gin.RunTLS(this.engine.addr, cert, key)
}
<|endoftext|>


<commit_before>package api

// RootResponse object which will be formatted to json and sent back to google and onto the user.
type RootResponse struct {
	ConversationToken  string          `json:"conversation_token,omitempty"`
	ExpectUserResponse bool            `json:"expect_user_response"`
	ExpectedInputs     []ExpectedInput `json:"expected_inputs"`
	FinalResponse_     FinalResponse   `json:"final_response"`
}

type ExpectedInput struct {
	PossibleIntents []ExpectedIntent `json:"possible_intents"`
}

type ExpectedIntent struct {
	Intent          string         `json:"intent"`
	InputValueSpec_ InputValueSpec `json:"input_value_spec"`
}

type FinalResponse struct {
	SpeechResponse_ SpeechResponse `json:"speech_response"`
}

type InputValueSpec struct {
	PermissionValueSpec_ PermissionValueSpec `json:"permission_value_spec"`
}

type PermissionValueSpec struct {
	OptContext  string   `json:"opt_context"`
	Permissions []string `json:"permissions"`
}

type SpeechResponse struct {
	TextToSpeech string `json:"text_to_speech"`
	SSML         string `json:"ssml"`
}
<commit_msg>Add missing struct<commit_after>package api

// RootResponse object which will be formatted to json and sent back to google and onto the user.
type RootResponse struct {
	ConversationToken  string          `json:"conversation_token,omitempty"`
	ExpectUserResponse bool            `json:"expect_user_response"`
	ExpectedInputs     []ExpectedInput `json:"expected_inputs"`
	FinalResponse_     FinalResponse   `json:"final_response"`
}

type ExpectedInput struct {
	PossibleIntents []ExpectedIntent `json:"possible_intents"`
	InputPrompt_    InputPrompt      `json:"input_prompt"`
}

type ExpectedIntent struct {
	Intent          string         `json:"intent"`
	InputValueSpec_ InputValueSpec `json:"input_value_spec"`
}

type FinalResponse struct {
	SpeechResponse_ SpeechResponse `json:"speech_response"`
}

type InputValueSpec struct {
	PermissionValueSpec_ PermissionValueSpec `json:"permission_value_spec"`
}

type PermissionValueSpec struct {
	OptContext  string   `json:"opt_context"`
	Permissions []string `json:"permissions"`
}

type SpeechResponse struct {
	TextToSpeech string `json:"text_to_speech"`
	SSML         string `json:"ssml"`
}

type InputPrompt struct {
	InitialPrompts []SpeechResponse `json:"initial_prompts"`
	NoInputPrompts []SpeechResponse `json:"no_input_prompts"`
}
<|endoftext|>