<commit_before>package goscaleio

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	types "github.com/emccode/goscaleio/types/v1"
)

type Client struct {
	Token       string
	SIOEndpoint url.URL
	Http        http.Client
	Insecure    string
	ShowBody    bool
	configConnect *ConfigConnect
}

type Cluster struct {
}

type ConfigConnect struct {
	Endpoint string
	Version  string
	Username string
	Password string
}

type ClientPersistent struct {
	configConnect *ConfigConnect
	client        *Client
}

func (client *Client) getVersion() (string, error) {
	endpoint := client.SIOEndpoint
	endpoint.Path = "/api/version"

	req := client.NewRequest(map[string]string{}, "GET", endpoint, nil)
	req.SetBasicAuth("", client.Token)

	resp, err := client.retryCheckResp(&client.Http, req)
	if err != nil {
		return "", fmt.Errorf("problem getting response: %v", err)
	}
	defer resp.Body.Close()

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", errors.New("error reading body")
	}

	version := string(bs)

	if client.ShowBody {
		log.WithField("body", version).Debug(
			"printing version message body")
	}

	version = strings.TrimRight(version, `"`)
	version = strings.TrimLeft(version, `"`)

	return version, nil
}

func (client *Client) updateVersion() error {

	version, err := client.getVersion()
	if err != nil {
		return err
	}
	client.configConnect.Version = version

	return nil
}

func (client *Client) Authenticate(configConnect *ConfigConnect) (Cluster, error) {

	configConnect.Version = client.configConnect.Version
	client.configConnect = configConnect

	endpoint := client.SIOEndpoint
	endpoint.Path += "/login"

	req := client.NewRequest(map[string]string{}, "GET", endpoint, nil)
	req.SetBasicAuth(configConnect.Username, configConnect.Password)

	resp, err := client.retryCheckResp(&client.Http, req)
	if err != nil {
		return Cluster{}, fmt.Errorf("problem getting response: %v", err)
	}
	defer resp.Body.Close()

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return Cluster{}, errors.New("error reading body")
	}

	token := string(bs)

	if client.ShowBody {
		log.WithField("body", token).Debug(
			"printing authentication message body")
	}

	token = strings.TrimRight(token, `"`)
	token = strings.TrimLeft(token, `"`)
	client.Token = token

	if client.configConnect.Version == "" {
		err = client.updateVersion()
		if err != nil {
			return Cluster{}, errors.New("error getting version of ScaleIO")
		}
	}

	return Cluster{}, nil
}

//https://github.com/chrislusf/teeproxy/blob/master/teeproxy.go
type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

func DuplicateRequest(request *http.Request) (request1 *http.Request, request2 *http.Request) {
	request1 = &http.Request{
		Method:        request.Method,
		URL:           request.URL,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Header:        request.Header,
		Host:          request.Host,
		ContentLength: request.ContentLength,
	}
	request2 = &http.Request{
		Method:        request.Method,
		URL:           request.URL,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Header:        request.Header,
		Host:          request.Host,
		ContentLength: request.ContentLength,
	}

	if request.Body != nil {
		b1 := new(bytes.Buffer)
		b2 := new(bytes.Buffer)
		w := io.MultiWriter(b1, b2)
		io.Copy(w, request.Body)
		request1.Body = nopCloser{b1}
		request2.Body = nopCloser{b2}

		defer request.Body.Close()
	}

	return
}

func (client *Client) retryCheckResp(httpClient *http.Client, req *http.Request) (*http.Response, error) {

	req1, req2 := DuplicateRequest(req)
	resp, errBody, err := client.checkResp(httpClient.Do(req1))
	if errBody == nil && err != nil {
		return &http.Response{}, err
	} else if errBody != nil && err != nil {
		if resp == nil {
			return nil, errors.New("Problem getting response from endpoint")
		}

		if resp.StatusCode == 401 && errBody.MajorErrorCode == 0 {
			_, err := client.Authenticate(client.configConnect)
			if err != nil {
				return nil, fmt.Errorf("Error re-authenticating: %s", err)
			}

			ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			req2.SetBasicAuth("", client.Token)
			resp, errBody, err = client.checkResp(httpClient.Do(req2))
			if err != nil {
				return &http.Response{}, errors.New(errBody.Message)
			}
		} else {
			return &http.Response{}, errors.New(errBody.Message)
		}
	}

	return resp, nil
}

func (client *Client) checkResp(resp *http.Response, err error) (*http.Response, *types.Error, error) {
	if err != nil {
		return resp, &types.Error{}, err
	}

	switch i := resp.StatusCode; {
	// Valid request, return the response.
	case i == 200 || i == 201 || i == 202 || i == 204:
		return resp, &types.Error{}, nil
	// Invalid request, parse the XML error returned and return it.
	case i == 400 || i == 401 || i == 403 || i == 404 || i == 405 || i == 406 || i == 409 || i == 415 || i == 500 || i == 503 || i == 504:
		errBody, err := client.parseErr(resp)
		return resp, errBody, err
	// Unhandled response.
	default:
		return nil, &types.Error{}, fmt.Errorf("unhandled API response, please report this issue, status code: %s", resp.Status)
	}
}

func (client *Client) decodeBody(resp *http.Response, out interface{}) error {

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if client.ShowBody {
		var prettyJSON bytes.Buffer
		_ = json.Indent(&prettyJSON, body, "", "  ")
		log.WithField("body", prettyJSON.String()).Debug(
			"print decoded body")
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func (client *Client) parseErr(resp *http.Response) (*types.Error, error) {

	errBody := new(types.Error)

	// if there was an error decoding the body, just return that
	if err := client.decodeBody(resp, errBody); err != nil {
		return &types.Error{}, fmt.Errorf("error parsing error body for non-200 request: %s", err)
	}

	return errBody, fmt.Errorf("API (%d) Error: %d: %s", resp.StatusCode, errBody.MajorErrorCode, errBody.Message)
}

func (c *Client) NewRequest(params map[string]string, method string, u url.URL, body io.Reader) *http.Request {

	if log.GetLevel() == log.DebugLevel && c.ShowBody && body != nil {
		buf := new(bytes.Buffer)
		buf.ReadFrom(body)
		log.WithField("body", buf.String()).Debug("print new request body")
	}

	p := url.Values{}

	for k, v := range params {
		p.Add(k, v)
	}

	u.RawQuery = p.Encode()

	req, _ := http.NewRequest(method, u.String(), body)

	return req

}

func NewClient() (client *Client, err error) {
	return NewClientWithArgs(
		os.Getenv("GOSCALEIO_ENDPOINT"),
		os.Getenv("GOSCALEIO_VERSION"),
		os.Getenv("GOSCALEIO_INSECURE") == "true",
		os.Getenv("GOSCALEIO_USECERTS") == "true")
}

func NewClientWithArgs(
	endpoint string,
	version string,
	insecure,
	useCerts bool) (client *Client, err error) {

	fields := map[string]interface{}{
		"endpoint": endpoint,
		"insecure": insecure,
		"useCerts": useCerts,
		"version":  version,
	}

	var uri *url.URL

	if endpoint != "" {
		uri, err = url.ParseRequestURI(endpoint)
		if err != nil {
			return &Client{},
				withFieldsE(fields, "error parsing endpoint", err)
		}
	} else {
		return &Client{},
			withFields(fields, "endpoint is required")
	}

	client = &Client{
		SIOEndpoint: *uri,
		Http: http.Client{
			Transport: &http.Transport{
				TLSHandshakeTimeout: 120 * time.Second,
				TLSClientConfig: &tls.Config{
					InsecureSkipVerify: insecure,
				},
			},
		},
	}

	if useCerts {
		pool := x509.NewCertPool()
		pool.AppendCertsFromPEM(pemCerts)

		client.Http.Transport = &http.Transport{
			TLSHandshakeTimeout: 120 * time.Second,
			TLSClientConfig: &tls.Config{
				RootCAs:            pool,
				InsecureSkipVerify: insecure,
			},
		}
	}

	client.configConnect = &ConfigConnect{
		Version: version,
	}

	return client, nil
}

func GetLink(links []*types.Link, rel string) (*types.Link, error) {
	for _, link := range links {
		if link.Rel == rel {
			return link, nil
		}
	}

	return &types.Link{}, errors.New("Couldn't find link")
}

func withFields(fields map[string]interface{}, message string) error {
	return withFieldsE(fields, message, nil)
}

func withFieldsE(
	fields map[string]interface{}, message string, inner error) error {

	if fields == nil {
		fields = make(map[string]interface{})
	}

	if inner != nil {
		fields["inner"] = inner
	}

	x := 0
	l := len(fields)

	var b bytes.Buffer
	for k, v := range fields {
		if x < l-1 {
			b.WriteString(fmt.Sprintf("%s=%v,", k, v))
		} else {
			b.WriteString(fmt.Sprintf("%s=%v", k, v))
		}
		x = x + 1
	}

	return newf("%s %s", message, b.String())
}

func newf(format string, a ...interface{}) error {
	return errors.New(fmt.Sprintf(format, a))
}
<commit_msg>Fixed endless auth loop on failure<commit_after>package goscaleio

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	types "github.com/emccode/goscaleio/types/v1"
)

type Client struct {
	Token         string
	SIOEndpoint   url.URL
	Http          http.Client
	Insecure      string
	ShowBody      bool
	configConnect *ConfigConnect
}

type Cluster struct {
}

type ConfigConnect struct {
	Endpoint string
	Version  string
	Username string
	Password string
}

type ClientPersistent struct {
	configConnect *ConfigConnect
	client        *Client
}

func (client *Client) getVersion() (string, error) {
	endpoint := client.SIOEndpoint
	endpoint.Path = "/api/version"

	req := client.NewRequest(map[string]string{}, "GET", endpoint, nil)
	req.SetBasicAuth("", client.Token)

	resp, err := client.retryCheckResp(&client.Http, req)
	if err != nil {
		return "", fmt.Errorf("problem getting response: %v", err)
	}
	defer resp.Body.Close()

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", errors.New("error reading body")
	}

	version := string(bs)

	if client.ShowBody {
		log.WithField("body", version).Debug(
			"printing version message body")
	}

	version = strings.TrimRight(version, `"`)
	version = strings.TrimLeft(version, `"`)

	return version, nil
}

func (client *Client) updateVersion() error {

	version, err := client.getVersion()
	if err != nil {
		return err
	}
	client.configConnect.Version = version

	return nil
}

func (client *Client) Authenticate(configConnect *ConfigConnect) (Cluster, error) {

	configConnect.Version = client.configConnect.Version
	client.configConnect = configConnect

	endpoint := client.SIOEndpoint
	endpoint.Path += "/login"

	req := client.NewRequest(map[string]string{}, "GET", endpoint, nil)
	req.SetBasicAuth(configConnect.Username, configConnect.Password)

	httpClient := &client.Http
	resp, errBody, err := client.checkResp(httpClient.Do(req))
	defer resp.Body.Close()
	if errBody == nil && err != nil {
		return Cluster{}, err
	} else if errBody != nil && err != nil {
		if resp == nil {
			return Cluster{}, errors.New("Problem getting response from endpoint")
		}
		return Cluster{}, errors.New(errBody.Message)
	}

	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return Cluster{}, errors.New("error reading body")
	}

	token := string(bs)

	if client.ShowBody {
		log.WithField("body", token).Debug(
			"printing authentication message body")
	}

	token = strings.TrimRight(token, `"`)
	token = strings.TrimLeft(token, `"`)
	client.Token = token

	if client.configConnect.Version == "" {
		err = client.updateVersion()
		if err != nil {
			return Cluster{}, errors.New("error getting version of ScaleIO")
		}
	}

	return Cluster{}, nil
}

//https://github.com/chrislusf/teeproxy/blob/master/teeproxy.go
type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

func DuplicateRequest(request *http.Request) (request1 *http.Request, request2 *http.Request) {
	request1 = &http.Request{
		Method:        request.Method,
		URL:           request.URL,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Header:        request.Header,
		Host:          request.Host,
		ContentLength: request.ContentLength,
	}
	request2 = &http.Request{
		Method:        request.Method,
		URL:           request.URL,
		Proto:         "HTTP/1.1",
		ProtoMajor:    1,
		ProtoMinor:    1,
		Header:        request.Header,
		Host:          request.Host,
		ContentLength: request.ContentLength,
	}

	if request.Body != nil {
		b1 := new(bytes.Buffer)
		b2 := new(bytes.Buffer)
		w := io.MultiWriter(b1, b2)
		io.Copy(w, request.Body)
		request1.Body = nopCloser{b1}
		request2.Body = nopCloser{b2}

		defer request.Body.Close()
	}

	return
}

func (client *Client) retryCheckResp(httpClient *http.Client, req *http.Request) (*http.Response, error) {

	req1, req2 := DuplicateRequest(req)
	resp, errBody, err := client.checkResp(httpClient.Do(req1))
	if errBody == nil && err != nil {
		return &http.Response{}, err
	} else if errBody != nil && err != nil {
		if resp == nil {
			return nil, errors.New("Problem getting response from endpoint")
		}

		if resp.StatusCode == 401 && errBody.MajorErrorCode == 0 {
			_, err := client.Authenticate(client.configConnect)
			if err != nil {
				return nil, fmt.Errorf("Error re-authenticating: %s", err)
			}

			ioutil.ReadAll(resp.Body)
			resp.Body.Close()

			req2.SetBasicAuth("", client.Token)
			resp, errBody, err = client.checkResp(httpClient.Do(req2))
			if err != nil {
				return &http.Response{}, errors.New(errBody.Message)
			}
		} else {
			return &http.Response{}, errors.New(errBody.Message)
		}
	}

	return resp, nil
}

func (client *Client) checkResp(resp *http.Response, err error) (*http.Response, *types.Error, error) {
	if err != nil {
		return resp, &types.Error{}, err
	}

	switch i := resp.StatusCode; {
	// Valid request, return the response.
	case i == 200 || i == 201 || i == 202 || i == 204:
		return resp, &types.Error{}, nil
	// Invalid request, parse the XML error returned and return it.
	case i == 400 || i == 401 || i == 403 || i == 404 || i == 405 || i == 406 || i == 409 || i == 415 || i == 500 || i == 503 || i == 504:
		errBody, err := client.parseErr(resp)
		return resp, errBody, err
	// Unhandled response.
	default:
		return nil, &types.Error{}, fmt.Errorf("unhandled API response, please report this issue, status code: %s", resp.Status)
	}
}

func (client *Client) decodeBody(resp *http.Response, out interface{}) error {

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if client.ShowBody {
		var prettyJSON bytes.Buffer
		_ = json.Indent(&prettyJSON, body, "", "  ")
		log.WithField("body", prettyJSON.String()).Debug(
			"print decoded body")
	}

	if err = json.Unmarshal(body, &out); err != nil {
		return err
	}

	return nil
}

func (client *Client) parseErr(resp *http.Response) (*types.Error, error) {

	errBody := new(types.Error)

	// if there was an error decoding the body, just return that
	if err := client.decodeBody(resp, errBody); err != nil {
		return &types.Error{}, fmt.Errorf("error parsing error body for non-200 request: %s", err)
	}

	return errBody, fmt.Errorf("API (%d) Error: %d: %s", resp.StatusCode, errBody.MajorErrorCode, errBody.Message)
}

func (c *Client) NewRequest(params map[string]string, method string, u url.URL, body io.Reader) *http.Request {

	if log.GetLevel() == log.DebugLevel && c.ShowBody && body != nil {
		buf := new(bytes.Buffer)
		buf.ReadFrom(body)
		log.WithField("body", buf.String()).Debug("print new request body")
	}

	p := url.Values{}

	for k, v := range params {
		p.Add(k, v)
	}

	u.RawQuery = p.Encode()

	req, _ := http.NewRequest(method, u.String(), body)

	return req

}

func NewClient() (client *Client, err error) {
	return NewClientWithArgs(
		os.Getenv("GOSCALEIO_ENDPOINT"),
		os.Getenv("GOSCALEIO_VERSION"),
		os.Getenv("GOSCALEIO_INSECURE") == "true",
		os.Getenv("GOSCALEIO_USECERTS") == "true")
}

func NewClientWithArgs(
	endpoint string,
	version string,
	insecure,
	useCerts bool) (client *Client, err error) {

	fields := map[string]interface{}{
		"endpoint": endpoint,
		"insecure": insecure,
		"useCerts": useCerts,
		"version":  version,
	}

	var uri *url.URL

	if endpoint != "" {
		uri, err = url.ParseRequestURI(endpoint)
		if err != nil {
			return &Client{},
				withFieldsE(fields, "error parsing endpoint", err)
		}
	} else {
		return &Client{},
			withFields(fields, "endpoint is required")
	}

	client = &Client{
		SIOEndpoint: *uri,
		Http: http.Client{
			Transport: &http.Transport{
				TLSHandshakeTimeout: 120 * time.Second,
				TLSClientConfig: &tls.Config{
					InsecureSkipVerify: insecure,
				},
			},
		},
	}

	if useCerts {
		pool := x509.NewCertPool()
		pool.AppendCertsFromPEM(pemCerts)

		client.Http.Transport = &http.Transport{
			TLSHandshakeTimeout: 120 * time.Second,
			TLSClientConfig: &tls.Config{
				RootCAs:            pool,
				InsecureSkipVerify: insecure,
			},
		}
	}

	client.configConnect = &ConfigConnect{
		Version: version,
	}

	return client, nil
}

func GetLink(links []*types.Link, rel string) (*types.Link, error) {
	for _, link := range links {
		if link.Rel == rel {
			return link, nil
		}
	}

	return &types.Link{}, errors.New("Couldn't find link")
}

func withFields(fields map[string]interface{}, message string) error {
	return withFieldsE(fields, message, nil)
}

func withFieldsE(
	fields map[string]interface{}, message string, inner error) error {

	if fields == nil {
		fields = make(map[string]interface{})
	}

	if inner != nil {
		fields["inner"] = inner
	}

	x := 0
	l := len(fields)

	var b bytes.Buffer
	for k, v := range fields {
		if x < l-1 {
			b.WriteString(fmt.Sprintf("%s=%v,", k, v))
		} else {
			b.WriteString(fmt.Sprintf("%s=%v", k, v))
		}
		x = x + 1
	}

	return newf("%s %s", message, b.String())
}

func newf(format string, a ...interface{}) error {
	return errors.New(fmt.Sprintf(format, a))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/hoisie/web"
	"io/ioutil"
	"strconv"
)

var allowed_speeds = []int{40, 60, 80, 100, 120}

func contains(a int, list []int) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func check_coordinate_sanity(matrix []Coord, country string) (bool, error) {
	bbox := bounding_boxes[country]

	verify := func(pair []float64) bool {
		lat, long := pair[0], pair[1]
		if long > bbox["long_max"] || long < bbox["long_min"] || lat > bbox["lat_max"] || lat < bbox["lat_min"] {
			return false
		}
		return true
	}

	for i, pair := range matrix {
		res := verify(pair)
		if !res {
			return false, errors.New(fmt.Sprintf("Coordinate (lat: %f, long: %f) at matrix index %d is outside the limits for country \"%s\" which is %vi. Make sure you use [[LAT, LONG]...].", pair[0], pair[1], i, country, bbox))
		}
	}
	return true, nil
}

// Starts a computation, validates the matrix in POST.
// If matrix data is missing, returns 400 Bad Request.
// If on the other hand matrix is data is not missing,
// but makes no sense, it returns 422 Unprocessable Entity.
func (server *Server) PostMatrix(ctx *web.Context) {
	var hash string
	var computed bool
	params := []string{"matrix", "speed_profile", "country"}

	body := ctx.Request.Body

	var buf bytes.Buffer
	buf.ReadFrom(body)
	bodyParams := buf.Bytes()
	debug.Println(buf.String())
	var paramBlob map[string]interface{}
	// Parse params
	json.Unmarshal(bodyParams, &paramBlob)

	ok := false
	for _, param := range params {
		// ok will be set to false if ctx.Params doesn't contain param
		_, ok = paramBlob[param]
	}

	if ok {
		data := paramBlob["matrix"].(string)
		country := paramBlob["country"].(string)
		sp, jep := paramBlob["speed_profile"].(float64)

		speed_profile := int(sp)
		// Sanitize speed profile.
		if !jep || !contains(speed_profile, allowed_speeds) {
			msg := fmt.Sprintf("speed profile '%d' makes no sense, must be one of %s", speed_profile, fmt.Sprint(allowed_speeds))
			ctx.Abort(422, msg)
			return
		}
		// Sanitize country.
		if _, ok := server.AllowedCountries[country]; !ok {
			countries := ""
			for k := range server.AllowedCountries {
				countries += k + " "
			}
			ctx.Abort(422, "country "+country+" not allowed, must be one of: "+countries)
			return
		}

		mat, err := parse_json_matrix(data)
		if err != nil {
			ctx.Abort(422, err.Error())
			return
		}

		ok, err = check_coordinate_sanity(mat, country)
		if err != nil {
			ctx.Abort(422, err.Error())
			return
		}

		hash, computed = server.CreateMatrixComputation(mat, country, int(speed_profile))

		// launch computation here if the result wasn't proxied.
		if !computed {
			go server.ComputeMatrix(hash)
		}
	} else {
		ctx.Abort(400, "Missing matrix data or speed profile or country. You sent: "+buf.String())
		return
	}

	loc := fmt.Sprintf("/spp/%s", hash)

	ctx.Redirect(201, loc)
}

// Returns a computation from the server as identified by the resource parameter
// in GET.
func (server *Server) GetMatrix(ctx *web.Context, resource string) string {
	progress, err := server.GetMatrixComputationProgress(resource)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	if progress == "complete" {
		url := fmt.Sprintf("/spp/%s/result", resource)
		debug.Println("redirect ->", url)
		ctx.Redirect(303, url)
	} else {
		ctx.ContentType("json")
		msg := fmt.Sprintf(`{ "progress": "%s" }`, progress)
		return msg
	}

	return ""
}

func (server *Server) GetMatrixResult(ctx *web.Context, resource string) string {
	if ex, _ := server.client.Exists(resource); !ex {
		ctx.Abort(500, "Result expired. POST again.")
		return ""
	}

	progress, err := server.GetMatrixComputationProgress(resource)
	if progress != "complete" {
		ctx.Abort(403, "Computation is not ready yet.")
		return ""
	}

	if exists, _ := server.client.Hexists(resource, "see"); exists {
		debug.Println("Got proxy result")
		pointer, _ := server.client.Hget(resource, "see")
		resource = string(pointer)
	}

	data, err := server.client.Hget(resource, "result")
	if err != nil {
		ctx.Abort(500, "Redis error: "+err.Error())
		return ""
	}

	if data != nil {
		ctx.ContentType("json")
		return fmt.Sprintf("{ \"Matrix\": %s }", string(data))
	}

	return ""
}

func (server *Server) GetServerStatus(ctx *web.Context) string {
	db, _ := sql.Open("postgres", server.Config.String())
	defer db.Close()

	err := db.Ping()

	if err != nil {
		ctx.Abort(500, "Could not connect to database: "+err.Error())
		return ""
	}

	return "OK"
}

func (server *Server) GetCorrectCoordinate(ctx *web.Context) string {
	s_lat, lat_ok := ctx.Params["lat"]
	s_long, long_ok := ctx.Params["long"]

	// TODO(ane): implement automatic lookup of country
	s_country, country_ok := ctx.Params["country"]

	if !lat_ok || !long_ok || !country_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need lat, long, country, you gave: %q", ctx.Params))
		return ""
	}

	lat, err := strconv.ParseFloat(s_lat, 32)
	if err != nil {
		ctx.Abort(400, fmt.Sprintf("Latitude %s is invalid, cannot parse!", s_lat))
	}

	long, err := strconv.ParseFloat(s_long, 32)
	if err != nil {
		ctx.Abort(400, fmt.Sprintf("Longitude %s is invalid, cannot parse!", s_long))
	}

	if _, ok := server.Config.AllowedCountries[s_country]; !ok {
		ctx.Abort(500, fmt.Sprintf("Country %s not allowed", s_country))
	}

	coord := Coord{lat, long}

	corr_node, err := CorrectPoint(server.Config, coord, s_country)
	if err != nil {
		ctx.Abort(500, err.Error())
	}

	response, err := json.Marshal(corr_node)
	if err != nil {
		ctx.Abort(500, err.Error())
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(response)
}

func (server *Server) GetNodesToCoordinates(ctx *web.Context) string {
	nodes, ex := ctx.Params["nodes"]
	country, ex2 := ctx.Params["country"]

	if !ex || !ex2 {
		ctx.Abort(400, fmt.Sprintf("Missing parameter: either nodes or country is missing"))
		return ""
	}

	var parsedNodes []int
	if err := json.Unmarshal([]byte(nodes), &parsedNodes); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	coordinates, err := GetCoordinates(server.Config, country, parsedNodes)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	cont, err := json.Marshal(coordinates)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(cont)
}

func (server *Server) GetPath(ctx *web.Context) string {
	p_source, p_source_ok := ctx.Params["source"]
	p_target, p_target_ok := ctx.Params["target"]
	p_country, p_country_ok := ctx.Params["country"]
	p_sp, p_sp_ok := ctx.Params["speed_profile"]

	if !p_source_ok || !p_target_ok || !p_country_ok || !p_sp_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need country, speed_profile, source, target; you gave: %q", ctx.Params))
		return ""
	}

	if _, ok := server.Config.AllowedCountries[p_country]; !ok {
		ctx.Abort(500, fmt.Sprintf("Country %s not allowed", p_country))
		return ""
	}

	source, _ := strconv.Atoi(p_source)
	target, _ := strconv.Atoi(p_target)
	sp, _ := strconv.Atoi(p_sp)

	path, err := CalculatePath(source, target, p_country, sp)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	data, err := json.Marshal(path)
	if err != nil {
		ctx.Abort(500, "json error: "+err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(data)
}

func (server *Server) GetFuzzyAddress(ctx *web.Context) string {
	p_addr, p_addr_ok := ctx.Params["address"]
	p_country, p_country_ok := ctx.Params["country"]
	p_limit, p_limit_ok := ctx.Params["limit"]
	var limit int

	if !p_addr_ok || !p_country_ok {
		ctx.Abort(400, fmt.Sprintf("Missing address or country."))
		return ""
	}

	if !p_limit_ok {
		limit = 5
	} else {
		limit, _ = strconv.Atoi(p_limit)
	}

	if p_country != "finland" {
		ctx.Abort(400, fmt.Sprintf("Only Finland is supported atm."))
		return ""
	}

	ctx.ContentType("application/json")

	addresses, err := GetFuzzyAddress(server.Config, p_addr, limit)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	if addresses == nil {
		return "{}"
	}

	addresses_json, err := json.Marshal(addresses)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	return string(addresses_json)
}

func (server *Server) GetCoordinatePath(ctx *web.Context) string {
	p_source, p_source_ok := ctx.Params["source"]
	p_target, p_target_ok := ctx.Params["target"]
	p_sp, p_sp_ok := ctx.Params["speed_profile"]

	if !p_source_ok || !p_target_ok || !p_sp_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need speed_profile, source, target; you gave: %q", ctx.Params))
		return ""
	}

	var sourceAddr, targetAddr Location
	if err := json.Unmarshal([]byte(p_source), &sourceAddr); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	if err := json.Unmarshal([]byte(p_target), &targetAddr); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	sp, _ := strconv.Atoi(p_sp)

	result, err := CalculateCoordinatePathFromAddresses(server.Config, sourceAddr, targetAddr, sp)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	jsonResult, err := json.Marshal(result)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.ContentType("application/json")
	return string(jsonResult)
}

func (server *Server) PostResolve(ctx *web.Context) string {
	content, err := ioutil.ReadAll(ctx.Request.Body)
	var locations, resolvedLocations []Location

	// Parse params
	if err := json.Unmarshal(content, &locations); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	} else {
		for i := 0; i < len(locations); i++ {
			newLoc, err := ResolveLocation(server.Config, locations[i])
			if err != nil {
				ctx.Abort(422, err.Error())
				return ""
			}
			resolvedLocations = append(resolvedLocations, newLoc)
		}
	}

	res, err := json.Marshal(resolvedLocations)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.ContentType("application/json")
	return string(res)
}
<commit_msg>Add CORS.<commit_after>package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/hoisie/web"
	"io/ioutil"
	"strconv"
)

var allowed_speeds = []int{40, 60, 80, 100, 120}

func contains(a int, list []int) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func check_coordinate_sanity(matrix []Coord, country string) (bool, error) {
	bbox := bounding_boxes[country]

	verify := func(pair []float64) bool {
		lat, long := pair[0], pair[1]
		if long > bbox["long_max"] || long < bbox["long_min"] || lat > bbox["lat_max"] || lat < bbox["lat_min"] {
			return false
		}
		return true
	}

	for i, pair := range matrix {
		res := verify(pair)
		if !res {
			return false, errors.New(fmt.Sprintf("Coordinate (lat: %f, long: %f) at matrix index %d is outside the limits for country \"%s\" which is %vi. Make sure you use [[LAT, LONG]...].", pair[0], pair[1], i, country, bbox))
		}
	}
	return true, nil
}

// Starts a computation, validates the matrix in POST.
// If matrix data is missing, returns 400 Bad Request.
// If on the other hand matrix is data is not missing,
// but makes no sense, it returns 422 Unprocessable Entity.
func (server *Server) PostMatrix(ctx *web.Context) {
	var hash string
	var computed bool
	params := []string{"matrix", "speed_profile", "country"}

	body := ctx.Request.Body

	var buf bytes.Buffer
	buf.ReadFrom(body)
	bodyParams := buf.Bytes()
	debug.Println(buf.String())
	var paramBlob map[string]interface{}
	// Parse params
	json.Unmarshal(bodyParams, &paramBlob)

	ok := false
	for _, param := range params {
		// ok will be set to false if ctx.Params doesn't contain param
		_, ok = paramBlob[param]
	}

	if ok {
		data := paramBlob["matrix"].(string)
		country := paramBlob["country"].(string)
		sp, jep := paramBlob["speed_profile"].(float64)

		speed_profile := int(sp)
		// Sanitize speed profile.
		if !jep || !contains(speed_profile, allowed_speeds) {
			msg := fmt.Sprintf("speed profile '%d' makes no sense, must be one of %s", speed_profile, fmt.Sprint(allowed_speeds))
			ctx.Abort(422, msg)
			return
		}
		// Sanitize country.
		if _, ok := server.AllowedCountries[country]; !ok {
			countries := ""
			for k := range server.AllowedCountries {
				countries += k + " "
			}
			ctx.Abort(422, "country "+country+" not allowed, must be one of: "+countries)
			return
		}

		mat, err := parse_json_matrix(data)
		if err != nil {
			ctx.Abort(422, err.Error())
			return
		}

		ok, err = check_coordinate_sanity(mat, country)
		if err != nil {
			ctx.Abort(422, err.Error())
			return
		}

		hash, computed = server.CreateMatrixComputation(mat, country, int(speed_profile))

		// launch computation here if the result wasn't proxied.
		if !computed {
			go server.ComputeMatrix(hash)
		}
	} else {
		ctx.Abort(400, "Missing matrix data or speed profile or country. You sent: "+buf.String())
		return
	}

	loc := fmt.Sprintf("/spp/%s", hash)

	ctx.Redirect(201, loc)
}

// Returns a computation from the server as identified by the resource parameter
// in GET.
func (server *Server) GetMatrix(ctx *web.Context, resource string) string {
	progress, err := server.GetMatrixComputationProgress(resource)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	if progress == "complete" {
		url := fmt.Sprintf("/spp/%s/result", resource)
		debug.Println("redirect ->", url)
		ctx.Redirect(303, url)
	} else {
		ctx.ContentType("json")
		msg := fmt.Sprintf(`{ "progress": "%s" }`, progress)
		return msg
	}

	return ""
}

func (server *Server) GetMatrixResult(ctx *web.Context, resource string) string {
	if ex, _ := server.client.Exists(resource); !ex {
		ctx.Abort(500, "Result expired. POST again.")
		return ""
	}

	progress, err := server.GetMatrixComputationProgress(resource)
	if progress != "complete" {
		ctx.Abort(403, "Computation is not ready yet.")
		return ""
	}

	if exists, _ := server.client.Hexists(resource, "see"); exists {
		debug.Println("Got proxy result")
		pointer, _ := server.client.Hget(resource, "see")
		resource = string(pointer)
	}

	data, err := server.client.Hget(resource, "result")
	if err != nil {
		ctx.Abort(500, "Redis error: "+err.Error())
		return ""
	}

	if data != nil {
		ctx.ContentType("json")
		return fmt.Sprintf("{ \"Matrix\": %s }", string(data))
	}

	return ""
}

func (server *Server) GetServerStatus(ctx *web.Context) string {
	db, _ := sql.Open("postgres", server.Config.String())
	defer db.Close()

	err := db.Ping()

	if err != nil {
		ctx.Abort(500, "Could not connect to database: "+err.Error())
		return ""
	}

	return "OK"
}

func (server *Server) GetCorrectCoordinate(ctx *web.Context) string {
	s_lat, lat_ok := ctx.Params["lat"]
	s_long, long_ok := ctx.Params["long"]

	// TODO(ane): implement automatic lookup of country
	s_country, country_ok := ctx.Params["country"]

	if !lat_ok || !long_ok || !country_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need lat, long, country, you gave: %q", ctx.Params))
		return ""
	}

	lat, err := strconv.ParseFloat(s_lat, 32)
	if err != nil {
		ctx.Abort(400, fmt.Sprintf("Latitude %s is invalid, cannot parse!", s_lat))
	}

	long, err := strconv.ParseFloat(s_long, 32)
	if err != nil {
		ctx.Abort(400, fmt.Sprintf("Longitude %s is invalid, cannot parse!", s_long))
	}

	if _, ok := server.Config.AllowedCountries[s_country]; !ok {
		ctx.Abort(500, fmt.Sprintf("Country %s not allowed", s_country))
	}

	coord := Coord{lat, long}

	corr_node, err := CorrectPoint(server.Config, coord, s_country)
	if err != nil {
		ctx.Abort(500, err.Error())
	}

	response, err := json.Marshal(corr_node)
	if err != nil {
		ctx.Abort(500, err.Error())
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(response)
}

func (server *Server) GetNodesToCoordinates(ctx *web.Context) string {
	nodes, ex := ctx.Params["nodes"]
	country, ex2 := ctx.Params["country"]

	if !ex || !ex2 {
		ctx.Abort(400, fmt.Sprintf("Missing parameter: either nodes or country is missing"))
		return ""
	}

	var parsedNodes []int
	if err := json.Unmarshal([]byte(nodes), &parsedNodes); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	coordinates, err := GetCoordinates(server.Config, country, parsedNodes)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	cont, err := json.Marshal(coordinates)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(cont)
}

func (server *Server) GetPath(ctx *web.Context) string {
	p_source, p_source_ok := ctx.Params["source"]
	p_target, p_target_ok := ctx.Params["target"]
	p_country, p_country_ok := ctx.Params["country"]
	p_sp, p_sp_ok := ctx.Params["speed_profile"]

	if !p_source_ok || !p_target_ok || !p_country_ok || !p_sp_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need country, speed_profile, source, target; you gave: %q", ctx.Params))
		return ""
	}

	if _, ok := server.Config.AllowedCountries[p_country]; !ok {
		ctx.Abort(500, fmt.Sprintf("Country %s not allowed", p_country))
		return ""
	}

	source, _ := strconv.Atoi(p_source)
	target, _ := strconv.Atoi(p_target)
	sp, _ := strconv.Atoi(p_sp)

	path, err := CalculatePath(source, target, p_country, sp)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	data, err := json.Marshal(path)
	if err != nil {
		ctx.Abort(500, "json error: "+err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(data)
}

func (server *Server) GetFuzzyAddress(ctx *web.Context) string {
	p_addr, p_addr_ok := ctx.Params["address"]
	p_country, p_country_ok := ctx.Params["country"]
	p_limit, p_limit_ok := ctx.Params["limit"]
	var limit int

	if !p_addr_ok || !p_country_ok {
		ctx.Abort(400, fmt.Sprintf("Missing address or country."))
		return ""
	}

	if !p_limit_ok {
		limit = 5
	} else {
		limit, _ = strconv.Atoi(p_limit)
	}

	if p_country != "finland" {
		ctx.Abort(400, fmt.Sprintf("Only Finland is supported atm."))
		return ""
	}

	ctx.ContentType("application/json")

	addresses, err := GetFuzzyAddress(server.Config, p_addr, limit)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	if addresses == nil {
		return "{}"
	}

	addresses_json, err := json.Marshal(addresses)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	return string(addresses_json)
}

func (server *Server) GetCoordinatePath(ctx *web.Context) string {
	p_source, p_source_ok := ctx.Params["source"]
	p_target, p_target_ok := ctx.Params["target"]
	p_sp, p_sp_ok := ctx.Params["speed_profile"]

	if !p_source_ok || !p_target_ok || !p_sp_ok {
		ctx.Abort(400, fmt.Sprintf("Missing parameter, need speed_profile, source, target; you gave: %q", ctx.Params))
		return ""
	}

	var sourceAddr, targetAddr Location
	if err := json.Unmarshal([]byte(p_source), &sourceAddr); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	if err := json.Unmarshal([]byte(p_target), &targetAddr); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	}

	sp, _ := strconv.Atoi(p_sp)

	result, err := CalculateCoordinatePathFromAddresses(server.Config, sourceAddr, targetAddr, sp)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	jsonResult, err := json.Marshal(result)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(jsonResult)
}

func (server *Server) PostResolve(ctx *web.Context) string {
	content, err := ioutil.ReadAll(ctx.Request.Body)
	var locations, resolvedLocations []Location

	// Parse params
	if err := json.Unmarshal(content, &locations); err != nil {
		ctx.Abort(400, err.Error())
		return ""
	} else {
		for i := 0; i < len(locations); i++ {
			newLoc, err := ResolveLocation(server.Config, locations[i])
			if err != nil {
				ctx.Abort(422, err.Error())
				return ""
			}
			resolvedLocations = append(resolvedLocations, newLoc)
		}
	}

	res, err := json.Marshal(resolvedLocations)
	if err != nil {
		ctx.Abort(500, err.Error())
		return ""
	}

	ctx.Header().Set("Access-Control-Allow-Origin", "*")
	ctx.ContentType("application/json")
	return string(res)
}
<|endoftext|>


<commit_before>package acl

import (
	"golang.org/x/sys/windows"

	"unsafe"
)

const (
	ERROR_SUCCESS = 0
)

// SE_OBJECT_TYPE enumeration.
const (
	SE_UNKNOWN_OBJECT_TYPE = iota
	SE_FILE_OBJECT
	SE_SERVICE
	SE_PRINTER
	SE_REGISTRY_KEY
	SE_LMSHARE
	SE_KERNEL_OBJECT
	SE_WINDOW_OBJECT
	SE_DS_OBJECT
	SE_DS_OBJECT_ALL
	SE_PROVIDER_DEFINED_OBJECT
	SE_WMIGUID_OBJECT
	SE_REGISTRY_WOW64_32KEY
)

// SECURITY_INFORMATION constants.
const (
	OWNER_SECURITY_INFORMATION               = 0x00001
	GROUP_SECURITY_INFORMATION               = 0x00002
	DACL_SECURITY_INFORMATION                = 0x00004
	SACL_SECURITY_INFORMATION                = 0x00008
	LABEL_SECURITY_INFORMATION               = 0x00010
	ATTRIBUTE_SECURITY_INFORMATION           = 0x00020
	SCOPE_SECURITY_INFORMATION               = 0x00040
	PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00080
	BACKUP_SECURITY_INFORMATION              = 0x10000

	PROTECTED_DACL_SECURITY_INFORMATION   = 0x80000000
	PROTECTED_SACL_SECURITY_INFORMATION   = 0x40000000
	UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
	UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)

var (
	advapi32 = windows.MustLoadDLL("advapi32.dll")

	procGetNamedSecurityInfoW = advapi32.MustFindProc("GetNamedSecurityInfoW")
	procSetNamedSecurityInfoW = advapi32.MustFindProc("SetNamedSecurityInfoW")
)

type ACL struct {
	AclRevision byte
	Sbz1        byte
	AclSize     uint16
	AceCount    uint16
	Sbz2        uint16
}

// Retrieve a copy of the security descriptor for the specified object. Note
// that ppSecurityDescriptor must be freed using windows.LocalFree().
func GetNamedSecurityInfo(pObjectName string, ObjectType int32, SecurityInfo uint32, ppsidOwner, ppsidGroup **windows.SID, ppDacl, ppSacl **ACL, ppSecurityDescriptor *windows.Handle) error {
	ret, _, err := procGetNamedSecurityInfoW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(pObjectName))),
		uintptr(ObjectType),
		uintptr(SecurityInfo),
		uintptr(unsafe.Pointer(ppsidOwner)),
		uintptr(unsafe.Pointer(ppsidGroup)),
		uintptr(unsafe.Pointer(ppDacl)),
		uintptr(unsafe.Pointer(ppSacl)),
		uintptr(unsafe.Pointer(ppSecurityDescriptor)),
	)
	if ret != ERROR_SUCCESS {
		return err
	}
	return nil
}

// Set the sepecified information in the object's security descriptor.
func SetNamedSecurityInfo(pObjectName string, ObjectType int32, SecurityInfo uint32, psidOwner, psidGroup *windows.SID, pDacl, pSacl *ACL) error {
	ret, _, err := procSetNamedSecurityInfoW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(pObjectName))),
		uintptr(ObjectType),
		uintptr(SecurityInfo),
		uintptr(unsafe.Pointer(psidOwner)),
		uintptr(unsafe.Pointer(psidGroup)),
		uintptr(unsafe.Pointer(pDacl)),
		uintptr(unsafe.Pointer(pSacl)),
	)
	if ret != ERROR_SUCCESS {
		return err
	}
	return nil
}
<commit_msg>Added SetEntriesInAcl() function.<commit_after>package acl

import (
	"golang.org/x/sys/windows"

	"unsafe"
)

const (
	ERROR_SUCCESS = 0
)

// SE_OBJECT_TYPE enumeration.
const (
	SE_UNKNOWN_OBJECT_TYPE = iota
	SE_FILE_OBJECT
	SE_SERVICE
	SE_PRINTER
	SE_REGISTRY_KEY
	SE_LMSHARE
	SE_KERNEL_OBJECT
	SE_WINDOW_OBJECT
	SE_DS_OBJECT
	SE_DS_OBJECT_ALL
	SE_PROVIDER_DEFINED_OBJECT
	SE_WMIGUID_OBJECT
	SE_REGISTRY_WOW64_32KEY
)

// SECURITY_INFORMATION flags.
const (
	OWNER_SECURITY_INFORMATION               = 0x00001
	GROUP_SECURITY_INFORMATION               = 0x00002
	DACL_SECURITY_INFORMATION                = 0x00004
	SACL_SECURITY_INFORMATION                = 0x00008
	LABEL_SECURITY_INFORMATION               = 0x00010
	ATTRIBUTE_SECURITY_INFORMATION           = 0x00020
	SCOPE_SECURITY_INFORMATION               = 0x00040
	PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00080
	BACKUP_SECURITY_INFORMATION              = 0x10000

	PROTECTED_DACL_SECURITY_INFORMATION   = 0x80000000
	PROTECTED_SACL_SECURITY_INFORMATION   = 0x40000000
	UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
	UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)

// MULTIPLE_TRUSTEE_OPERATION enumeration.
const (
	NO_MULTIPLE_TRUSTEE = iota
	TRUSTEE_IS_IMPERSONATE
)

// TRUSTEE_FORM enumeration.
const (
	TRUSTEE_IS_SID = iota
	TRUSTEE_IS_NAME
	TRUSTEE_BAD_FORM
	TRUSTEE_IS_OBJECTS_AND_SID
	TRUSTEE_IS_OBJECTS_AND_NAME
)

// TRUSTEE_TYPE enumeration.
const (
	TRUSTEE_IS_UNKNOWN = iota
	TRUSTEE_IS_USER
	TRUSTEE_IS_GROUP
	TRUSTEE_IS_DOMAIN
	TRUSTEE_IS_ALIAS
	TRUSTEE_IS_WELL_KNOWN_GROUP
	TRUSTEE_IS_DELETED
	TRUSTEE_IS_INVALID
	TRUSTEE_IS_COMPUTER
)

// ACCESS_MODE enumeration.
const (
	NOT_USED_ACCESS = iota
	GRANT_ACCESS
	SET_ACCESS
	DENY_ACCESS
	REVOKE_ACCESS
	SET_AUDIT_SUCCESS
	SET_AUDIT_FAILURE
)

// ACE flags.
const (
	NO_INHERITANCE                     = 0x0
	SUB_OBJECTS_ONLY_INHERIT           = 0x1
	SUB_CONTAINERS_ONLY_INHERIT        = 0x2
	SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3
	INHERIT_NO_PROPAGATE               = 0x4
	INHERIT_ONLY                       = 0x8

	OBJECT_INHERIT_ACE       = 0x1
	CONTAINER_INHERIT_ACE    = 0x2
	NO_PROPAGATE_INHERIT_ACE = 0x4
	INHERIT_ONLY_ACE         = 0x8
)

var (
	advapi32 = windows.MustLoadDLL("advapi32.dll")

	procGetNamedSecurityInfoW = advapi32.MustFindProc("GetNamedSecurityInfoW")
	procSetNamedSecurityInfoW = advapi32.MustFindProc("SetNamedSecurityInfoW")
	procSetEntriesInAclW      = advapi32.MustFindProc("SetEntriesInAclW")
)

type ACL struct{}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379636.aspx
type Trustee struct {
	MultipleTrustee          *Trustee
	MultipleTrusteeOperation int32
	TrusteeForm              int32
	TrusteeType              int32
	Name                     *uint16
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa446627.aspx
type ExplicitAccess struct {
	AccessPermissions uint32
	AccessMode        int32
	Inheritance       uint32
	Trustee           Trustee
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa446645.aspx
func GetNamedSecurityInfo(objectName string, objectType int32, secInfo uint32, owner, group **windows.SID, dacl, sacl **ACL, secDesc *windows.Handle) error {
	ret, _, err := procGetNamedSecurityInfoW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(objectName))),
		uintptr(objectType),
		uintptr(secInfo),
		uintptr(unsafe.Pointer(owner)),
		uintptr(unsafe.Pointer(group)),
		uintptr(unsafe.Pointer(dacl)),
		uintptr(unsafe.Pointer(sacl)),
		uintptr(unsafe.Pointer(secDesc)),
	)
	if ret != ERROR_SUCCESS {
		return err
	}
	return nil
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379579.aspx
func SetNamedSecurityInfo(objectName string, objectType int32, secInfo uint32, owner, group *windows.SID, dacl, sacl *ACL) error {
	ret, _, err := procSetNamedSecurityInfoW.Call(
		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(objectName))),
		uintptr(objectType),
		uintptr(secInfo),
		uintptr(unsafe.Pointer(owner)),
		uintptr(unsafe.Pointer(group)),
		uintptr(unsafe.Pointer(dacl)),
		uintptr(unsafe.Pointer(sacl)),
	)
	if ret != ERROR_SUCCESS {
		return err
	}
	return nil
}

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379576.aspx
func SetEntriesInAcl(entries []ExplicitAccess, oldAcl *ACL, newAcl **ACL) error {
	ret, _, err := procSetEntriesInAclW.Call(
		uintptr(len(entries)),
		uintptr(unsafe.Pointer(&entries[0])),
		uintptr(unsafe.Pointer(oldAcl)),
		uintptr(unsafe.Pointer(newAcl)),
	)
	if ret != ERROR_SUCCESS {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package node

import "github.com/leeola/errors"

func (n *Node) IsNewIndex() bool {
	// Ignoring the error, as it does not matter. Comparing an empty value
	// will mean we need to rebuild the index, and an error results in the same.
	v, _ := n.db.GetNodeIndexVersion()
	isOldIndex := v == n.index.IndexVersion()
	return !isOldIndex
}

func (n *Node) RebuildIndex() error {
	n.log.Info("rebuilding index")

	if err := n.index.Reset(); err != nil {
		return errors.Wrap(err, "failed to reset index")
	}

	n.log.Warn("rebuilding disabled for refactoring!")
	return nil

	// ch, err := n.store.List()
	// if err != nil {
	// 	return errors.Stack(err)
	// }

	// for h := range ch {
	// 	ctype, b, err := store.GetContentTypeWithBytes(n.store, h)
	// 	if err != nil {
	// 		return errors.Wrapf(err, "failed to get contentType from hash:%s", h)
	// 	}

	// 	// If it has no type, index the entry
	// 	if ctype == "" {
	// 		if err := n.index.Entry(h); err != nil {
	// 			return errors.Wrapf(err, "failed to index entry:%s", h)
	// 		}
	// 		continue
	// 	}

	// 	mu, ok := n.metadataUnmarshallers[ctype]

	// 	if !ok {
	// 		if err := n.index.Entry(h); err != nil {
	// 			return errors.Wrapf(err, "failed to index entry:%s", h)
	// 		}
	// 		continue
	// 	}

	// 	m, err := mu.UnmarshalMetadata(b)
	// 	if err != nil {
	// 		return errors.Wrapf(err, "failed to unmarshal metadata from:%s", h)
	// 	}

	// 	if err := n.index.Metadata(h, m); err != nil {
	// 		return errors.Wrapf(err, "failed to index entry:%s", h)
	// 	}
	// }

	// // Now that we're done indexing, store the new index version in the node db.
	// if err := n.db.SetNodeIndexVersion(n.index.Version()); err != nil {
	// 	return errors.Wrap(err, "failed to store new index version")
	// }

	// return nil
}
<commit_msg>refactor(node): enable storing of index version<commit_after>package node

import "github.com/leeola/errors"

func (n *Node) IsNewIndex() bool {
	// Ignoring the error, as it does not matter. Comparing an empty value
	// will mean we need to rebuild the index, and an error results in the same.
	v, _ := n.db.GetNodeIndexVersion()
	isOldIndex := v == n.index.IndexVersion()
	return !isOldIndex
}

func (n *Node) RebuildIndex() error {
	n.log.Info("rebuilding index")

	if err := n.index.Reset(); err != nil {
		return errors.Wrap(err, "failed to reset index")
	}

	n.log.Warn("full rebuilding disabled for refactoring!")

	// ch, err := n.store.List()
	// if err != nil {
	// 	return errors.Stack(err)
	// }

	// for h := range ch {
	// 	ctype, b, err := store.GetContentTypeWithBytes(n.store, h)
	// 	if err != nil {
	// 		return errors.Wrapf(err, "failed to get contentType from hash:%s", h)
	// 	}

	// 	// If it has no type, index the entry
	// 	if ctype == "" {
	// 		if err := n.index.Entry(h); err != nil {
	// 			return errors.Wrapf(err, "failed to index entry:%s", h)
	// 		}
	// 		continue
	// 	}

	// 	mu, ok := n.metadataUnmarshallers[ctype]

	// 	if !ok {
	// 		if err := n.index.Entry(h); err != nil {
	// 			return errors.Wrapf(err, "failed to index entry:%s", h)
	// 		}
	// 		continue
	// 	}

	// 	m, err := mu.UnmarshalMetadata(b)
	// 	if err != nil {
	// 		return errors.Wrapf(err, "failed to unmarshal metadata from:%s", h)
	// 	}

	// 	if err := n.index.Metadata(h, m); err != nil {
	// 		return errors.Wrapf(err, "failed to index entry:%s", h)
	// 	}
	// }

	// Now that we're done indexing, store the new index version in the node db.
	if err := n.db.SetNodeIndexVersion(n.index.IndexVersion()); err != nil {
		return errors.Wrap(err, "failed to store new index version")
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"
	"text/template"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/nodetemple/nodetemple/version"
)

var (
	cmdHelp = &cobra.Command{
		Use:   "help [command]",
		Short: "Print usage information",
		Long:  "Print usage information for any command",
		Run:   cmdNodectl.HelpFunc(),
		PersistentPreRun:  func(cmd *Command, args []string) {},
		PersistentPostRun: func(cmd *Command, args []string) {},
	}

	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
			parts := []string{cmd.Name()}
			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
				cmd = cmd.Parent()
				parts = append([]string{cmd.Name()}, parts...)
			}
			return strings.Join(parts, " ")
		},
	}
)

func init() {
	commandUsage := `
{{ $cmd := .Cmd }}\
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
NAME:
{{ if not .Cmd.HasParent }}\
{{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
{{else}}\
{{printf "\t%s - %s" $cmdname .Cmd.Short}}
{{end}}\

USAGE:
{{printf "\t%s" .Cmd.UseLine}}
{{ if not .Cmd.HasParent }}\

VERSION:
{{printf "\t%s" .Version}}
{{end}}\
{{if .Cmd.HasSubCommands}}\

COMMANDS:
{{range .SubCommands}}\
{{ $cmdname := cmdName . $cmd }}\
{{ if .Runnable }}\
{{printf "\t%s\t%s" $cmdname .Short}}
{{end}}\
{{end}}\
{{end}}\
{{ if .Cmd.Long }}\

DESCRIPTION:
{{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
{{end}}\
{{end}}\
{{if .Cmd.HasLocalFlags}}\

{{ if not .Cmd.HasParent }}GLOBAL {{end}}FLAGS:
{{.Cmd.LocalFlags.FlagUsages}}\
{{ if not .Cmd.HasParent }}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{end}}\
{{if .Cmd.HasInheritedFlags}}\

GLOBAL FLAGS:
{{.Cmd.InheritedFlags.FlagUsages}}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{ if .Cmd.HasSubCommands }}
Run "{{.Cmd.CommandPath}} help [command]" for more information about a specific command usage
{{end}}\
{{ if .Cmd.HasParent }}
Run "{{.Executable}} help" for more information about a general usage
{{end}}`[1:]

	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
}

func getSubCommands(cmd *cobra.Command) []*cobra.Command {
	subCommands := []*cobra.Command{}
	for _, subCmd := range cmd.Commands() {
		subCommands = append(subCommands, subCmd)
		subCommands = append(subCommands, getSubCommands(subCmd)...)
	}
	return subCommands
}

func usageFunc(cmd *cobra.Command) error {
	subCommands := getSubCommands(cmd)
	err := commandUsageTemplate.Execute(tabOut, struct {
		Executable  string
		Cmd         *cobra.Command
		CmdFlags    *pflag.FlagSet
		SubCommands []*cobra.Command
		EnvFlag     string
		Version     string
	}{
		cliName,
		cmd,
		cmd.Flags(),
		subCommands,
		strings.ToUpper(cliName),
		version.Version,
	})
	tabOut.Flush()
	return err
}
<commit_msg>Fix undefinded Command<commit_after>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"
	"text/template"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/nodetemple/nodetemple/version"
)

var (
	cmdHelp = &cobra.Command{
		Use:   "help [command]",
		Short: "Print usage information",
		Long:  "Print usage information for any command",
		Run:   cmdNodectl.HelpFunc(),
		PersistentPreRun:  func(cmd *cobra.Command, args []string) {},
		PersistentPostRun: func(cmd *cobra.Command, args []string) {},
	}

	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
			parts := []string{cmd.Name()}
			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
				cmd = cmd.Parent()
				parts = append([]string{cmd.Name()}, parts...)
			}
			return strings.Join(parts, " ")
		},
	}
)

func init() {
	commandUsage := `
{{ $cmd := .Cmd }}\
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
NAME:
{{ if not .Cmd.HasParent }}\
{{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
{{else}}\
{{printf "\t%s - %s" $cmdname .Cmd.Short}}
{{end}}\

USAGE:
{{printf "\t%s" .Cmd.UseLine}}
{{ if not .Cmd.HasParent }}\

VERSION:
{{printf "\t%s" .Version}}
{{end}}\
{{if .Cmd.HasSubCommands}}\

COMMANDS:
{{range .SubCommands}}\
{{ $cmdname := cmdName . $cmd }}\
{{ if .Runnable }}\
{{printf "\t%s\t%s" $cmdname .Short}}
{{end}}\
{{end}}\
{{end}}\
{{ if .Cmd.Long }}\

DESCRIPTION:
{{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
{{end}}\
{{end}}\
{{if .Cmd.HasLocalFlags}}\

{{ if not .Cmd.HasParent }}GLOBAL {{end}}FLAGS:
{{.Cmd.LocalFlags.FlagUsages}}\
{{ if not .Cmd.HasParent }}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{end}}\
{{if .Cmd.HasInheritedFlags}}\

GLOBAL FLAGS:
{{.Cmd.InheritedFlags.FlagUsages}}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{ if .Cmd.HasSubCommands }}
Run "{{.Cmd.CommandPath}} help [command]" for more information about a specific command usage
{{end}}\
{{ if .Cmd.HasParent }}
Run "{{.Executable}} help" for more information about a general usage
{{end}}`[1:]

	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
}

func getSubCommands(cmd *cobra.Command) []*cobra.Command {
	subCommands := []*cobra.Command{}
	for _, subCmd := range cmd.Commands() {
		subCommands = append(subCommands, subCmd)
		subCommands = append(subCommands, getSubCommands(subCmd)...)
	}
	return subCommands
}

func usageFunc(cmd *cobra.Command) error {
	subCommands := getSubCommands(cmd)
	err := commandUsageTemplate.Execute(tabOut, struct {
		Executable  string
		Cmd         *cobra.Command
		CmdFlags    *pflag.FlagSet
		SubCommands []*cobra.Command
		EnvFlag     string
		Version     string
	}{
		cliName,
		cmd,
		cmd.Flags(),
		subCommands,
		strings.ToUpper(cliName),
		version.Version,
	})
	tabOut.Flush()
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"
	"text/template"

	"github.com/spf13/cobra"
	"github.com/nodetemple/nodetemple/version"
)

var (
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
			parts := []string{cmd.Name()}
			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
				cmd = cmd.Parent()
				parts = append([]string{cmd.Name()}, parts...)
			}
			return strings.Join(parts, " ")
		},
	}
)

func init() {
	commandUsage := `
{{ $cmd := .Cmd }}\
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
NAME:
{{ if not .Cmd.HasParent }}\
{{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
{{else}}\
{{printf "\t%s - %s" $cmdname .Cmd.Short}}
{{end}}\

USAGE:
{{printf "\t%s" .Cmd.UseLine}}
{{ if not .Cmd.HasParent }}\

VERSION:
{{printf "\t%s" .Version}}
{{end}}\
{{if .Cmd.HasSubCommands}}\

COMMANDS:
{{range .SubCommands}}\
{{ $cmdname := cmdName . $cmd }}\
{{ if .Runnable }}\
{{printf "\t%s\t%s" $cmdname .Short}}
{{end}}\
{{end}}\
{{end}}\
{{ if .Cmd.Long }}\

DESCRIPTION:
{{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
{{end}}\
{{end}}\
{{if .Cmd.HasLocalFlags}}\

OPTIONS:
{{.Cmd.LocalFlags.FlagUsages}}\
{{end}}\
{{if .Cmd.HasInheritedFlags}}\

GLOBAL OPTIONS:
{{.Cmd.InheritedFlags.FlagUsages}}
Global options can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{ if .Cmd.HasSubCommands }}\

Run "{{.Executable}} help [command]" for more details on a specific command
{{else}}\

For help on global options run "{{.Executable}} help"
{{end}}`[1:]

	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
}

func getSubCommands(cmd *cobra.Command) []*cobra.Command {
	subCommands := []*cobra.Command{}
	for _, subCmd := range cmd.Commands() {
		subCommands = append(subCommands, subCmd)
		subCommands = append(subCommands, getSubCommands(subCmd)...)
	}
	return subCommands
}

func usageFunc(cmd *cobra.Command) error {
	subCommands := getSubCommands(cmd)
	commandUsageTemplate.Execute(tabOut, struct {
		Executable  string
		Cmd         *cobra.Command
		SubCommands []*cobra.Command
		EnvFlag     string
		Version     string
	}{
		cliName,
		cmd,
		subCommands,
		strings.ToUpper(cliName),
		version.Version,
	})
	tabOut.Flush()
	return nil
}
<commit_msg>Global opts help<commit_after>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"strings"
	"text/template"

	"github.com/spf13/cobra"
	"github.com/nodetemple/nodetemple/version"
)

var (
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
			parts := []string{cmd.Name()}
			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
				cmd = cmd.Parent()
				parts = append([]string{cmd.Name()}, parts...)
			}
			return strings.Join(parts, " ")
		},
	}
)

func init() {
	commandUsage := `
{{ $cmd := .Cmd }}\
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
NAME:
{{ if not .Cmd.HasParent }}\
{{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
{{else}}\
{{printf "\t%s - %s" $cmdname .Cmd.Short}}
{{end}}\

USAGE:
{{printf "\t%s" .Cmd.UseLine}}
{{ if not .Cmd.HasParent }}\

VERSION:
{{printf "\t%s" .Version}}
{{end}}\
{{if .Cmd.HasSubCommands}}\

COMMANDS:
{{range .SubCommands}}\
{{ $cmdname := cmdName . $cmd }}\
{{ if .Runnable }}\
{{printf "\t%s\t%s" $cmdname .Short}}
{{end}}\
{{end}}\
{{end}}\
{{ if .Cmd.Long }}\

DESCRIPTION:
{{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
{{end}}\
{{end}}\
{{if .Cmd.HasLocalFlags}}\

{{ if not .Cmd.HasParent }}GLOBAL {{end}}FLAGS:
{{.Cmd.LocalFlags.FlagUsages}}\
{{ if not .Cmd.HasParent }}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{end}}\
{{if .Cmd.HasInheritedFlags}}\

GLOBAL FLAGS:
{{.Cmd.InheritedFlags.FlagUsages}}
Global flags can also be configured via upper-case environment variables prefixed with "{{.EnvFlag}}_"
For example: "--some-flag" => "{{.EnvFlag}}_SOME_FLAG"
{{end}}\
{{ if .Cmd.HasSubCommands }}
Run "{{.Cmd.CommandPath}} help [command]" for more information about a specific command
{{end}}\
Run "{{.Executable}} help" for more information about common usage
`[1:]

	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
}

func getSubCommands(cmd *cobra.Command) []*cobra.Command {
	subCommands := []*cobra.Command{}
	for _, subCmd := range cmd.Commands() {
		subCommands = append(subCommands, subCmd)
		subCommands = append(subCommands, getSubCommands(subCmd)...)
	}
	return subCommands
}

func usageFunc(cmd *cobra.Command) error {
	subCommands := getSubCommands(cmd)
	commandUsageTemplate.Execute(tabOut, struct {
		Executable  string
		Cmd         *cobra.Command
		SubCommands []*cobra.Command
		EnvFlag     string
		Version     string
	}{
		cliName,
		cmd,
		subCommands,
		strings.ToUpper(cliName),
		version.Version,
	})
	tabOut.Flush()
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/nodetemple/nodetemple/common"
	"github.com/nodetemple/nodetemple/nodectl/util"
	"github.com/nodetemple/nodetemple/nodectl/command"
)

func main() {
	app := cli.NewApp()
	app.Name = "nodectl"
	app.Usage = "CLI for an orchestration of CoreOS and Kubernetes cluster"
	app.Version = common.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "providers, p", Usage: "A comma-separated list of IaaS providers ("+strings.Join(common.AvailableProviders, ",")+"), e.g.: do:do-api-key,gce:gce-api-key", EnvVar: util.EnvVarConv(app.Name, "providers"),},
		cli.BoolFlag{Name: "debug", Usage: "Print out more debug information to stderr"},
	}
	/*app.Before = func(c *cli.Context) error {
		if c.String("api-key") != "" {
			APIKey = c.String("api-key")
		}

		if APIKey == "" && !c.Bool("help") && !c.Bool("version") {
			return errors.New("must provide API Key via NODECTL_PROVIDERS environment variable or via CLI argument.")
		}

		switch c.String("format") {
		case "json":
			OutputFormat = c.String("format")
		case "yaml":
			OutputFormat = c.String("format")
		default:
			return fmt.Errorf("invalid output format: %q, available output options: json, yaml.", c.String("format"))
		}

		return nil
	}*/
	app.Commands = []cli.Command{
		command.DemoCmd(),
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		util.Err("unknown command '%v'\nRun '%v help [command]' for usage information", command, c.App.Name)
	}

	app.Run(os.Args)
}
<commit_msg>API keys format eg<commit_after>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/nodetemple/nodetemple/common"
	"github.com/nodetemple/nodetemple/nodectl/util"
	"github.com/nodetemple/nodetemple/nodectl/command"
)

func main() {
	app := cli.NewApp()
	app.Name = "nodectl"
	app.Usage = "CLI for an orchestration of CoreOS and Kubernetes cluster"
	app.Version = common.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "providers, p", Usage: "A comma-separated list of IaaS providers ("+strings.Join(common.AvailableProviders, ",")+") and API keys, format: 'provider:api-key,...'", EnvVar: util.EnvVarConv(app.Name, "providers"),},
		cli.BoolFlag{Name: "debug", Usage: "Print out more debug information to stderr"},
	}
	/*app.Before = func(c *cli.Context) error {
		if c.String("api-key") != "" {
			APIKey = c.String("api-key")
		}

		if APIKey == "" && !c.Bool("help") && !c.Bool("version") {
			return errors.New("must provide API Key via NODECTL_PROVIDERS environment variable or via CLI argument.")
		}

		switch c.String("format") {
		case "json":
			OutputFormat = c.String("format")
		case "yaml":
			OutputFormat = c.String("format")
		default:
			return fmt.Errorf("invalid output format: %q, available output options: json, yaml.", c.String("format"))
		}

		return nil
	}*/
	app.Commands = []cli.Command{
		command.DemoCmd(),
	}
	app.CommandNotFound = func(c *cli.Context, command string) {
		util.Err("unknown command '%v'\nRun '%v help [command]' for usage information", command, c.App.Name)
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Financial-Times/base-ft-rw-app-go"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go"
	"github.com/Financial-Times/public-brands-api/brands"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
	"github.com/rcrowley/go-metrics"
	"net/http"
	"os"
	"strings"
)

func main() {
	app := cli.App("public-brands-api", "A public RESTful API for accessing Brands in neo4j")
	neoURL := app.StringOpt("neo-url", "http://localhost:7474/db/data", "neo4j endpoint URL")
	//neoURL := app.StringOpt("neo-url", "http://ftper59365-law1a-eu-t:8080/db/data", "neo4j endpoint URL")
	port := app.StringOpt("port", "8080", "Port to listen on")
	logLevel := app.StringOpt("log-level", "INFO", "Logging level (DEBUG, INFO, WARN, ERROR)")
	env := app.StringOpt("env", "local", "environment this app is running in")
	graphiteTCPAddress := app.StringOpt("graphiteTCPAddress", "",
		"Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)")
	graphitePrefix := app.StringOpt("graphitePrefix", "",
		"Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.brands.api.ftaps59382-law1a-eu-t")
	logMetrics := app.BoolOpt("logMetrics", false, "Whether to log metrics. Set to true if running locally and you want metrics output")

	app.Action = func() {

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)
		if *env != "local" {
			f, err := os.OpenFile("/var/log/apps/public-brands-api-go-app.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
			if err == nil {
				log.SetOutput(f)
				log.SetFormatter(&log.TextFormatter{})
			} else {
				log.Fatalf("Failed to initialise log file, %v", err)
			}

			defer f.Close()
		}

		log.Infof("public-brands-api will listen on port: %s, connecting to: %s", *port, *neoURL)
		runServer(*neoURL, *port, *env)

	}
	setLogLevel(strings.ToUpper(*logLevel))
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, env string) {
	db, err := neoism.Connect(neoURL)
	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}
	brands.BrandsDriver = brands.NewCypherDriver(db, env)
	router := mux.NewRouter()

	// Healthchecks and standards first
	router.HandleFunc("/__health", v1a.Handler("BrandsReadWriteNeo4j Healthchecks",
		"Checks for accessing neo4j", brands.HealthCheck()))
	router.HandleFunc("/ping", brands.Ping)
	router.HandleFunc("/__ping", brands.Ping)
	router.HandleFunc("/build-info", brands.BuildInfo)
	router.HandleFunc("/__build-info", brands.BuildInfo)

	// Then API specific ones:
	router.HandleFunc("/brands/{uuid}", brands.GetBrand).Methods("GET")

	if err := http.ListenAndServe(":"+port,
		httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry,
			httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), router))); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}
}

func setLogLevel(level string) {
	switch level {
	case "DEBUG":
		log.SetLevel(log.DebugLevel)
	case "INFO":
		log.SetLevel(log.InfoLevel)
	case "WARN":
		log.SetLevel(log.WarnLevel)
	case "ERROR":
		log.SetLevel(log.ErrorLevel)
	default:
		log.Errorf("Requested log level %s is not supported, will default to INFO level", level)
		log.SetLevel(log.InfoLevel)
	}
	log.Debugf("Logging level set to %s", level)
}
<commit_msg>Fixed breaking change from base-rw, neo-utils-go and http-handlers-go package re-work<commit_after>package main

import (
	"github.com/Financial-Times/base-ft-rw-app-go/baseftrwapp"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/http-handlers-go/httphandlers"
	"github.com/Financial-Times/public-brands-api/brands"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
	"github.com/rcrowley/go-metrics"
	"net/http"
	"os"
	"strings"
)

func main() {
	app := cli.App("public-brands-api", "A public RESTful API for accessing Brands in neo4j")
	neoURL := app.StringOpt("neo-url", "http://localhost:7474/db/data", "neo4j endpoint URL")
	//neoURL := app.StringOpt("neo-url", "http://ftper59365-law1a-eu-t:8080/db/data", "neo4j endpoint URL")
	port := app.StringOpt("port", "8080", "Port to listen on")
	logLevel := app.StringOpt("log-level", "INFO", "Logging level (DEBUG, INFO, WARN, ERROR)")
	env := app.StringOpt("env", "local", "environment this app is running in")
	graphiteTCPAddress := app.StringOpt("graphiteTCPAddress", "",
		"Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)")
	graphitePrefix := app.StringOpt("graphitePrefix", "",
		"Prefix to use. Should start with content, include the environment, and the host name. e.g. content.test.public.brands.api.ftaps59382-law1a-eu-t")
	logMetrics := app.BoolOpt("logMetrics", false, "Whether to log metrics. Set to true if running locally and you want metrics output")

	app.Action = func() {

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)
		if *env != "local" {
			f, err := os.OpenFile("/var/log/apps/public-brands-api-go-app.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
			if err == nil {
				log.SetOutput(f)
				log.SetFormatter(&log.TextFormatter{})
			} else {
				log.Fatalf("Failed to initialise log file, %v", err)
			}

			defer f.Close()
		}

		log.Infof("public-brands-api will listen on port: %s, connecting to: %s", *port, *neoURL)
		runServer(*neoURL, *port, *env)

	}
	setLogLevel(strings.ToUpper(*logLevel))
	log.Infof("Application started with args %s", os.Args)
	app.Run(os.Args)
}

func runServer(neoURL string, port string, env string) {
	db, err := neoism.Connect(neoURL)
	if err != nil {
		log.Fatalf("Error connecting to neo4j %s", err)
	}
	brands.BrandsDriver = brands.NewCypherDriver(db, env)
	router := mux.NewRouter()

	// Healthchecks and standards first
	router.HandleFunc("/__health", v1a.Handler("BrandsReadWriteNeo4j Healthchecks",
		"Checks for accessing neo4j", brands.HealthCheck()))
	router.HandleFunc("/ping", brands.Ping)
	router.HandleFunc("/__ping", brands.Ping)
	router.HandleFunc("/build-info", brands.BuildInfo)
	router.HandleFunc("/__build-info", brands.BuildInfo)

	// Then API specific ones:
	router.HandleFunc("/brands/{uuid}", brands.GetBrand).Methods("GET")

	if err := http.ListenAndServe(":"+port,
		httphandlers.HTTPMetricsHandler(metrics.DefaultRegistry,
			httphandlers.TransactionAwareRequestLoggingHandler(log.StandardLogger(), router))); err != nil {
		log.Fatalf("Unable to start server: %v", err)
	}
}

func setLogLevel(level string) {
	switch level {
	case "DEBUG":
		log.SetLevel(log.DebugLevel)
	case "INFO":
		log.SetLevel(log.InfoLevel)
	case "WARN":
		log.SetLevel(log.WarnLevel)
	case "ERROR":
		log.SetLevel(log.ErrorLevel)
	default:
		log.Errorf("Requested log level %s is not supported, will default to INFO level", level)
		log.SetLevel(log.InfoLevel)
	}
	log.Debugf("Logging level set to %s", level)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"mime"
	"os"
	"path/filepath"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/ryanuber/go-glob"
)

type AWS struct {
	client *s3.S3
	remote []string
	local  []string
	vargs  PluginArgs
}

func NewAWS(vargs PluginArgs) AWS {
	sess := session.New(&aws.Config{
		Credentials: credentials.NewStaticCredentials(vargs.Key, vargs.Secret, ""),
		Region:      aws.String(vargs.Region),
	})
	c := s3.New(sess)
	r := make([]string, 1, 1)
	l := make([]string, 1, 1)

	return AWS{c, r, l, vargs}
}

func (a *AWS) visit(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if path == "." {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	localPath := strings.TrimPrefix(path, a.vargs.Source)
	if strings.HasPrefix(localPath, "/") {
		localPath = localPath[1:]
	}

	remotePath := filepath.Join(a.vargs.Target, localPath)

	a.local = append(a.local, localPath)
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	defer file.Close()

	access := ""
	if a.vargs.Access.IsString() {
		access = a.vargs.Access.String()
	} else if !a.vargs.Access.IsEmpty() {
		accessMap := a.vargs.Access.Map()
		for pattern := range accessMap {
			if match := glob.Glob(pattern, localPath); match == true {
				access = accessMap[pattern]
				break
			}
		}
	}

	if access == "" {
		access = "private"
	}

	fileExt := filepath.Ext(localPath)
	var contentType string
	if a.vargs.ContentType.IsString() {
		contentType = a.vargs.ContentType.String()
	} else if !a.vargs.ContentType.IsEmpty() {
		contentMap := a.vargs.ContentType.Map()
		for patternExt := range contentMap {
			if patternExt == fileExt {
				contentType = contentMap[patternExt]
				break
			}
		}
	}

	metadata := map[string]*string{}
	vmap := a.vargs.Metadata.Map()
	if len(vmap) > 0 {
		for pattern := range vmap {
			if match := glob.Glob(pattern, localPath); match == true {
				for k, v := range vmap[pattern] {
					metadata[k] = aws.String(v)
				}
				break
			}
		}
	}

	if contentType == "" {
		contentType = mime.TypeByExtension(fileExt)
	}

	exists := false
	for _, remoteFile := range a.remote {
		if remoteFile == localPath {
			exists = true
			break
		}
	}

	if exists {
		hash := md5.New()
		io.Copy(hash, file)
		sum := fmt.Sprintf("\"%x\"", hash.Sum(nil))

		head, err := a.client.HeadObject(&s3.HeadObjectInput{
			Bucket: aws.String(a.vargs.Bucket),
			Key:    aws.String(remotePath),
		})
		if err != nil {
			return err
		}

		if sum == *head.ETag {
			shouldCopy := false

			if head.ContentType == nil && contentType != "" {
				debug("Content-Type has changed from unset to %s\n", contentType)
				shouldCopy = true
			}

			if !shouldCopy && head.ContentType != nil && contentType != *head.ContentType {
				debug("Content-Type has changed from %s to %s\n", *head.ContentType, contentType)
				shouldCopy = true
			}

			if !shouldCopy && len(head.Metadata) != len(metadata) {
				debug("Count of metadata values has changed for %s\n", localPath)
				shouldCopy = true
			}

			if !shouldCopy && len(metadata) > 0 {
				for k, v := range metadata {
					if hv, ok := head.Metadata[k]; ok {
						if *v != *hv {
							debug("Metadata values have changed for %s\n", localPath)
							shouldCopy = true
							break
						}
					}
				}
			}

			if !shouldCopy {
				grant, err := a.client.GetObjectAcl(&s3.GetObjectAclInput{
					Bucket: aws.String(a.vargs.Bucket),
					Key:    aws.String(remotePath),
				})
				if err != nil {
					return err
				}

				previousAccess := "private"
				for _, g := range grant.Grants {
					gt := *g.Grantee
					if gt.URI != nil {
						if *gt.URI == "http://acs.amazonaws.com/groups/global/AllUsers" {
							if *g.Permission == "READ" {
								previousAccess = "public-read"
							} else if *g.Permission == "WRITE" {
								previousAccess = "public-read-write"
							}
						} else if *gt.URI == "http://acs.amazonaws.com/groups/global/AllUsers" {
							if *g.Permission == "READ" {
								previousAccess = "authenticated-read"
							}
						}
					}
				}

				if previousAccess != access {
					debug("Permissions for \"%s\" have changed from \"%s\" to \"%s\"\n", remotePath, previousAccess, access)
					shouldCopy = true
				}
			}

			if !shouldCopy {
				debug("Skipping \"%s\" because hashes and metadata match\n", localPath)
				return nil
			}

			fmt.Printf("Updating metadata for \"%s\" Content-Type: \"%s\", ACL: \"%s\"\n", localPath, contentType, access)
			_, err = a.client.CopyObject(&s3.CopyObjectInput{
				Bucket:            aws.String(a.vargs.Bucket),
				Key:               aws.String(remotePath),
				CopySource:        aws.String(fmt.Sprintf("%s/%s", a.vargs.Bucket, remotePath)),
				ACL:               aws.String(access),
				ContentType:       aws.String(contentType),
				Metadata:          metadata,
				MetadataDirective: aws.String("REPLACE"),
			})
			return err
		}

		_, err = file.Seek(0, 0)
		if err != nil {
			return err
		}
	}

	fmt.Printf("Uploading \"%s\" with Content-Type \"%s\" and permissions \"%s\"\n", localPath, contentType, access)
	_, err = a.client.PutObject(&s3.PutObjectInput{
		Bucket:      aws.String(a.vargs.Bucket),
		Key:         aws.String(remotePath),
		Body:        file,
		ContentType: aws.String(contentType),
		ACL:         aws.String(access),
		Metadata:    metadata,
	})
	return err
}

func (a *AWS) AddRedirects(redirects map[string]string) error {
	for path, location := range redirects {
		fmt.Printf("Adding redirect from \"%s\" to \"%s\"", path, location)
		a.local = append(a.local, strings.TrimPrefix(path, "/"))
		_, err := a.client.PutObject(&s3.PutObjectInput{
			Bucket: aws.String(a.vargs.Bucket),
			Key:    aws.String(path),
			WebsiteRedirectLocation: aws.String(location),
		})

		if err != nil {
			return err
		}
	}

	return nil
}

func (a *AWS) List(path string) error {
	resp, err := a.client.ListObjects(&s3.ListObjectsInput{
		Bucket: aws.String(a.vargs.Bucket),
		Prefix: aws.String(path),
	})
	if err != nil {
		return err
	}

	for _, item := range resp.Contents {
		a.remote = append(a.remote, *item.Key)
	}

	for *resp.IsTruncated {
		resp, err = a.client.ListObjects(&s3.ListObjectsInput{
			Bucket: aws.String(a.vargs.Bucket),
			Prefix: aws.String(path),
			Marker: aws.String(a.remote[len(a.remote)-1]),
		})

		if err != nil {
			return err
		}

		for _, item := range resp.Contents {
			a.remote = append(a.remote, *item.Key)
		}
	}

	return nil
}

func (a *AWS) Cleanup() error {
	for _, remote := range a.remote {
		found := false
		for _, local := range a.local {
			if local == remote {
				found = true
				break
			}
		}

		if !found {
			fmt.Printf("Removing remote file \"%s\"\n", remote)
			_, err := a.client.DeleteObject(&s3.DeleteObjectInput{
				Bucket: aws.String(a.vargs.Bucket),
				Key:    aws.String(remote),
			})
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<commit_msg>add public-read acl to redirects<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"mime"
	"os"
	"path/filepath"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/ryanuber/go-glob"
)

type AWS struct {
	client *s3.S3
	remote []string
	local  []string
	vargs  PluginArgs
}

func NewAWS(vargs PluginArgs) AWS {
	sess := session.New(&aws.Config{
		Credentials: credentials.NewStaticCredentials(vargs.Key, vargs.Secret, ""),
		Region:      aws.String(vargs.Region),
	})
	c := s3.New(sess)
	r := make([]string, 1, 1)
	l := make([]string, 1, 1)

	return AWS{c, r, l, vargs}
}

func (a *AWS) visit(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if path == "." {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	localPath := strings.TrimPrefix(path, a.vargs.Source)
	if strings.HasPrefix(localPath, "/") {
		localPath = localPath[1:]
	}

	remotePath := filepath.Join(a.vargs.Target, localPath)

	a.local = append(a.local, localPath)
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	defer file.Close()

	access := ""
	if a.vargs.Access.IsString() {
		access = a.vargs.Access.String()
	} else if !a.vargs.Access.IsEmpty() {
		accessMap := a.vargs.Access.Map()
		for pattern := range accessMap {
			if match := glob.Glob(pattern, localPath); match == true {
				access = accessMap[pattern]
				break
			}
		}
	}

	if access == "" {
		access = "private"
	}

	fileExt := filepath.Ext(localPath)
	var contentType string
	if a.vargs.ContentType.IsString() {
		contentType = a.vargs.ContentType.String()
	} else if !a.vargs.ContentType.IsEmpty() {
		contentMap := a.vargs.ContentType.Map()
		for patternExt := range contentMap {
			if patternExt == fileExt {
				contentType = contentMap[patternExt]
				break
			}
		}
	}

	metadata := map[string]*string{}
	vmap := a.vargs.Metadata.Map()
	if len(vmap) > 0 {
		for pattern := range vmap {
			if match := glob.Glob(pattern, localPath); match == true {
				for k, v := range vmap[pattern] {
					metadata[k] = aws.String(v)
				}
				break
			}
		}
	}

	if contentType == "" {
		contentType = mime.TypeByExtension(fileExt)
	}

	exists := false
	for _, remoteFile := range a.remote {
		if remoteFile == localPath {
			exists = true
			break
		}
	}

	if exists {
		hash := md5.New()
		io.Copy(hash, file)
		sum := fmt.Sprintf("\"%x\"", hash.Sum(nil))

		head, err := a.client.HeadObject(&s3.HeadObjectInput{
			Bucket: aws.String(a.vargs.Bucket),
			Key:    aws.String(remotePath),
		})
		if err != nil {
			return err
		}

		if sum == *head.ETag {
			shouldCopy := false

			if head.ContentType == nil && contentType != "" {
				debug("Content-Type has changed from unset to %s\n", contentType)
				shouldCopy = true
			}

			if !shouldCopy && head.ContentType != nil && contentType != *head.ContentType {
				debug("Content-Type has changed from %s to %s\n", *head.ContentType, contentType)
				shouldCopy = true
			}

			if !shouldCopy && len(head.Metadata) != len(metadata) {
				debug("Count of metadata values has changed for %s\n", localPath)
				shouldCopy = true
			}

			if !shouldCopy && len(metadata) > 0 {
				for k, v := range metadata {
					if hv, ok := head.Metadata[k]; ok {
						if *v != *hv {
							debug("Metadata values have changed for %s\n", localPath)
							shouldCopy = true
							break
						}
					}
				}
			}

			if !shouldCopy {
				grant, err := a.client.GetObjectAcl(&s3.GetObjectAclInput{
					Bucket: aws.String(a.vargs.Bucket),
					Key:    aws.String(remotePath),
				})
				if err != nil {
					return err
				}

				previousAccess := "private"
				for _, g := range grant.Grants {
					gt := *g.Grantee
					if gt.URI != nil {
						if *gt.URI == "http://acs.amazonaws.com/groups/global/AllUsers" {
							if *g.Permission == "READ" {
								previousAccess = "public-read"
							} else if *g.Permission == "WRITE" {
								previousAccess = "public-read-write"
							}
						} else if *gt.URI == "http://acs.amazonaws.com/groups/global/AllUsers" {
							if *g.Permission == "READ" {
								previousAccess = "authenticated-read"
							}
						}
					}
				}

				if previousAccess != access {
					debug("Permissions for \"%s\" have changed from \"%s\" to \"%s\"\n", remotePath, previousAccess, access)
					shouldCopy = true
				}
			}

			if !shouldCopy {
				debug("Skipping \"%s\" because hashes and metadata match\n", localPath)
				return nil
			}

			fmt.Printf("Updating metadata for \"%s\" Content-Type: \"%s\", ACL: \"%s\"\n", localPath, contentType, access)
			_, err = a.client.CopyObject(&s3.CopyObjectInput{
				Bucket:            aws.String(a.vargs.Bucket),
				Key:               aws.String(remotePath),
				CopySource:        aws.String(fmt.Sprintf("%s/%s", a.vargs.Bucket, remotePath)),
				ACL:               aws.String(access),
				ContentType:       aws.String(contentType),
				Metadata:          metadata,
				MetadataDirective: aws.String("REPLACE"),
			})
			return err
		}

		_, err = file.Seek(0, 0)
		if err != nil {
			return err
		}
	}

	fmt.Printf("Uploading \"%s\" with Content-Type \"%s\" and permissions \"%s\"\n", localPath, contentType, access)
	_, err = a.client.PutObject(&s3.PutObjectInput{
		Bucket:      aws.String(a.vargs.Bucket),
		Key:         aws.String(remotePath),
		Body:        file,
		ContentType: aws.String(contentType),
		ACL:         aws.String(access),
		Metadata:    metadata,
	})
	return err
}

func (a *AWS) AddRedirects(redirects map[string]string) error {
	for path, location := range redirects {
		fmt.Printf("Adding redirect from \"%s\" to \"%s\"", path, location)
		a.local = append(a.local, strings.TrimPrefix(path, "/"))
		_, err := a.client.PutObject(&s3.PutObjectInput{
			Bucket: aws.String(a.vargs.Bucket),
			Key:    aws.String(path),
			ACL:    aws.String("public-read"),
			WebsiteRedirectLocation: aws.String(location),
		})

		if err != nil {
			return err
		}
	}

	return nil
}

func (a *AWS) List(path string) error {
	resp, err := a.client.ListObjects(&s3.ListObjectsInput{
		Bucket: aws.String(a.vargs.Bucket),
		Prefix: aws.String(path),
	})
	if err != nil {
		return err
	}

	for _, item := range resp.Contents {
		a.remote = append(a.remote, *item.Key)
	}

	for *resp.IsTruncated {
		resp, err = a.client.ListObjects(&s3.ListObjectsInput{
			Bucket: aws.String(a.vargs.Bucket),
			Prefix: aws.String(path),
			Marker: aws.String(a.remote[len(a.remote)-1]),
		})

		if err != nil {
			return err
		}

		for _, item := range resp.Contents {
			a.remote = append(a.remote, *item.Key)
		}
	}

	return nil
}

func (a *AWS) Cleanup() error {
	for _, remote := range a.remote {
		found := false
		for _, local := range a.local {
			if local == remote {
				found = true
				break
			}
		}

		if !found {
			fmt.Printf("Removing remote file \"%s\"\n", remote)
			_, err := a.client.DeleteObject(&s3.DeleteObjectInput{
				Bucket: aws.String(a.vargs.Bucket),
				Key:    aws.String(remote),
			})
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/sosedoff/musicbot/mopidy"
	"github.com/sosedoff/musicbot/slack"
)

type BotConfig struct {
	Channel    string
	SlackToken string
	MopidyHost string
}

type Bot struct {
	config      BotConfig
	slack       *slack.Client
	mopidy      *mopidy.Client
	slackEvent  chan slack.Event
	mopidyEvent chan mopidy.Event
	commands    []Command
}

func NewBot(config BotConfig) Bot {
	return Bot{config: config}
}

func (bot *Bot) initSlack() error {
	client := slack.NewClient(bot.config.SlackToken)

	err := client.Connect()
	if err != nil {
		return err
	}

	bot.slack = client
	bot.slackEvent = make(chan slack.Event)

	return nil
}

func (bot *Bot) initMopidy() error {
	client := mopidy.New(bot.config.MopidyHost)

	err := client.Connect()
	if err != nil {
		return err
	}

	bot.mopidy = client
	bot.mopidyEvent = make(chan mopidy.Event)

	return nil
}

func (bot *Bot) handleSlackEvents() {
	for {
		ev := <-bot.slackEvent
		switch ev.Data.(type) {
		case slack.MessageEvent:
			msg := ev.Data.(slack.MessageEvent)
			bot.handleMessage(&msg.Message)
		}
	}
}

func (bot *Bot) handleMopidyEvents() {
	for {
		ev := <-bot.mopidyEvent

		switch ev.Data.(type) {
		case mopidy.TrackPlaybackStarted:
			data := ev.Data.(mopidy.TrackPlaybackStarted)
			track := data.TlTrack.Track

			bot.Say("Playing: " + track.String())
		}
	}
}

func (bot *Bot) handleMessage(msg *slack.Message) {
	for _, cmd := range bot.commands {
		match := cmd.Match(msg.Text)

		if match != nil {
			go cmd.handler(bot, match)
			break
		}
	}
}

func (bot *Bot) addCommand(expr string, handler HandlerFunc) {
	cmd := NewCommand(bot, expr, handler)
	bot.commands = append(bot.commands, cmd)
}

func (bot *Bot) Say(text string) {
	err := bot.slack.SendMessage(bot.config.Channel, text)
	if err != nil {
		fmt.Println("Error:", err)
	}
}

func (bot *Bot) Run() {
	if err := bot.initMopidy(); err != nil {
		log.Fatalln(err)
	}

	if err := bot.initSlack(); err != nil {
		log.Fatalln(err)
	}

	setupCommands(bot)

	go bot.handleSlackEvents()
	go bot.handleMopidyEvents()

	go bot.mopidy.Run(bot.mopidyEvent)
	go bot.slack.Start(bot.slackEvent)
}
<commit_msg>Add volume changed event<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/sosedoff/musicbot/mopidy"
	"github.com/sosedoff/musicbot/slack"
)

type BotConfig struct {
	Channel    string
	SlackToken string
	MopidyHost string
}

type Bot struct {
	config      BotConfig
	slack       *slack.Client
	mopidy      *mopidy.Client
	slackEvent  chan slack.Event
	mopidyEvent chan mopidy.Event
	commands    []Command
}

func NewBot(config BotConfig) Bot {
	return Bot{config: config}
}

func (bot *Bot) initSlack() error {
	client := slack.NewClient(bot.config.SlackToken)

	err := client.Connect()
	if err != nil {
		return err
	}

	bot.slack = client
	bot.slackEvent = make(chan slack.Event)

	return nil
}

func (bot *Bot) initMopidy() error {
	client := mopidy.New(bot.config.MopidyHost)

	err := client.Connect()
	if err != nil {
		return err
	}

	bot.mopidy = client
	bot.mopidyEvent = make(chan mopidy.Event)

	return nil
}

func (bot *Bot) handleSlackEvents() {
	for {
		ev := <-bot.slackEvent
		switch ev.Data.(type) {
		case slack.MessageEvent:
			msg := ev.Data.(slack.MessageEvent)
			bot.handleMessage(&msg.Message)
		}
	}
}

func (bot *Bot) handleMopidyEvents() {
	for {
		ev := <-bot.mopidyEvent

		switch ev.Data.(type) {
		case mopidy.TrackPlaybackStarted:
			data := ev.Data.(mopidy.TrackPlaybackStarted)
			track := data.TlTrack.Track
			bot.Say(fmt.Sprintf(":musical_note: %s", track.String()))
		case mopidy.VolumeChangedEvent:
			data := ev.Data.(mopidy.VolumeChangedEvent)
			bot.Say(fmt.Sprintf("Volume is set to %v%s", data.Volume, "%"))
		}
	}
}

func (bot *Bot) handleMessage(msg *slack.Message) {
	for _, cmd := range bot.commands {
		match := cmd.Match(msg.Text)

		if match != nil {
			go cmd.handler(bot, match)
			break
		}
	}
}

func (bot *Bot) addCommand(expr string, handler HandlerFunc) {
	cmd := NewCommand(bot, expr, handler)
	bot.commands = append(bot.commands, cmd)
}

func (bot *Bot) Say(text string) {
	err := bot.slack.SendMessage(bot.config.Channel, text)
	if err != nil {
		fmt.Println("Error:", err)
	}
}

func (bot *Bot) Run() {
	if err := bot.initMopidy(); err != nil {
		log.Fatalln(err)
	}

	if err := bot.initSlack(); err != nil {
		log.Fatalln(err)
	}

	setupCommands(bot)

	go bot.handleSlackEvents()
	go bot.handleMopidyEvents()

	go bot.mopidy.Run(bot.mopidyEvent)
	go bot.slack.Start(bot.slackEvent)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"
)

var bot *tgbotapi.BotAPI

func botRun() error {
	var err error
	bot, err = tgbotapi.NewBotAPI(cfg.Bot.Token)
	if err != nil {
		return err
	}

	bot.Debug = cfg.Bot.Debug

	log.Printf("Authorized on account %s", bot.Self.UserName)

	_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert(fmt.Sprintf("%s%s/%s", cfg.HTTP.Host, cfg.HTTP.Port, cfg.Bot.Token), cfg.HTTP.PublicKey))
	if err != nil {
		log.Fatal(err)
	}

	updates := bot.ListenForWebhook(fmt.Sprintf("/%s", bot.Token))
	go func() {
		if err := http.ListenAndServeTLS(cfg.HTTP.Port, cfg.HTTP.PublicKey, cfg.HTTP.PrivateKey, nil); err != nil {
			panic(err)
		}
	}()

	for update := range updates {
		msgRouter(update)
	}
	return nil
}

func msgRouter(update tgbotapi.Update) error {
	if update.Message == nil {
		log.Println("message is nil", update)
		return nil
	}

	switch {
	case update.Message.IsCommand():
		return isCommand(update)
	case update.Message.Chat.IsPrivate() || bot.IsMessageToMe(*update.Message):
		return isMessage(update)
	}
	return nil
}

func isCommand(update tgbotapi.Update) error {
	msg := strings.Trim(update.Message.CommandArguments(), " ")

	switch update.Message.Command() {
	case "s":
		if msg == "" {
			return sendMsg(update, HelpMsg)
		}
		txt, err := search(msg)
		if err != nil {
			return err
		}
		return sendMsg(update, txt)
	case "daily":
		return isDaily(update)
	default:
		return sendMsg(update, HelpMsg)
	}
	return nil
}

func isMessage(update tgbotapi.Update) error {
	txt, err := search(update.Message.Text)
	if err != nil {
		return err
	}
	return sendMsg(update, txt)
}

func isDaily(update tgbotapi.Update) error {
	txt, err := daily()
	if err != nil {
		return err
	}
	return sendMsg(update, txt)
}

func sendMsg(update tgbotapi.Update, txt string) error {
	msg := tgbotapi.NewMessage(update.Message.Chat.ID, txt)
	msg.ParseMode = "HTML"
	msg.DisableWebPagePreview = true
	if _, err := bot.Send(msg); err != nil {
		log.Println(err)
		return err
	}

	return nil
}
<commit_msg>update<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/go-telegram-bot-api/telegram-bot-api"
)

var bot *tgbotapi.BotAPI

func botRun() error {
	var err error
	bot, err = tgbotapi.NewBotAPI(cfg.Bot.Token)
	if err != nil {
		return err
	}

	bot.Debug = cfg.Bot.Debug

	log.Printf("Authorized on account %s", bot.Self.UserName)

	_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert(fmt.Sprintf("%s%s/%s", cfg.HTTP.Host, cfg.HTTP.Port, cfg.Bot.Token), cfg.HTTP.PublicKey))
	if err != nil {
		log.Fatal(err)
	}

	updates := bot.ListenForWebhook(fmt.Sprintf("/%s", bot.Token))
	go func() {
		if err := http.ListenAndServeTLS(cfg.HTTP.Port, cfg.HTTP.PublicKey, cfg.HTTP.PrivateKey, nil); err != nil {
			panic(err)
		}
	}()

	for update := range updates {
		msgRouter(update)
	}
	return nil
}

func msgRouter(update tgbotapi.Update) error {
	switch {
	case update.Message.IsCommand():
		return isCommand(update)
	case update.InlineQuery != nil:
		return isInline(update)
	case update.Message.Chat.IsPrivate() || bot.IsMessageToMe(*update.Message):
		return isMessage(update)
	}
	return nil
}

func isCommand(update tgbotapi.Update) error {
	msg := strings.Trim(update.Message.CommandArguments(), " ")

	switch update.Message.Command() {
	case "s":
		if msg == "" {
			return sendMsg(update, HelpMsg)
		}
		txt, err := search(msg)
		if err != nil {
			return err
		}
		return sendMsg(update, txt)
	case "daily":
		return isDaily(update)
	default:
		return sendMsg(update, HelpMsg)
	}
	return nil
}

func isMessage(update tgbotapi.Update) error {
	txt, err := search(update.Message.Text)
	if err != nil {
		return err
	}
	return sendMsg(update, txt)
}

func isInline(update tgbotapi.Update) error {
	fmt.Println(update.InlineQuery)
	return nil
}

func isDaily(update tgbotapi.Update) error {
	txt, err := daily()
	if err != nil {
		return err
	}
	return sendMsg(update, txt)
}

func sendMsg(update tgbotapi.Update, txt string) error {
	msg := tgbotapi.NewMessage(update.Message.Chat.ID, txt)
	msg.ParseMode = "HTML"
	msg.DisableWebPagePreview = true
	if _, err := bot.Send(msg); err != nil {
		log.Println(err)
		return err
	}

	return nil
}
<|endoftext|>