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

package pgsql

import (
	"strconv"
)

// readyState is the state that is active when the connection to the
// PostgreSQL server is ready for queries.
type readyState struct {
	abstractState
}

func (state readyState) closeStatement(stmt *Statement) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.closeStatement"))
	}

	state.close(conn, 'S', stmt.name)
}

func (readyState) code() ConnStatus {
	return StatusReady
}

func (readyState) disconnect(conn *Conn) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.disconnect"))
	}

	conn.writeFrontendMessageCode(_Terminate)
	conn.writeInt32(4)

	conn.flush()

	conn.state = connectedState{}

	err := conn.conn.Close()
	if err != nil {
		conn.logError(LogError, err)
		return
	}

	conn.state = disconnectedState{}
}

func (state readyState) execute(stmt *Statement, reader *Reader) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.execute"))
	}

	values := make([]string, len(stmt.params))

	// Send Bind packet to server.
	var paramValuesLen int
	for i, param := range stmt.params {
		switch val := param.value.(type) {
		case bool:
			if val {
				values[i] = "t"
			} else {
				values[i] = "f"
			}

		case byte:
			values[i] = string([]byte{val})

		case float:
			values[i] = strconv.Ftoa(val, 'f', -1)

		case float32:
			values[i] = strconv.Ftoa32(val, 'f', -1)

		case float64:
			values[i] = strconv.Ftoa64(val, 'f', -1)

		case int:
			values[i] = strconv.Itoa(val)

		case int16:
			values[i] = strconv.Itoa(int(val))

		case int32:
			values[i] = strconv.Itoa(int(val))

		case int64:
			values[i] = strconv.Itoa64(val)

		case nil:

		case string:
			values[i] = val

		default:
			panic("unsupported parameter type")
		}

		paramValuesLen += len(values[i])
	}

	msgLen := int32(4 +
		len(stmt.portalName) + 1 +
		len(stmt.name) + 1 +
		2 + 2 +
		2 + len(stmt.params)*4 + paramValuesLen +
		2 + 2)

	conn.writeFrontendMessageCode(_Bind)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.portalName)
	conn.writeString0(stmt.name)
	conn.writeInt16(1)
	conn.writeInt16(int16(textFormat))
	conn.writeInt16(int16(len(stmt.params)))

	for i, param := range stmt.params {
		if param.value == nil {
			conn.writeInt32(-1)
		} else {
			conn.writeInt32(int32(len(values[i])))
			conn.writeString(values[i])
		}
	}

	conn.writeInt16(1)
	conn.writeInt16(binaryFormat)

	state.flush(conn)
	state.processBackendMessages(conn, reader)

	// Send Describe packet to server.
	msgLen = int32(4 + 1 + len(stmt.portalName) + 1)

	conn.writeFrontendMessageCode(_Describe)
	conn.writeInt32(msgLen)
	conn.writeByte('P')
	conn.writeString0(stmt.portalName)

	state.flush(conn)
	state.processBackendMessages(conn, reader)

	// Send Execute packet to server.
	msgLen = int32(4 + len(stmt.portalName) + 1 + 4)

	conn.writeFrontendMessageCode(_Execute)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.portalName)
	conn.writeInt32(0)

	state.flush(conn)

	// Send Sync packet to server.
	conn.writeFrontendMessageCode(_Sync)
	conn.writeInt32(4)

	state.flush(conn)

	conn.state = processingQueryState{}
}

func (readyState) flush(conn *Conn) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.flush"))
	}

	conn.writeFrontendMessageCode(_Flush)
	conn.writeInt32(4)

	conn.flush()
}

func (state readyState) prepare(stmt *Statement) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.prepare"))
	}

	msgLen := int32(4 +
		len(stmt.name) + 1 +
		len(stmt.actualCommand) + 1 +
		2 + len(stmt.params)*4)

	conn.writeFrontendMessageCode(_Parse)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.name)
	conn.writeString0(stmt.actualCommand)

	conn.writeInt16(int16(len(stmt.params)))
	for _, param := range stmt.params {
		conn.writeInt32(int32(param.typ))
	}

	state.flush(conn)

	state.processBackendMessages(conn, nil)
}

func (state readyState) query(conn *Conn, reader *Reader, command string) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.query"))
	}

	conn.writeFrontendMessageCode(_Query)
	conn.writeInt32(int32(4 + len(command) + 1))
	conn.writeString0(command)

	conn.flush()

	state.processBackendMessages(conn, reader)

	conn.state = processingQueryState{}
}
<commit_msg>Do not swallow error on disconnect<commit_after>// Copyright 2010 Alexander Neumann. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pgsql

import (
	"strconv"
)

// readyState is the state that is active when the connection to the
// PostgreSQL server is ready for queries.
type readyState struct {
	abstractState
}

func (state readyState) closeStatement(stmt *Statement) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.closeStatement"))
	}

	state.close(conn, 'S', stmt.name)
}

func (readyState) code() ConnStatus {
	return StatusReady
}

func (readyState) disconnect(conn *Conn) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.disconnect"))
	}

	conn.writeFrontendMessageCode(_Terminate)
	conn.writeInt32(4)

	conn.flush()

	conn.state = connectedState{}

	err := conn.conn.Close()
	if err != nil {
		panic(err)
	}

	conn.state = disconnectedState{}
}

func (state readyState) execute(stmt *Statement, reader *Reader) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.execute"))
	}

	values := make([]string, len(stmt.params))

	// Send Bind packet to server.
	var paramValuesLen int
	for i, param := range stmt.params {
		switch val := param.value.(type) {
		case bool:
			if val {
				values[i] = "t"
			} else {
				values[i] = "f"
			}

		case byte:
			values[i] = string([]byte{val})

		case float:
			values[i] = strconv.Ftoa(val, 'f', -1)

		case float32:
			values[i] = strconv.Ftoa32(val, 'f', -1)

		case float64:
			values[i] = strconv.Ftoa64(val, 'f', -1)

		case int:
			values[i] = strconv.Itoa(val)

		case int16:
			values[i] = strconv.Itoa(int(val))

		case int32:
			values[i] = strconv.Itoa(int(val))

		case int64:
			values[i] = strconv.Itoa64(val)

		case nil:

		case string:
			values[i] = val

		default:
			panic("unsupported parameter type")
		}

		paramValuesLen += len(values[i])
	}

	msgLen := int32(4 +
		len(stmt.portalName) + 1 +
		len(stmt.name) + 1 +
		2 + 2 +
		2 + len(stmt.params)*4 + paramValuesLen +
		2 + 2)

	conn.writeFrontendMessageCode(_Bind)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.portalName)
	conn.writeString0(stmt.name)
	conn.writeInt16(1)
	conn.writeInt16(int16(textFormat))
	conn.writeInt16(int16(len(stmt.params)))

	for i, param := range stmt.params {
		if param.value == nil {
			conn.writeInt32(-1)
		} else {
			conn.writeInt32(int32(len(values[i])))
			conn.writeString(values[i])
		}
	}

	conn.writeInt16(1)
	conn.writeInt16(binaryFormat)

	state.flush(conn)
	state.processBackendMessages(conn, reader)

	// Send Describe packet to server.
	msgLen = int32(4 + 1 + len(stmt.portalName) + 1)

	conn.writeFrontendMessageCode(_Describe)
	conn.writeInt32(msgLen)
	conn.writeByte('P')
	conn.writeString0(stmt.portalName)

	state.flush(conn)
	state.processBackendMessages(conn, reader)

	// Send Execute packet to server.
	msgLen = int32(4 + len(stmt.portalName) + 1 + 4)

	conn.writeFrontendMessageCode(_Execute)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.portalName)
	conn.writeInt32(0)

	state.flush(conn)

	// Send Sync packet to server.
	conn.writeFrontendMessageCode(_Sync)
	conn.writeInt32(4)

	state.flush(conn)

	conn.state = processingQueryState{}
}

func (readyState) flush(conn *Conn) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.flush"))
	}

	conn.writeFrontendMessageCode(_Flush)
	conn.writeInt32(4)

	conn.flush()
}

func (state readyState) prepare(stmt *Statement) {
	conn := stmt.conn

	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.prepare"))
	}

	msgLen := int32(4 +
		len(stmt.name) + 1 +
		len(stmt.actualCommand) + 1 +
		2 + len(stmt.params)*4)

	conn.writeFrontendMessageCode(_Parse)
	conn.writeInt32(msgLen)
	conn.writeString0(stmt.name)
	conn.writeString0(stmt.actualCommand)

	conn.writeInt16(int16(len(stmt.params)))
	for _, param := range stmt.params {
		conn.writeInt32(int32(param.typ))
	}

	state.flush(conn)

	state.processBackendMessages(conn, nil)
}

func (state readyState) query(conn *Conn, reader *Reader, command string) {
	if conn.LogLevel >= LogDebug {
		defer conn.logExit(conn.logEnter("readyState.query"))
	}

	conn.writeFrontendMessageCode(_Query)
	conn.writeInt32(int32(4 + len(command) + 1))
	conn.writeString0(command)

	conn.flush()

	state.processBackendMessages(conn, reader)

	conn.state = processingQueryState{}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/blackjack/syslog"
	"github.com/gorilla/rpc"
	"github.com/gorilla/rpc/json"
	"net/http"
	// "os"
	"github.com/mdevilliers/redishappy/configuration"
	//"github.com/mdevilliers/redishappy/haproxy"
	"github.com/mdevilliers/redishappy/sentinel"
	"github.com/mdevilliers/redishappy/util"
)

func main() {

	fmt.Println("redis-happy started")

	syslog.Openlog("redis-happy", syslog.LOG_PID, syslog.LOG_USER)
	syslog.Syslog(syslog.LOG_INFO, "redis-happy started.")

	configuration, err := configuration.LoadFromFile("config.json")

	if err != nil {
		panic(err)
	}

	fmt.Printf("Parsed from config : %s\n", util.String(configuration))

	switchmasterchannel := make(chan sentinel.MasterSwitchedEvent)

	go loopSentinelEvents(switchmasterchannel)

	for _, configuredSentinel := range configuration.Sentinels {

		sentinelAddress := fmt.Sprintf("%s:%d", configuredSentinel.Host, configuredSentinel.Port)
		sen, err := sentinel.NewClient(sentinelAddress)

		// TODO : exploding is no good - needs to connect to at least one
		// sentinel. Also explore of any sentinel you have to find others
		// using   _ ,err = sen.FindConnectedSentinels("nameofcluster")
		// check against the list of clusters to validate you can find
		// an answer for all the clusters you are monitoring
		// Once this is all initilised then write an haproxy config that
		// validly documents the existing tompology
		if err != nil {
			panic(err)
		}

		sen.StartMonitoring(switchmasterchannel)
	}

	// host a json endpoint
	fmt.Println("hosting json endpoint...")
	service := rpc.NewServer()
	service.RegisterCodec(json.NewCodec(), "application/json")
	service.RegisterService(new(HelloService), "")
	http.Handle("/rpc", service)
	http.ListenAndServe(":8085", nil)

}

func loopSentinelEvents(switchmasterchannel chan sentinel.MasterSwitchedEvent) {

	for i := range switchmasterchannel {

		syslog.Syslogf(syslog.LOG_ERR, "redis cluster {%s} master failover detected from {%s}:{%d} to {%s}:{%d}.", i.Name, i.OldMasterIp, i.OldMasterPort,i.NewMasterIp, i.NewMasterPort)

		fmt.Printf("Master Switched : %s\n", i.String())

	}
}

//func contactHAProxyExample(){
//connect to the haproxy management socket
// client := haproxy.NewClient("/tmp/haproxy")
// response,_ := client.Rpc("show info\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("show stat\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("xxxx\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("show acl\n")
// fmt.Printf( "%s\n", response.Message)
//}

type HelloArgs struct {
	Who string
}

type HelloReply struct {
	Message string
}

type HelloService struct{}

func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
	reply.Message = "Hello, " + args.Who + "!"
	return nil
}
<commit_msg>remove last String() usage<commit_after>package main

import (
	"fmt"
	"github.com/blackjack/syslog"
	"github.com/gorilla/rpc"
	"github.com/gorilla/rpc/json"
	"net/http"
	// "os"
	"github.com/mdevilliers/redishappy/configuration"
	//"github.com/mdevilliers/redishappy/haproxy"
	"github.com/mdevilliers/redishappy/sentinel"
	"github.com/mdevilliers/redishappy/util"
)

func main() {

	fmt.Println("redis-happy started")

	syslog.Openlog("redis-happy", syslog.LOG_PID, syslog.LOG_USER)
	syslog.Syslog(syslog.LOG_INFO, "redis-happy started.")

	configuration, err := configuration.LoadFromFile("config.json")

	if err != nil {
		panic(err)
	}

	fmt.Printf("Parsed from config : %s\n", util.String(configuration))

	switchmasterchannel := make(chan sentinel.MasterSwitchedEvent)

	go loopSentinelEvents(switchmasterchannel)

	for _, configuredSentinel := range configuration.Sentinels {

		sentinelAddress := fmt.Sprintf("%s:%d", configuredSentinel.Host, configuredSentinel.Port)
		sen, err := sentinel.NewClient(sentinelAddress)

		// TODO : exploding is no good - needs to connect to at least one
		// sentinel. Also explore of any sentinel you have to find others
		// using   _ ,err = sen.FindConnectedSentinels("nameofcluster")
		// check against the list of clusters to validate you can find
		// an answer for all the clusters you are monitoring
		// Once this is all initilised then write an haproxy config that
		// validly documents the existing tompology
		if err != nil {
			panic(err)
		}

		sen.StartMonitoring(switchmasterchannel)
	}

	// host a json endpoint
	fmt.Println("hosting json endpoint...")
	service := rpc.NewServer()
	service.RegisterCodec(json.NewCodec(), "application/json")
	service.RegisterService(new(HelloService), "")
	http.Handle("/rpc", service)
	http.ListenAndServe(":8085", nil)

}

func loopSentinelEvents(switchmasterchannel chan sentinel.MasterSwitchedEvent) {

	for i := range switchmasterchannel {

		syslog.Syslogf(syslog.LOG_ERR, "redis cluster {%s} master failover detected from {%s}:{%d} to {%s}:{%d}.", i.Name, i.OldMasterIp, i.OldMasterPort,i.NewMasterIp, i.NewMasterPort)

		fmt.Printf("Master Switched : %s\n",  util.String(i))

	}
}

//func contactHAProxyExample(){
//connect to the haproxy management socket
// client := haproxy.NewClient("/tmp/haproxy")
// response,_ := client.Rpc("show info\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("show stat\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("xxxx\n")
// fmt.Printf( "%s\n", response.Message)
// response,_ = client.Rpc("show acl\n")
// fmt.Printf( "%s\n", response.Message)
//}

type HelloArgs struct {
	Who string
}

type HelloReply struct {
	Message string
}

type HelloService struct{}

func (h *HelloService) Say(r *http.Request, args *HelloArgs, reply *HelloReply) error {
	reply.Message = "Hello, " + args.Who + "!"
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"strconv"
	"strings"

	"github.com/hoisie/mustache"
)

type amberHandler struct {
	charTemplate *mustache.Template
	error404     string
	error415     string
}

func main() {
	template, err := mustache.ParseFile("AmberTemplate.html.ms")
	if err != nil {
		panic(err)
	} else {
		var handler = amberHandler{charTemplate: template, error404: "<!doctype html><meta charset='utf-8'><title>404 Error</title>Character Not Found", error415: "<!doctype html><meta charset='utf-8'><title>Unsupported Media Type</title>This server only supports returning Amber characters, which cannot contain periods."}

		http.Handle("/", &handler)

		log.Fatal(http.ListenAndServe(":8082", nil))
	}
}

func (h *amberHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var pathComponents = strings.Split(r.URL.Path, "/")
	var filename = pathComponents[len(pathComponents)-1]

	if strings.Contains(filename, ".") {
		pic, picErr := ioutil.ReadFile(filename)
		if picErr != nil {
			w.WriteHeader(415)
			w.Write([]byte(h.error415))
		} else {
			w.Write(pic)
		}
	} else {
		dat, err := ioutil.ReadFile(filename + ".json")
		if err != nil {
			w.WriteHeader(404)
			w.Write([]byte(h.error404))
		} else {
			var f interface{}
			err = json.Unmarshal(dat, &f)
			if err != nil {
				panic(err)
			}

			m := f.(map[string]interface{})
			attributeAuction := m["attributeAuction"].(map[string]interface{})

			for k, v := range attributeAuction {
				value := v.(float64)
				if strings.Contains(k, "Rank") {
					var rank string
					switch {
					case value < -2 && value > -4:
						rank = "Human"
					case value < -1 && value > -3:
						rank = "Demon"
					case value < 0 && value > -1:
						rank = "Chaos"
					case value == 0:
						rank = "Amber"
					default:
						var postfix = "th"
						var numString string
						if value-math.Floor(value) < 0.01 {
							var intValue = int(value)
							switch intValue {
							case 1:
								postfix = "st"
							case 2:
								postfix = "nd"
							case 3:
								postfix = "rd"
							}
							numString = strconv.Itoa(intValue)
						} else {
							numString = strconv.FormatFloat(value, 'f', 1, 64)
						}
						rank = numString + postfix
					}

					attributeAuction[k] = rank
				}
			}

			oldBioString := m["bio"].(string)
			bio := strings.Replace(oldBioString, "\n", "
", -1)
			m["bio"] = bio
			var result = h.charTemplate.Render(m)
			w.Write([]byte(result))
		}
	}
}
<commit_msg>Add a test!<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"strconv"
	"strings"

	"github.com/hoisie/mustache"
)

type amberHandler struct {
	charTemplate *mustache.Template
	error404     string
	error415     string
}

func main() {
	serveAmber(8082)
}

func serveAmber(port int) {
	fmt.Println(port)
	template, err := mustache.ParseFile("AmberTemplate.html.ms")
	if err != nil {
		panic(err)
	} else {
		var handler = amberHandler{charTemplate: template, error404: "<!doctype html><meta charset='utf-8'><title>404 Error</title>Character Not Found", error415: "<!doctype html><meta charset='utf-8'><title>Unsupported Media Type</title>This server only supports returning Amber characters, which cannot contain periods."}

		http.Handle("/", &handler)

		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(port), nil))
	}
}

func (h *amberHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var pathComponents = strings.Split(r.URL.Path, "/")
	var filename = pathComponents[len(pathComponents)-1]

	if strings.Contains(filename, ".") {
		pic, picErr := ioutil.ReadFile(filename)
		if picErr != nil {
			w.WriteHeader(415)
			w.Write([]byte(h.error415))
		} else {
			w.Write(pic)
		}
	} else {
		dat, err := ioutil.ReadFile(filename + ".json")
		if err != nil {
			w.WriteHeader(404)
			w.Write([]byte(h.error404))
		} else {
			var f interface{}
			err = json.Unmarshal(dat, &f)
			if err != nil {
				panic(err)
			}

			m := f.(map[string]interface{})
			attributeAuction := m["attributeAuction"].(map[string]interface{})

			for k, v := range attributeAuction {
				value := v.(float64)
				if strings.Contains(k, "Rank") {
					var rank string
					switch {
					case value < -2 && value > -4:
						rank = "Human"
					case value < -1 && value > -3:
						rank = "Demon"
					case value < 0 && value > -1:
						rank = "Chaos"
					case value == 0:
						rank = "Amber"
					default:
						var postfix = "th"
						var numString string
						if value-math.Floor(value) < 0.01 {
							var intValue = int(value)
							switch intValue {
							case 1:
								postfix = "st"
							case 2:
								postfix = "nd"
							case 3:
								postfix = "rd"
							}
							numString = strconv.Itoa(intValue)
						} else {
							numString = strconv.FormatFloat(value, 'f', 1, 64)
						}
						rank = numString + postfix
					}

					attributeAuction[k] = rank
				}
			}

			oldBioString := m["bio"].(string)
			bio := strings.Replace(oldBioString, "\n", "
", -1)
			m["bio"] = bio
			var result = h.charTemplate.Render(m)
			w.Write([]byte(result))
		}
	}
}
<|endoftext|>


<commit_before>package progressbar

import (
	"net/url"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/term"

	"github.com/jfrog/jfrog-cli-core/v2/common/commands"
	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
	corelog "github.com/jfrog/jfrog-cli-core/v2/utils/log"
	logUtils "github.com/jfrog/jfrog-cli/utils/log"
	"github.com/jfrog/jfrog-client-go/utils"
	ioUtils "github.com/jfrog/jfrog-client-go/utils/io"
	"github.com/jfrog/jfrog-client-go/utils/log"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

var terminalWidth int

// The ShouldInitProgressBar func is used to determine whether the progress bar should be displayed.
// This default implementation will init the progress bar if the following conditions are met:
// CI == false (or unset) and Stderr is a terminal.
var ShouldInitProgressBar = func() (bool, error) {
	ci, err := utils.GetBoolEnvValue(coreutils.CI, false)
	if ci || err != nil {
		return false, err
	}
	if !log.IsTerminal() {
		return false, err
	}
	err = setTerminalWidthVar()
	if err != nil {
		return false, err
	}
	return true, nil
}

type filesProgressBarManager struct {
	// A list of progress bar objects.
	bars []progressBar
	// A wait group for all progress bars.
	barsWg *sync.WaitGroup
	// A container of all external mpb bar objects to be displayed.
	container *mpb.Progress
	// A synchronization lock object.
	barsRWMutex sync.RWMutex
	// A general work indicator spinner.
	headlineBar *mpb.Bar
	// A bar that displies the path of the log file.
	logFilePathBar *mpb.Bar
	// A general tasks completion indicator.
	generalProgressBar *mpb.Bar
	// A cumulative amount of tasks
	tasksCount int64
	// The log file
	logFile *os.File
}

type progressBarUnit struct {
	bar         *mpb.Bar
	incrChannel chan int
	description string
}

type progressBar interface {
	ioUtils.Progress
	getProgressBarUnit() *progressBarUnit
}

func (p *filesProgressBarManager) InitProgressReaders() {
	if p.logFile != nil {
		p.printLogFilePathAsBar(p.logFile.Name())
	}
	p.newHeadlineBar(" Working")
	p.tasksCount = 0
	p.newGeneralProgressBar()
}

// Initializes a new reader progress indicator for a new file transfer.
// Input: 'total' - file size.
//		  'label' - the title of the operation.
//		  'path' - the path of the file being processed.
// Output: progress indicator id
func (p *filesProgressBarManager) NewProgressReader(total int64, label, path string) (bar ioUtils.Progress) {
	// Write Lock when appending a new bar to the slice
	p.barsRWMutex.Lock()
	defer p.barsRWMutex.Unlock()
	p.barsWg.Add(1)
	newBar := p.container.Add(
		int64(total),
		mpb.NewBarFiller(mpb.BarStyle().Lbound("|").Filler("🟩").Tip("🟩").Padding("⬛").Refiller("").Rbound("|")),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(
			// Extra chars length is the max length of the KibiByteCounter
			decor.Name(buildProgressDescription(label, path, 17)),
			decor.CountersKibiByte("%3.1f/%3.1f"),
		),
	)

	// Add bar to bars array
	unit := initNewBarUnit(newBar, path)
	barId := len(p.bars) + 1
	readerProgressBar := ReaderProgressBar{progressBarUnit: unit, Id: barId}
	p.bars = append(p.bars, &readerProgressBar)
	return &readerProgressBar
}

// Changes progress indicator state and acts accordingly.
func (p *filesProgressBarManager) SetProgressState(id int, state string) {
	switch state {
	case "Merging":
		p.addNewMergingSpinner(id)
	}
}

// Initializes a new progress bar, that replaces the progress bar with the given replacedBarId
func (p *filesProgressBarManager) addNewMergingSpinner(replacedBarId int) {
	// Write Lock when appending a new bar to the slice
	p.barsRWMutex.Lock()
	defer p.barsRWMutex.Unlock()
	replacedBar := p.bars[replacedBarId-1].getProgressBarUnit()
	p.bars[replacedBarId-1].Abort()
	newBar := p.container.Add(1,
		mpb.NewBarFiller(mpb.SpinnerStyle(createSpinnerFramesArray()...).PositionLeft()),
		mpb.AppendDecorators(
			decor.Name(buildProgressDescription("  Merging  ", replacedBar.description, 0)),
		),
	)
	// Bar replacement is a simple spinner and thus does not implement any read functionality
	unit := &progressBarUnit{bar: newBar, description: replacedBar.description}
	progressBar := SimpleProgressBar{progressBarUnit: unit, Id: replacedBarId}
	p.bars[replacedBarId-1] = &progressBar
}

func buildProgressDescription(label, path string, extraCharsLen int) string {
	separator := " | "
	// Max line length after decreasing bar width (*2 in case unicode chars with double width are used) and the extra chars
	descMaxLength := terminalWidth - (progressBarWidth*2 + extraCharsLen)
	return buildDescByLimits(descMaxLength, " "+label+separator, shortenUrl(path), separator)
}

func shortenUrl(path string) string {
	if _, err := url.ParseRequestURI(path); err != nil {
		return path
	}

	semicolonIndex := strings.Index(path, ";")
	if semicolonIndex == -1 {
		return path
	}
	return path[:semicolonIndex]
}

func buildDescByLimits(descMaxLength int, prefix, path, suffix string) string {
	desc := prefix + path + suffix

	// Verify that the whole description doesn't exceed the max length
	if len(desc) <= descMaxLength {
		return desc
	}

	// If it does exceed, check if shortening the path will help (+3 is for "...")
	if len(desc)-len(path)+3 > descMaxLength {
		// Still exceeds, do not display desc
		return ""
	}

	// Shorten path from the beginning
	path = "..." + path[len(desc)-descMaxLength+3:]
	return prefix + path + suffix
}

func initNewBarUnit(bar *mpb.Bar, path string) *progressBarUnit {
	ch := make(chan int, 1000)
	unit := &progressBarUnit{bar: bar, incrChannel: ch, description: path}
	go incrBarFromChannel(unit)
	return unit
}

func incrBarFromChannel(unit *progressBarUnit) {
	// Increase bar while channel is open
	for n := range unit.incrChannel {
		unit.bar.IncrBy(n)
	}
}

func createSpinnerFramesArray() []string {
	black := "⬛"
	green := "🟩"
	spinnerFramesArray := make([]string, progressBarWidth)
	for i := 1; i < progressBarWidth-1; i++ {
		cur := "|" + strings.Repeat(black, i-1) + green + strings.Repeat(black, progressBarWidth-2-i) + "|"
		spinnerFramesArray[i] = cur
	}
	return spinnerFramesArray
}

// Aborts a progress bar.
// Should be called even if bar completed successfully.
// The progress component's Abort method has no effect if bar has already completed, so can always be safely called anyway
func (p *filesProgressBarManager) RemoveProgress(id int) {
	p.barsRWMutex.RLock()
	defer p.barsWg.Done()
	defer p.barsRWMutex.RUnlock()
	p.bars[id-1].Abort()
	p.generalProgressBar.Increment()

}

// Quits the progress bar while aborting the initial bars.
func (p *filesProgressBarManager) Quit() (err error) {
	if p.headlineBar != nil {
		p.headlineBar.Abort(true)
		p.barsWg.Done()
		p.headlineBar = nil
	}
	if p.logFilePathBar != nil {
		p.barsWg.Done()
		p.logFilePathBar = nil
	}
	if p.generalProgressBar != nil {
		p.generalProgressBar.Abort(true)
		p.barsWg.Done()
		p.generalProgressBar = nil
	}
	// Wait a refresh rate to make sure all aborts have finished
	time.Sleep(progressRefreshRate)
	p.container.Wait()
	// Close the created log file (once)
	if p.logFile != nil {
		err = logUtils.CloseLogFile(p.logFile)
		p.logFile = nil
		// Set back the default logger
		corelog.SetDefaultLogger()
	}
	return
}

func (p *filesProgressBarManager) GetProgress(id int) ioUtils.Progress {
	return p.bars[id-1]
}

// Initializes progress bar if possible (all conditions in 'shouldInitProgressBar' are met).
// Returns nil, nil, err if failed.
func InitFilesProgressBarIfPossible(printLogPath bool) (ioUtils.ProgressMgr, error) {
	shouldInit, err := ShouldInitProgressBar()
	if !shouldInit || err != nil {
		return nil, err
	}

	logFile, err := logUtils.CreateLogFile()
	if err != nil {
		return nil, err
	}
	if printLogPath {
		log.Info("Log path:", logFile.Name())
	}
	log.SetLogger(log.NewLogger(corelog.GetCliLogLevel(), logFile))

	newProgressBar := &filesProgressBarManager{}
	newProgressBar.barsWg = new(sync.WaitGroup)

	// Initialize the progressBar container with wg, to create a single joint point
	newProgressBar.container = mpb.New(
		mpb.WithOutput(os.Stderr),
		mpb.WithWaitGroup(newProgressBar.barsWg),
		mpb.WithWidth(progressBarWidth),
		mpb.WithRefreshRate(progressRefreshRate))

	newProgressBar.logFile = logFile

	return newProgressBar, nil
}

// Get terminal dimensions
func setTerminalWidthVar() error {
	width, _, err := term.GetSize(int(os.Stderr.Fd()))
	if err != nil {
		return err
	}
	// -5 to avoid edges
	terminalWidth = width - 5
	if terminalWidth <= 0 {
		terminalWidth = 5
	}
	return err
}

// Initializes a new progress bar for general progress indication
func (p *filesProgressBarManager) newGeneralProgressBar() {
	p.barsWg.Add(1)
	p.generalProgressBar = p.container.Add(p.tasksCount,
		mpb.NewBarFiller(mpb.BarStyle().Lbound("|").Filler("⬜").Tip("⬜").Padding("⬛").Refiller("").Rbound("|")),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(
			decor.Name(" Tasks: "),
			decor.CountersNoUnit("%d/%d"),
		),
	)
}

// Initializes a new progress bar for headline, with a spinner
func (p *filesProgressBarManager) newHeadlineBar(headline string) {
	p.barsWg.Add(1)
	p.headlineBar = p.container.Add(1,
		mpb.NewBarFiller(mpb.SpinnerStyle("∙∙∙∙∙∙", "●∙∙∙∙∙", "∙●∙∙∙∙", "∙∙●∙∙∙", "∙∙∙●∙∙", "∙∙∙∙●∙", "∙∙∙∙∙●", "∙∙∙∙∙∙").PositionLeft()),
		mpb.BarRemoveOnComplete(),
		mpb.PrependDecorators(
			decor.Name(headline),
		),
	)
}

func (p *filesProgressBarManager) SetHeadlineMsg(msg string) {
	if p.headlineBar != nil {
		current := p.headlineBar
		p.barsRWMutex.RLock()
		// First abort, then mark progress as done and finally release the lock.
		defer p.barsRWMutex.RUnlock()
		defer p.barsWg.Done()
		defer current.Abort(true)
	}
	p.newHeadlineBar(msg)
}

func (p *filesProgressBarManager) ClearHeadlineMsg() {
	if p.headlineBar != nil {
		p.barsRWMutex.RLock()
		p.headlineBar.Abort(true)
		p.barsWg.Done()
		p.barsRWMutex.RUnlock()
		// Wait a refresh rate to make sure the abort has finished
		time.Sleep(progressRefreshRate)
	}
	p.headlineBar = nil
}

// Initializes a new progress bar that states the log file path. The bar's text remains after cli is done.
func (p *filesProgressBarManager) printLogFilePathAsBar(path string) {
	p.barsWg.Add(1)
	prefix := " Log path: "
	p.logFilePathBar = p.container.AddBar(0,
		mpb.BarFillerClearOnComplete(),
		mpb.PrependDecorators(
			decor.Name(buildDescByLimits(terminalWidth, prefix, path, "")),
		),
	)
	p.logFilePathBar.SetTotal(0, true)
}

// IncGeneralProgressTotalBy incremenates the general progress bar total count by given n.
func (p *filesProgressBarManager) IncGeneralProgressTotalBy(n int64) {
	atomic.AddInt64(&p.tasksCount, n)
	if p.generalProgressBar != nil {
		p.generalProgressBar.SetTotal(p.tasksCount, false)
	}
}

type CommandWithProgress interface {
	commands.Command
	SetProgress(ioUtils.ProgressMgr)
}

func ExecWithProgress(cmd CommandWithProgress, printLogPath bool) (err error) {
	// Init progress bar.
	progressBar, err := InitFilesProgressBarIfPossible(printLogPath)
	if err != nil {
		return err
	}
	if progressBar != nil {
		cmd.SetProgress(progressBar)
		defer func() {
			e := progressBar.Quit()
			if err == nil {
				err = e
			}
		}()
	}
	err = commands.Exec(cmd)
	return
}
<commit_msg>Fix deprecated progress bar constructor function (#1568)<commit_after>package progressbar

import (
	"net/url"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"golang.org/x/term"

	"github.com/jfrog/jfrog-cli-core/v2/common/commands"
	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
	corelog "github.com/jfrog/jfrog-cli-core/v2/utils/log"
	logUtils "github.com/jfrog/jfrog-cli/utils/log"
	"github.com/jfrog/jfrog-client-go/utils"
	ioUtils "github.com/jfrog/jfrog-client-go/utils/io"
	"github.com/jfrog/jfrog-client-go/utils/log"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

var terminalWidth int

// The ShouldInitProgressBar func is used to determine whether the progress bar should be displayed.
// This default implementation will init the progress bar if the following conditions are met:
// CI == false (or unset) and Stderr is a terminal.
var ShouldInitProgressBar = func() (bool, error) {
	ci, err := utils.GetBoolEnvValue(coreutils.CI, false)
	if ci || err != nil {
		return false, err
	}
	if !log.IsTerminal() {
		return false, err
	}
	err = setTerminalWidthVar()
	if err != nil {
		return false, err
	}
	return true, nil
}

type filesProgressBarManager struct {
	// A list of progress bar objects.
	bars []progressBar
	// A wait group for all progress bars.
	barsWg *sync.WaitGroup
	// A container of all external mpb bar objects to be displayed.
	container *mpb.Progress
	// A synchronization lock object.
	barsRWMutex sync.RWMutex
	// A general work indicator spinner.
	headlineBar *mpb.Bar
	// A bar that displays the path of the log file.
	logFilePathBar *mpb.Bar
	// A general tasks completion indicator.
	generalProgressBar *mpb.Bar
	// A cumulative amount of tasks
	tasksCount int64
	// The log file
	logFile *os.File
}

type progressBarUnit struct {
	bar         *mpb.Bar
	incrChannel chan int
	description string
}

type progressBar interface {
	ioUtils.Progress
	getProgressBarUnit() *progressBarUnit
}

func (p *filesProgressBarManager) InitProgressReaders() {
	if p.logFile != nil {
		p.printLogFilePathAsBar(p.logFile.Name())
	}
	p.newHeadlineBar(" Working")
	p.tasksCount = 0
	p.newGeneralProgressBar()
}

// Initializes a new reader progress indicator for a new file transfer.
// Input: 'total' - file size.
//		  'label' - the title of the operation.
//		  'path' - the path of the file being processed.
// Output: progress indicator id
func (p *filesProgressBarManager) NewProgressReader(total int64, label, path string) (bar ioUtils.Progress) {
	// Write Lock when appending a new bar to the slice
	p.barsRWMutex.Lock()
	defer p.barsRWMutex.Unlock()
	p.barsWg.Add(1)
	newBar := p.container.New(int64(total),
		mpb.BarStyle().Lbound("|").Filler("🟩").Tip("🟩").Padding("⬛").Refiller("").Rbound("|"),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(
			// Extra chars length is the max length of the KibiByteCounter
			decor.Name(buildProgressDescription(label, path, 17)),
			decor.CountersKibiByte("%3.1f/%3.1f"),
		),
	)

	// Add bar to bars array
	unit := initNewBarUnit(newBar, path)
	barId := len(p.bars) + 1
	readerProgressBar := ReaderProgressBar{progressBarUnit: unit, Id: barId}
	p.bars = append(p.bars, &readerProgressBar)
	return &readerProgressBar
}

// Changes progress indicator state and acts accordingly.
func (p *filesProgressBarManager) SetProgressState(id int, state string) {
	switch state {
	case "Merging":
		p.addNewMergingSpinner(id)
	}
}

// Initializes a new progress bar, that replaces the progress bar with the given replacedBarId
func (p *filesProgressBarManager) addNewMergingSpinner(replacedBarId int) {
	// Write Lock when appending a new bar to the slice
	p.barsRWMutex.Lock()
	defer p.barsRWMutex.Unlock()
	replacedBar := p.bars[replacedBarId-1].getProgressBarUnit()
	p.bars[replacedBarId-1].Abort()
	newBar := p.container.New(1,
		mpb.SpinnerStyle(createSpinnerFramesArray()...).PositionLeft(),
		mpb.AppendDecorators(
			decor.Name(buildProgressDescription("  Merging  ", replacedBar.description, 0)),
		),
	)
	// Bar replacement is a simple spinner and thus does not implement any read functionality
	unit := &progressBarUnit{bar: newBar, description: replacedBar.description}
	progressBar := SimpleProgressBar{progressBarUnit: unit, Id: replacedBarId}
	p.bars[replacedBarId-1] = &progressBar
}

func buildProgressDescription(label, path string, extraCharsLen int) string {
	separator := " | "
	// Max line length after decreasing bar width (*2 in case unicode chars with double width are used) and the extra chars
	descMaxLength := terminalWidth - (progressBarWidth*2 + extraCharsLen)
	return buildDescByLimits(descMaxLength, " "+label+separator, shortenUrl(path), separator)
}

func shortenUrl(path string) string {
	if _, err := url.ParseRequestURI(path); err != nil {
		return path
	}

	semicolonIndex := strings.Index(path, ";")
	if semicolonIndex == -1 {
		return path
	}
	return path[:semicolonIndex]
}

func buildDescByLimits(descMaxLength int, prefix, path, suffix string) string {
	desc := prefix + path + suffix

	// Verify that the whole description doesn't exceed the max length
	if len(desc) <= descMaxLength {
		return desc
	}

	// If it does exceed, check if shortening the path will help (+3 is for "...")
	if len(desc)-len(path)+3 > descMaxLength {
		// Still exceeds, do not display desc
		return ""
	}

	// Shorten path from the beginning
	path = "..." + path[len(desc)-descMaxLength+3:]
	return prefix + path + suffix
}

func initNewBarUnit(bar *mpb.Bar, path string) *progressBarUnit {
	ch := make(chan int, 1000)
	unit := &progressBarUnit{bar: bar, incrChannel: ch, description: path}
	go incrBarFromChannel(unit)
	return unit
}

func incrBarFromChannel(unit *progressBarUnit) {
	// Increase bar while channel is open
	for n := range unit.incrChannel {
		unit.bar.IncrBy(n)
	}
}

func createSpinnerFramesArray() []string {
	black := "⬛"
	green := "🟩"
	spinnerFramesArray := make([]string, progressBarWidth)
	for i := 1; i < progressBarWidth-1; i++ {
		cur := "|" + strings.Repeat(black, i-1) + green + strings.Repeat(black, progressBarWidth-2-i) + "|"
		spinnerFramesArray[i] = cur
	}
	return spinnerFramesArray
}

// Aborts a progress bar.
// Should be called even if bar completed successfully.
// The progress component's Abort method has no effect if bar has already completed, so can always be safely called anyway
func (p *filesProgressBarManager) RemoveProgress(id int) {
	p.barsRWMutex.RLock()
	defer p.barsWg.Done()
	defer p.barsRWMutex.RUnlock()
	p.bars[id-1].Abort()
	p.generalProgressBar.Increment()

}

// Quits the progress bar while aborting the initial bars.
func (p *filesProgressBarManager) Quit() (err error) {
	if p.headlineBar != nil {
		p.headlineBar.Abort(true)
		p.barsWg.Done()
		p.headlineBar = nil
	}
	if p.logFilePathBar != nil {
		p.barsWg.Done()
		p.logFilePathBar = nil
	}
	if p.generalProgressBar != nil {
		p.generalProgressBar.Abort(true)
		p.barsWg.Done()
		p.generalProgressBar = nil
	}
	// Wait a refresh rate to make sure all aborts have finished
	time.Sleep(progressRefreshRate)
	p.container.Wait()
	// Close the created log file (once)
	if p.logFile != nil {
		err = logUtils.CloseLogFile(p.logFile)
		p.logFile = nil
		// Set back the default logger
		corelog.SetDefaultLogger()
	}
	return
}

func (p *filesProgressBarManager) GetProgress(id int) ioUtils.Progress {
	return p.bars[id-1]
}

// Initializes progress bar if possible (all conditions in 'shouldInitProgressBar' are met).
// Returns nil, nil, err if failed.
func InitFilesProgressBarIfPossible(printLogPath bool) (ioUtils.ProgressMgr, error) {
	shouldInit, err := ShouldInitProgressBar()
	if !shouldInit || err != nil {
		return nil, err
	}

	logFile, err := logUtils.CreateLogFile()
	if err != nil {
		return nil, err
	}
	if printLogPath {
		log.Info("Log path:", logFile.Name())
	}
	log.SetLogger(log.NewLogger(corelog.GetCliLogLevel(), logFile))

	newProgressBar := &filesProgressBarManager{}
	newProgressBar.barsWg = new(sync.WaitGroup)

	// Initialize the progressBar container with wg, to create a single joint point
	newProgressBar.container = mpb.New(
		mpb.WithOutput(os.Stderr),
		mpb.WithWaitGroup(newProgressBar.barsWg),
		mpb.WithWidth(progressBarWidth),
		mpb.WithRefreshRate(progressRefreshRate))

	newProgressBar.logFile = logFile

	return newProgressBar, nil
}

// Get terminal dimensions
func setTerminalWidthVar() error {
	width, _, err := term.GetSize(int(os.Stderr.Fd()))
	if err != nil {
		return err
	}
	// -5 to avoid edges
	terminalWidth = width - 5
	if terminalWidth <= 0 {
		terminalWidth = 5
	}
	return err
}

// Initializes a new progress bar for general progress indication
func (p *filesProgressBarManager) newGeneralProgressBar() {
	p.barsWg.Add(1)
	p.generalProgressBar = p.container.New(p.tasksCount,
		mpb.BarStyle().Lbound("|").Filler("⬜").Tip("⬜").Padding("⬛").Refiller("").Rbound("|"),
		mpb.BarRemoveOnComplete(),
		mpb.AppendDecorators(
			decor.Name(" Tasks: "),
			decor.CountersNoUnit("%d/%d"),
		),
	)
}

// Initializes a new progress bar for headline, with a spinner
func (p *filesProgressBarManager) newHeadlineBar(headline string) {
	p.barsWg.Add(1)
	p.headlineBar = p.container.New(1,
		mpb.SpinnerStyle("∙∙∙∙∙∙", "●∙∙∙∙∙", "∙●∙∙∙∙", "∙∙●∙∙∙", "∙∙∙●∙∙", "∙∙∙∙●∙", "∙∙∙∙∙●", "∙∙∙∙∙∙").PositionLeft(),
		mpb.BarRemoveOnComplete(),
		mpb.PrependDecorators(
			decor.Name(headline),
		),
	)
}

func (p *filesProgressBarManager) SetHeadlineMsg(msg string) {
	if p.headlineBar != nil {
		current := p.headlineBar
		p.barsRWMutex.RLock()
		// First abort, then mark progress as done and finally release the lock.
		defer p.barsRWMutex.RUnlock()
		defer p.barsWg.Done()
		defer current.Abort(true)
	}
	p.newHeadlineBar(msg)
}

func (p *filesProgressBarManager) ClearHeadlineMsg() {
	if p.headlineBar != nil {
		p.barsRWMutex.RLock()
		p.headlineBar.Abort(true)
		p.barsWg.Done()
		p.barsRWMutex.RUnlock()
		// Wait a refresh rate to make sure the abort has finished
		time.Sleep(progressRefreshRate)
	}
	p.headlineBar = nil
}

// Initializes a new progress bar that states the log file path. The bar's text remains after cli is done.
func (p *filesProgressBarManager) printLogFilePathAsBar(path string) {
	p.barsWg.Add(1)
	prefix := " Log path: "
	p.logFilePathBar = p.container.AddBar(0,
		mpb.BarFillerClearOnComplete(),
		mpb.PrependDecorators(
			decor.Name(buildDescByLimits(terminalWidth, prefix, path, "")),
		),
	)
	p.logFilePathBar.SetTotal(0, true)
}

// IncGeneralProgressTotalBy increments the general progress bar total count by given n.
func (p *filesProgressBarManager) IncGeneralProgressTotalBy(n int64) {
	atomic.AddInt64(&p.tasksCount, n)
	if p.generalProgressBar != nil {
		p.generalProgressBar.SetTotal(p.tasksCount, false)
	}
}

type CommandWithProgress interface {
	commands.Command
	SetProgress(ioUtils.ProgressMgr)
}

func ExecWithProgress(cmd CommandWithProgress, printLogPath bool) (err error) {
	// Init progress bar.
	progressBar, err := InitFilesProgressBarIfPossible(printLogPath)
	if err != nil {
		return err
	}
	if progressBar != nil {
		cmd.SetProgress(progressBar)
		defer func() {
			e := progressBar.Quit()
			if err == nil {
				err = e
			}
		}()
	}
	err = commands.Exec(cmd)
	return
}
<|endoftext|>


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

// Command solid-mgr-rpi updates the RPi read-only configuration with a new overlay.
package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/pkg/errors"
)

const (
	bootCmdLine = "/tmp/boot/cmdline.txt" // FIXME(sbinet)
)

func main() {
	log.SetPrefix("rpi-mgr: ")
	log.SetFlags(0)

	flag.Parse()

	host := flag.Arg(0)
	cmd := flag.Arg(1)
	log.Printf("host=%q", host)
	log.Printf("cmd=%q", cmd)

	switch cmd {
	case "ro":
		err := cmdRO(host)
		if err != nil {
			log.Fatal(err)
		}
	case "rw":
		err := cmdRW(host)
		if err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("unknown command %q", cmd)
	}
}

func removeOverlay(p []byte) ([]byte, error) {
	o := bytes.Replace(p, []byte("boot=overlay "), []byte(""), -1)
	o = bytes.Replace(o, []byte(" boot=overlay"), []byte(""), -1)
	o = bytes.Replace(o, []byte("  "), []byte(" "), -1)
	return o, nil
}

func addOverlay(p []byte) ([]byte, error) {
	o, err := removeOverlay(p)
	if err != nil {
		return nil, err
	}
	o = append([]byte("boot=overlay "), o...)
	return o, nil
}

func cmdRO(host string) error {
	buf, err := fetchContent(host)
	if err != nil {
		return err
	}

	ro, err := addOverlay(buf)
	if err != nil {
		return errors.Wrapf(err, "could not add boot=overlay to %s:%s", host, bootCmdLine)
	}

	err = putContent(host, ro)
	if err != nil {
		return err
	}

	return nil
}

func cmdRW(host string) error {
	buf, err := fetchContent(host)
	if err != nil {
		return err
	}

	ro, err := removeOverlay(buf)
	if err != nil {
		return errors.Wrapf(err, "could not remove boot=overlay from %s:%s", host, bootCmdLine)
	}

	err = putContent(host, ro)
	if err != nil {
		return err
	}

	return nil
}

func fetchContent(host string) ([]byte, error) {
	buf := new(bytes.Buffer)
	cmd := exec.Command("ssh", host, "--", "cat", bootCmdLine)
	cmd.Stdout = buf
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		return nil, errors.Wrapf(err, "could not extract %q from %q", bootCmdLine, host)
	}

	log.Printf("content: %q", buf.String())

	return buf.Bytes(), nil
}

func putContent(host string, data []byte) error {
	tmp, err := ioutil.TempDir("", "solid-mgr-boot-")
	if err != nil {
		return errors.Wrapf(err, "could not create temporary directory")
	}
	defer os.RemoveAll(tmp)

	fname := filepath.Join(tmp, "cmdline.txt")
	err = ioutil.WriteFile(fname, data, 0644)
	if err != nil {
		return errors.Wrapf(err, "could not create new ro cmdline.txt file")
	}

	cmd := exec.Command("scp", fname, host+":"+bootCmdLine)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<commit_msg>solid-mgr-rpi: point at /boot/cmdline.txt<commit_after>// Copyright 2018 The solid-mon-rpi Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command solid-mgr-rpi updates the RPi read-only configuration with a new overlay.
package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/pkg/errors"
)

const (
	bootCmdLine = "/boot/cmdline.txt"
)

func main() {
	log.SetPrefix("rpi-mgr: ")
	log.SetFlags(0)

	flag.Parse()

	host := flag.Arg(0)
	cmd := flag.Arg(1)
	log.Printf("host=%q", host)
	log.Printf("cmd=%q", cmd)

	switch cmd {
	case "ro":
		err := cmdRO(host)
		if err != nil {
			log.Fatal(err)
		}
	case "rw":
		err := cmdRW(host)
		if err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("unknown command %q", cmd)
	}
}

func removeOverlay(p []byte) ([]byte, error) {
	o := bytes.Replace(p, []byte("boot=overlay "), []byte(""), -1)
	o = bytes.Replace(o, []byte(" boot=overlay"), []byte(""), -1)
	o = bytes.Replace(o, []byte("  "), []byte(" "), -1)
	return o, nil
}

func addOverlay(p []byte) ([]byte, error) {
	o, err := removeOverlay(p)
	if err != nil {
		return nil, err
	}
	o = append([]byte("boot=overlay "), o...)
	return o, nil
}

func cmdRO(host string) error {
	buf, err := fetchContent(host)
	if err != nil {
		return err
	}

	ro, err := addOverlay(buf)
	if err != nil {
		return errors.Wrapf(err, "could not add boot=overlay to %s:%s", host, bootCmdLine)
	}

	err = putContent(host, ro)
	if err != nil {
		return err
	}

	return nil
}

func cmdRW(host string) error {
	buf, err := fetchContent(host)
	if err != nil {
		return err
	}

	ro, err := removeOverlay(buf)
	if err != nil {
		return errors.Wrapf(err, "could not remove boot=overlay from %s:%s", host, bootCmdLine)
	}

	err = putContent(host, ro)
	if err != nil {
		return err
	}

	return nil
}

func fetchContent(host string) ([]byte, error) {
	buf := new(bytes.Buffer)
	cmd := exec.Command("ssh", host, "--", "cat", bootCmdLine)
	cmd.Stdout = buf
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		return nil, errors.Wrapf(err, "could not extract %q from %q", bootCmdLine, host)
	}

	log.Printf("content: %q", buf.String())

	return buf.Bytes(), nil
}

func putContent(host string, data []byte) error {
	tmp, err := ioutil.TempDir("", "solid-mgr-boot-")
	if err != nil {
		return errors.Wrapf(err, "could not create temporary directory")
	}
	defer os.RemoveAll(tmp)

	fname := filepath.Join(tmp, "cmdline.txt")
	err = ioutil.WriteFile(fname, data, 0644)
	if err != nil {
		return errors.Wrapf(err, "could not create new ro cmdline.txt file")
	}

	cmd := exec.Command("scp", fname, host+":"+bootCmdLine)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

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

type somaNodeRequest struct {
	action string
	node   somaproto.ProtoNode
	reply  chan []somaNodeResult
}

type somaNodeResult struct {
	rErr error
	lErr error
	node somaproto.ProtoNode
}

/* Read Access
 *
 */
type somaNodeReadHandler struct {
	input     chan somaNodeRequest
	shutdown  chan bool
	conn      *sql.DB
	list_stmt *sql.Stmt
	show_stmt *sql.Stmt
}

func (r *somaNodeReadHandler) run() {
	var err error

	log.Println("Prepare: node/list")
	r.list_stmt, err = r.conn.Prepare(`
SELECT node_id,
       node_name
FROM   soma.nodes
WHERE  node_online;`)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Prepare: node/show")
	r.show_stmt, err = r.conn.Prepare(`
SELECT node_id,
       node_asset_id,
       node_name,
       organizational_team_id,
       server_id,
       object_state,
       node_online,
       node_deleted,
FROM   soma.nodes
WHERE  node_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}

runloop:
	for {
		select {
		case <-r.shutdown:
			break runloop
		case req := <-r.input:
			go func() {
				r.process(&req)
			}()
		}
	}
}

func (r *somaNodeReadHandler) process(q *somaNodeRequest) {
	var nodeId, nodeName, nodeTeam, nodeServer, nodeState string
	var nodeAsset int
	var nodeOnline, nodeDeleted bool
	var rows *sql.Rows
	var err error
	result := make([]somaNodeResult, 0)

	switch q.action {
	case "list":
		log.Printf("R: node/list")
		rows, err = r.list_stmt.Query()
		defer rows.Close()
		result = append(result, somaNodeResult{
			rErr: err,
		})
		q.reply <- result
		return

		for rows.Next() {
			err := rows.Scan(&nodeId, &nodeName)
			if err != nil {
				result = append(result, somaNodeResult{
					lErr: err,
				})
				err = nil
				continue
			}
			result = append(result, somaNodeResult{
				node: somaproto.ProtoNode{
					Id:   nodeId,
					Name: nodeName,
				},
			})
		}
	case "show":
		log.Printf("R: node/show")
		err = r.show_stmt.QueryRow(q.node.Id).Scan(
			&nodeId,
			&nodeAsset,
			&nodeName,
			&nodeTeam,
			&nodeServer,
			&nodeState,
			&nodeOnline,
			&nodeDeleted,
		)
		if err != nil {
			if err.Error() != "sql: no rows in result set" {
				result = append(result, somaNodeResult{
					rErr: err,
				})
			}
			q.reply <- result
			return
		}

		result = append(result, somaNodeResult{
			node: somaproto.ProtoNode{
				Id:        nodeId,
				AssetId:   uint64(nodeAsset),
				Name:      nodeName,
				Team:      nodeTeam,
				Server:    nodeServer,
				State:     nodeState,
				IsOnline:  nodeOnline,
				IsDeleted: nodeDeleted,
			},
		})
	default:
		result = append(result, somaNodeResult{
			rErr: errors.New("not implemented"),
		})
	}
	q.reply <- result
}

/* Write Access
 *
 */
type somaNodeWriteHandler struct {
	input    chan somaNodeRequest
	shutdown chan bool
	conn     *sql.DB
	add_stmt *sql.Stmt
	del_stmt *sql.Stmt
	prg_stmt *sql.Stmt
}

func (w *somaNodeWriteHandler) run() {
	var err error

	log.Println("Prepare: node/add")
	w.add_stmt, err = w.conn.Prepare(`
INSERT INTO soma.nodes (
	node_id,
	node_asset_id,
	node_name,
	organizational_team_id,
	server_id,
	object_state,
	node_online,
    node_deleted)
SELECT $1, $2, $3, $4, $5, $6, $7, $8
WHERE NOT EXISTS (
	SELECT node_id
	FROM   soma.nodes
	WHERE  node_id = $9
	OR     node_asset_id = $10
    OR     (node_name = $11 AND node_online));`)
	if err != nil {
		log.Fatal("node/add: ", err)
	}
	defer w.add_stmt.Close()

	log.Println("Prepare: node/del")
	w.del_stmt, err = w.conn.Prepare(`
UPDATE soma.nodes
SET    node_deleted = yes
WHERE  node_id = $1
AND    node_deleted = no;`)
	if err != nil {
		log.Fatal("node/del: ", err)
	}
	defer w.del_stmt.Close()

	log.Println("Prepare: node/prg")
	w.prg_stmt, err = w.conn.Prepare(`
DELETE FROM soma.nodes
WHERE       node_id = $1
AND         node_deleted;`)
	if err != nil {
		log.Fatal("node/prg: ", err)
	}
	defer w.prg_stmt.Close()

runloop:
	for {
		select {
		case <-w.shutdown:
			break runloop
		case req := <-w.input:
			w.process(&req)
		}
	}
}

func (w *somaNodeWriteHandler) process(q *somaNodeRequest) {
	var res sql.Result
	var err error
	result := make([]somaNodeResult, 0)

	switch q.action {
	case "add":
		log.Printf("R: node/add for %s", q.node.Name)
		id := uuid.NewV4()
		res, err = w.add_stmt.Exec(
			id.String(),
			q.node.AssetId,
			q.node.Name,
			q.node.Team,
			q.node.Server,
			q.node.State,
			q.node.IsOnline,
			q.node.IsDeleted,
			id.String(),
			q.node.AssetId,
			q.node.Name,
		)
		q.node.Id = id.String()
	case "delete":
		log.Printf("R: node/delete for %s", q.node.Id)
		res, err = w.del_stmt.Exec(
			q.node.Id,
		)
		// TODO trigger undeployment
	case "purge":
		log.Printf("R: node/purge for %s", q.node.Id)
		res, err = w.prg_stmt.Exec(
			q.node.Id,
		)
	default:
		log.Printf("R: unimplemented node/%s", q.action)
		result = append(result, somaNodeResult{
			rErr: errors.New("not implemented"),
		})
		q.reply <- result
		return
	}
	if err != nil {
		result = append(result, somaNodeResult{
			rErr: err,
		})
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result = append(result, somaNodeResult{
			lErr: errors.New("No rows affected"),
		})
	case rowCnt > 1:
		result = append(result, somaNodeResult{
			lErr: fmt.Errorf("Too many rows affected: %d", rowCnt),
		})
	default:
		result = append(result, somaNodeResult{
			node: q.node,
		})
	}
	q.reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>BUGFIX: nodes request error handling<commit_after>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

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

type somaNodeRequest struct {
	action string
	node   somaproto.ProtoNode
	reply  chan []somaNodeResult
}

type somaNodeResult struct {
	rErr error
	lErr error
	node somaproto.ProtoNode
}

/* Read Access
 *
 */
type somaNodeReadHandler struct {
	input     chan somaNodeRequest
	shutdown  chan bool
	conn      *sql.DB
	list_stmt *sql.Stmt
	show_stmt *sql.Stmt
}

func (r *somaNodeReadHandler) run() {
	var err error

	log.Println("Prepare: node/list")
	r.list_stmt, err = r.conn.Prepare(`
SELECT node_id,
       node_name
FROM   soma.nodes
WHERE  node_online;`)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Prepare: node/show")
	r.show_stmt, err = r.conn.Prepare(`
SELECT node_id,
       node_asset_id,
       node_name,
       organizational_team_id,
       server_id,
       object_state,
       node_online,
       node_deleted,
FROM   soma.nodes
WHERE  node_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}

runloop:
	for {
		select {
		case <-r.shutdown:
			break runloop
		case req := <-r.input:
			go func() {
				r.process(&req)
			}()
		}
	}
}

func (r *somaNodeReadHandler) process(q *somaNodeRequest) {
	var nodeId, nodeName, nodeTeam, nodeServer, nodeState string
	var nodeAsset int
	var nodeOnline, nodeDeleted bool
	var rows *sql.Rows
	var err error
	result := make([]somaNodeResult, 0)

	switch q.action {
	case "list":
		log.Printf("R: node/list")
		rows, err = r.list_stmt.Query()
		defer rows.Close()
		if err != nil {
			result = append(result, somaNodeResult{
				rErr: err,
			})
			q.reply <- result
			return
		}

		for rows.Next() {
			err := rows.Scan(&nodeId, &nodeName)
			if err != nil {
				result = append(result, somaNodeResult{
					lErr: err,
				})
				err = nil
				continue
			}
			result = append(result, somaNodeResult{
				node: somaproto.ProtoNode{
					Id:   nodeId,
					Name: nodeName,
				},
			})
		}
	case "show":
		log.Printf("R: node/show")
		err = r.show_stmt.QueryRow(q.node.Id).Scan(
			&nodeId,
			&nodeAsset,
			&nodeName,
			&nodeTeam,
			&nodeServer,
			&nodeState,
			&nodeOnline,
			&nodeDeleted,
		)
		if err != nil {
			if err.Error() != "sql: no rows in result set" {
				result = append(result, somaNodeResult{
					rErr: err,
				})
			}
			q.reply <- result
			return
		}

		result = append(result, somaNodeResult{
			node: somaproto.ProtoNode{
				Id:        nodeId,
				AssetId:   uint64(nodeAsset),
				Name:      nodeName,
				Team:      nodeTeam,
				Server:    nodeServer,
				State:     nodeState,
				IsOnline:  nodeOnline,
				IsDeleted: nodeDeleted,
			},
		})
	default:
		result = append(result, somaNodeResult{
			rErr: errors.New("not implemented"),
		})
	}
	q.reply <- result
}

/* Write Access
 *
 */
type somaNodeWriteHandler struct {
	input    chan somaNodeRequest
	shutdown chan bool
	conn     *sql.DB
	add_stmt *sql.Stmt
	del_stmt *sql.Stmt
	prg_stmt *sql.Stmt
}

func (w *somaNodeWriteHandler) run() {
	var err error

	log.Println("Prepare: node/add")
	w.add_stmt, err = w.conn.Prepare(`
INSERT INTO soma.nodes (
	node_id,
	node_asset_id,
	node_name,
	organizational_team_id,
	server_id,
	object_state,
	node_online,
    node_deleted)
SELECT $1, $2, $3, $4, $5, $6, $7, $8
WHERE NOT EXISTS (
	SELECT node_id
	FROM   soma.nodes
	WHERE  node_id = $9
	OR     node_asset_id = $10
    OR     (node_name = $11 AND node_online));`)
	if err != nil {
		log.Fatal("node/add: ", err)
	}
	defer w.add_stmt.Close()

	log.Println("Prepare: node/del")
	w.del_stmt, err = w.conn.Prepare(`
UPDATE soma.nodes
SET    node_deleted = yes
WHERE  node_id = $1
AND    node_deleted = no;`)
	if err != nil {
		log.Fatal("node/del: ", err)
	}
	defer w.del_stmt.Close()

	log.Println("Prepare: node/prg")
	w.prg_stmt, err = w.conn.Prepare(`
DELETE FROM soma.nodes
WHERE       node_id = $1
AND         node_deleted;`)
	if err != nil {
		log.Fatal("node/prg: ", err)
	}
	defer w.prg_stmt.Close()

runloop:
	for {
		select {
		case <-w.shutdown:
			break runloop
		case req := <-w.input:
			w.process(&req)
		}
	}
}

func (w *somaNodeWriteHandler) process(q *somaNodeRequest) {
	var res sql.Result
	var err error
	result := make([]somaNodeResult, 0)

	switch q.action {
	case "add":
		log.Printf("R: node/add for %s", q.node.Name)
		id := uuid.NewV4()
		res, err = w.add_stmt.Exec(
			id.String(),
			q.node.AssetId,
			q.node.Name,
			q.node.Team,
			q.node.Server,
			q.node.State,
			q.node.IsOnline,
			q.node.IsDeleted,
			id.String(),
			q.node.AssetId,
			q.node.Name,
		)
		q.node.Id = id.String()
	case "delete":
		log.Printf("R: node/delete for %s", q.node.Id)
		res, err = w.del_stmt.Exec(
			q.node.Id,
		)
		// TODO trigger undeployment
	case "purge":
		log.Printf("R: node/purge for %s", q.node.Id)
		res, err = w.prg_stmt.Exec(
			q.node.Id,
		)
	default:
		log.Printf("R: unimplemented node/%s", q.action)
		result = append(result, somaNodeResult{
			rErr: errors.New("not implemented"),
		})
		q.reply <- result
		return
	}
	if err != nil {
		result = append(result, somaNodeResult{
			rErr: err,
		})
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result = append(result, somaNodeResult{
			lErr: errors.New("No rows affected"),
		})
	case rowCnt > 1:
		result = append(result, somaNodeResult{
			lErr: fmt.Errorf("Too many rows affected: %d", rowCnt),
		})
	default:
		result = append(result, somaNodeResult{
			node: q.node,
		})
	}
	q.reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package dns

import (
	// "fmt"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors/server"
	"github.com/nanobox-io/nanobox/util"
	"github.com/nanobox-io/nanobox/util/display"
	"github.com/nanobox-io/nanobox/util/dns"
)

var AppSetup func(envModel *models.Env, appModel *models.App, name string) error

// Add adds a dns entry to the local hosts file
func Add(envModel *models.Env, appModel *models.App, name string) error {

	if err := AppSetup(envModel, appModel, appModel.Name); err != nil {
		return util.ErrorAppend(err, "failed to setup app")
	}

	// fetch the IP
	// env in dev is used in the dev container
	// env in sim is used for portal
	envIP := appModel.LocalIPs["env"]

	// generate the dns entry
	entry := dns.Entry(envIP, name, appModel.ID)

	// short-circuit if this entry already exists
	if dns.Exists(entry) {
		return nil
	}

	// make sure the server is running since it will do the dns addition
	if err := server.Setup(); err != nil {
		return util.ErrorAppend(err, "failed to setup server")
	}

	// issue a warning about `.dev` being unusable with Chrome
	if name[len(name)-4:] == ".dev" {
		tld := appModel.DisplayName()
		if tld == "dry-run" {
			tld = "test"
		}

		display.Warn("\nGoogle has been locking down use of the .dev TLD, and your app may not be accessible with this domain.\nTry using %s.%s instead\n", name[0:len(name)-4], tld)
	}

	// add the entry
	if err := dns.Add(entry); err != nil {
		lumber.Error("dns:Add:dns.Add(%s): %s", entry, err.Error())
		return util.ErrorAppend(err, "unable to add dns entry")
	}

	display.Info("\n%s %s added\n", display.TaskComplete, name)

	return nil
}
<commit_msg>Make the .dev TLD warning a fatal error<commit_after>package dns

import (
	// "fmt"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors/server"
	"github.com/nanobox-io/nanobox/util"
	"github.com/nanobox-io/nanobox/util/display"
	"github.com/nanobox-io/nanobox/util/dns"
)

var AppSetup func(envModel *models.Env, appModel *models.App, name string) error

// Add adds a dns entry to the local hosts file
func Add(envModel *models.Env, appModel *models.App, name string) error {

	if err := AppSetup(envModel, appModel, appModel.Name); err != nil {
		return util.ErrorAppend(err, "failed to setup app")
	}

	// fetch the IP
	// env in dev is used in the dev container
	// env in sim is used for portal
	envIP := appModel.LocalIPs["env"]

	// generate the dns entry
	entry := dns.Entry(envIP, name, appModel.ID)

	// short-circuit if this entry already exists
	if dns.Exists(entry) {
		return nil
	}

	// make sure the server is running since it will do the dns addition
	if err := server.Setup(); err != nil {
		return util.ErrorAppend(err, "failed to setup server")
	}

	// issue a warning about `.dev` being unusable with Chrome
	if name[len(name)-4:] == ".dev" {
		tld := appModel.DisplayName()
		if tld == "dry-run" {
			tld = "test"
		}

		return util.Errorf("Google has been locking down use of the .dev TLD, and your app may not be accessible with this domain.\nTry using %s.%s instead.", name[0:len(name)-4], tld)
	}

	// add the entry
	if err := dns.Add(entry); err != nil {
		lumber.Error("dns:Add:dns.Add(%s): %s", entry, err.Error())
		return util.ErrorAppend(err, "unable to add dns entry")
	}

	display.Info("\n%s %s added\n", display.TaskComplete, name)

	return nil
}
<|endoftext|>


<commit_before>package p2p

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"errors"
	"hash"
	"io"

	"github.com/ethereum/go-ethereum/rlp"
)

var (
	// this is used in place of actual frame header data.
	// TODO: replace this when Msg contains the protocol type code.
	zeroHeader = []byte{0xC2, 0x80, 0x80}

	// sixteen zero bytes
	zero16 = make([]byte, 16)
)

// rlpxFrameRW implements a simplified version of RLPx framing.
// chunked messages are not supported and all headers are equal to
// zeroHeader.
//
// rlpxFrameRW is not safe for concurrent use from multiple goroutines.
type rlpxFrameRW struct {
	conn io.ReadWriter
	enc  cipher.Stream
	dec  cipher.Stream

	macCipher  cipher.Block
	egressMAC  hash.Hash
	ingressMAC hash.Hash
}

func newRlpxFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW {
	macc, err := aes.NewCipher(s.MAC)
	if err != nil {
		panic("invalid MAC secret: " + err.Error())
	}
	encc, err := aes.NewCipher(s.AES)
	if err != nil {
		panic("invalid AES secret: " + err.Error())
	}
	// we use an all-zeroes IV for AES because the key used
	// for encryption is ephemeral.
	iv := make([]byte, encc.BlockSize())
	return &rlpxFrameRW{
		conn:       conn,
		enc:        cipher.NewCTR(encc, iv),
		dec:        cipher.NewCTR(encc, iv),
		macCipher:  macc,
		egressMAC:  s.EgressMAC,
		ingressMAC: s.IngressMAC,
	}
}

func (rw *rlpxFrameRW) WriteMsg(msg Msg) error {
	ptype, _ := rlp.EncodeToBytes(msg.Code)

	// write header
	headbuf := make([]byte, 32)
	fsize := uint32(len(ptype)) + msg.Size
	putInt24(fsize, headbuf) // TODO: check overflow
	copy(headbuf[3:], zeroHeader)
	rw.enc.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now encrypted

	// write header MAC
	copy(headbuf[16:], updateMAC(rw.egressMAC, rw.macCipher, headbuf[:16]))
	if _, err := rw.conn.Write(headbuf); err != nil {
		return err
	}

	// write encrypted frame, updating the egress MAC hash with
	// the data written to conn.
	tee := cipher.StreamWriter{S: rw.enc, W: io.MultiWriter(rw.conn, rw.egressMAC)}
	if _, err := tee.Write(ptype); err != nil {
		return err
	}
	if _, err := io.Copy(tee, msg.Payload); err != nil {
		return err
	}
	if padding := fsize % 16; padding > 0 {
		if _, err := tee.Write(zero16[:16-padding]); err != nil {
			return err
		}
	}

	// write frame MAC. egress MAC hash is up to date because
	// frame content was written to it as well.
	fmacseed := rw.egressMAC.Sum(nil)
	mac := updateMAC(rw.egressMAC, rw.macCipher, fmacseed)
	_, err := rw.conn.Write(mac)
	return err
}

func (rw *rlpxFrameRW) ReadMsg() (msg Msg, err error) {
	// read the header
	headbuf := make([]byte, 32)
	if _, err := io.ReadFull(rw.conn, headbuf); err != nil {
		return msg, err
	}
	// verify header mac
	shouldMAC := updateMAC(rw.ingressMAC, rw.macCipher, headbuf[:16])
	if !hmac.Equal(shouldMAC, headbuf[16:]) {
		return msg, errors.New("bad header MAC")
	}
	rw.dec.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now decrypted
	fsize := readInt24(headbuf)
	// ignore protocol type for now

	// read the frame content
	var rsize = fsize // frame size rounded up to 16 byte boundary
	if padding := fsize % 16; padding > 0 {
		rsize += 16 - padding
	}
	framebuf := make([]byte, rsize)
	if _, err := io.ReadFull(rw.conn, framebuf); err != nil {
		return msg, err
	}

	// read and validate frame MAC. we can re-use headbuf for that.
	rw.ingressMAC.Write(framebuf)
	fmacseed := rw.ingressMAC.Sum(nil)
	if _, err := io.ReadFull(rw.conn, headbuf[:16]); err != nil {
		return msg, err
	}
	shouldMAC = updateMAC(rw.ingressMAC, rw.macCipher, fmacseed)
	if !hmac.Equal(shouldMAC, headbuf[:16]) {
		return msg, errors.New("bad frame MAC")
	}

	// decrypt frame content
	rw.dec.XORKeyStream(framebuf, framebuf)

	// decode message code
	content := bytes.NewReader(framebuf[:fsize])
	if err := rlp.Decode(content, &msg.Code); err != nil {
		return msg, err
	}
	msg.Size = uint32(content.Len())
	msg.Payload = content
	return msg, nil
}

// updateMAC reseeds the given hash with encrypted seed.
// it returns the first 16 bytes of the hash sum after seeding.
func updateMAC(mac hash.Hash, block cipher.Block, seed []byte) []byte {
	aesbuf := make([]byte, aes.BlockSize)
	block.Encrypt(aesbuf, mac.Sum(nil))
	for i := range aesbuf {
		aesbuf[i] ^= seed[i]
	}
	mac.Write(aesbuf)
	return mac.Sum(nil)[:16]
}

func readInt24(b []byte) uint32 {
	return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16
}

func putInt24(v uint32, b []byte) {
	b[0] = byte(v >> 16)
	b[1] = byte(v >> 8)
	b[2] = byte(v)
}
<commit_msg>p2p: reject messages that cannot be written as simple RLPx frames<commit_after>package p2p

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"errors"
	"hash"
	"io"

	"github.com/ethereum/go-ethereum/rlp"
)

var (
	// this is used in place of actual frame header data.
	// TODO: replace this when Msg contains the protocol type code.
	zeroHeader = []byte{0xC2, 0x80, 0x80}

	// sixteen zero bytes
	zero16 = make([]byte, 16)

	maxUint24 = ^uint32(0) >> 8
)

// rlpxFrameRW implements a simplified version of RLPx framing.
// chunked messages are not supported and all headers are equal to
// zeroHeader.
//
// rlpxFrameRW is not safe for concurrent use from multiple goroutines.
type rlpxFrameRW struct {
	conn io.ReadWriter
	enc  cipher.Stream
	dec  cipher.Stream

	macCipher  cipher.Block
	egressMAC  hash.Hash
	ingressMAC hash.Hash
}

func newRlpxFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW {
	macc, err := aes.NewCipher(s.MAC)
	if err != nil {
		panic("invalid MAC secret: " + err.Error())
	}
	encc, err := aes.NewCipher(s.AES)
	if err != nil {
		panic("invalid AES secret: " + err.Error())
	}
	// we use an all-zeroes IV for AES because the key used
	// for encryption is ephemeral.
	iv := make([]byte, encc.BlockSize())
	return &rlpxFrameRW{
		conn:       conn,
		enc:        cipher.NewCTR(encc, iv),
		dec:        cipher.NewCTR(encc, iv),
		macCipher:  macc,
		egressMAC:  s.EgressMAC,
		ingressMAC: s.IngressMAC,
	}
}

func (rw *rlpxFrameRW) WriteMsg(msg Msg) error {
	ptype, _ := rlp.EncodeToBytes(msg.Code)

	// write header
	headbuf := make([]byte, 32)
	fsize := uint32(len(ptype)) + msg.Size
	if fsize > maxUint24 {
		return errors.New("message size overflows uint24")
	}
	putInt24(fsize, headbuf) // TODO: check overflow
	copy(headbuf[3:], zeroHeader)
	rw.enc.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now encrypted

	// write header MAC
	copy(headbuf[16:], updateMAC(rw.egressMAC, rw.macCipher, headbuf[:16]))
	if _, err := rw.conn.Write(headbuf); err != nil {
		return err
	}

	// write encrypted frame, updating the egress MAC hash with
	// the data written to conn.
	tee := cipher.StreamWriter{S: rw.enc, W: io.MultiWriter(rw.conn, rw.egressMAC)}
	if _, err := tee.Write(ptype); err != nil {
		return err
	}
	if _, err := io.Copy(tee, msg.Payload); err != nil {
		return err
	}
	if padding := fsize % 16; padding > 0 {
		if _, err := tee.Write(zero16[:16-padding]); err != nil {
			return err
		}
	}

	// write frame MAC. egress MAC hash is up to date because
	// frame content was written to it as well.
	fmacseed := rw.egressMAC.Sum(nil)
	mac := updateMAC(rw.egressMAC, rw.macCipher, fmacseed)
	_, err := rw.conn.Write(mac)
	return err
}

func (rw *rlpxFrameRW) ReadMsg() (msg Msg, err error) {
	// read the header
	headbuf := make([]byte, 32)
	if _, err := io.ReadFull(rw.conn, headbuf); err != nil {
		return msg, err
	}
	// verify header mac
	shouldMAC := updateMAC(rw.ingressMAC, rw.macCipher, headbuf[:16])
	if !hmac.Equal(shouldMAC, headbuf[16:]) {
		return msg, errors.New("bad header MAC")
	}
	rw.dec.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now decrypted
	fsize := readInt24(headbuf)
	// ignore protocol type for now

	// read the frame content
	var rsize = fsize // frame size rounded up to 16 byte boundary
	if padding := fsize % 16; padding > 0 {
		rsize += 16 - padding
	}
	framebuf := make([]byte, rsize)
	if _, err := io.ReadFull(rw.conn, framebuf); err != nil {
		return msg, err
	}

	// read and validate frame MAC. we can re-use headbuf for that.
	rw.ingressMAC.Write(framebuf)
	fmacseed := rw.ingressMAC.Sum(nil)
	if _, err := io.ReadFull(rw.conn, headbuf[:16]); err != nil {
		return msg, err
	}
	shouldMAC = updateMAC(rw.ingressMAC, rw.macCipher, fmacseed)
	if !hmac.Equal(shouldMAC, headbuf[:16]) {
		return msg, errors.New("bad frame MAC")
	}

	// decrypt frame content
	rw.dec.XORKeyStream(framebuf, framebuf)

	// decode message code
	content := bytes.NewReader(framebuf[:fsize])
	if err := rlp.Decode(content, &msg.Code); err != nil {
		return msg, err
	}
	msg.Size = uint32(content.Len())
	msg.Payload = content
	return msg, nil
}

// updateMAC reseeds the given hash with encrypted seed.
// it returns the first 16 bytes of the hash sum after seeding.
func updateMAC(mac hash.Hash, block cipher.Block, seed []byte) []byte {
	aesbuf := make([]byte, aes.BlockSize)
	block.Encrypt(aesbuf, mac.Sum(nil))
	for i := range aesbuf {
		aesbuf[i] ^= seed[i]
	}
	mac.Write(aesbuf)
	return mac.Sum(nil)[:16]
}

func readInt24(b []byte) uint32 {
	return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16
}

func putInt24(v uint32, b []byte) {
	b[0] = byte(v >> 16)
	b[1] = byte(v >> 8)
	b[2] = byte(v)
}
<|endoftext|>


<commit_before>package TemperatureSensorController

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
	"time"
)

// ReadTemperature is used to access the current temperature from the temperature sensor
func ReadTemperature() (float32, error) {
	var error error
	var bytes []byte
	var path = "/sys/bus/w1/devices/28-8000001fa053/w1_slave"

	bytes, error = ioutil.ReadFile(path)
	time.Sleep(time.Second)
	bytes, error = ioutil.ReadFile(path)

	if error != nil {
		return 0, error
	}

	var wholeText = string(bytes)
	var lines = strings.Split(wholeText, "\n")
	if strings.HasSuffix(lines[0], "NO") {
		return 0, errors.New("Read temperature from sensor failed - the sensor returned 'NO'")
	}

	var indexOfT = strings.Index(lines[1], "t=")
	if indexOfT == -1 {
		return 0, errors.New("Read temperature from sensor failed - 't=' not found")
	}

	var temperatureAsString = string(lines[1][indexOfT+2:])
	var temperature float64
	temperature, error = strconv.ParseFloat(temperatureAsString, 32)
	if error != nil {
		return 0, error
	}

	return float32(temperature / 1000), nil
}
<commit_msg>The temperature returned by ReadTemperature is now rounded to the first digit after the decimal point.<commit_after>package TemperatureSensorController

import (
	"errors"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"time"
)

// ReadTemperature is used to access the current temperature from the temperature sensor
func ReadTemperature() (float32, error) {
	var error error
	var bytes []byte
	var path = "/sys/bus/w1/devices/28-8000001fa053/w1_slave"

	bytes, error = ioutil.ReadFile(path)
	time.Sleep(time.Second)
	bytes, error = ioutil.ReadFile(path)

	if error != nil {
		return 0, error
	}

	var wholeText = string(bytes)
	var lines = strings.Split(wholeText, "\n")
	if strings.HasSuffix(lines[0], "NO") {
		return 0, errors.New("Read temperature from sensor failed - the sensor returned 'NO'")
	}

	var indexOfT = strings.Index(lines[1], "t=")
	if indexOfT == -1 {
		return 0, errors.New("Read temperature from sensor failed - 't=' not found")
	}

	var temperatureAsString = string(lines[1][indexOfT+2:])
	var temperature float64
	temperature, error = strconv.ParseFloat(temperatureAsString, 32)
	if error != nil {
		return 0, error
	}

	return round(float32(temperature/1000), 1)
}

func round(number float32, decimalDigitToRoundTo int) (float32, error) {
	var roundedNumberAsString = fmt.Sprintf("%."+strconv.Itoa(decimalDigitToRoundTo)+"f", number)
	var roundedNumberAsFloat64, error = strconv.ParseFloat(roundedNumberAsString, 32)
	if error != nil {
		return 0, nil
	}

	return float32(roundedNumberAsFloat64), nil
}
<|endoftext|>


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

package http

import (
	"context"
	"net/http"
	"net/http/cookiejar"
	"reflect"

	"fmt"
	"github.com/loadimpact/k6/js/common"
	log "github.com/sirupsen/logrus"
	"net/http/httputil"
)

var (
	typeString                     = reflect.TypeOf("")
	typeURL                        = reflect.TypeOf(URL{})
	typeMapKeyStringValueInterface = reflect.TypeOf(map[string]interface{}{})
)

const (
	HTTP_METHOD_GET                    = "GET"
	HTTP_METHOD_POST                   = "POST"
	HTTP_METHOD_PUT                    = "PUT"
	HTTP_METHOD_DELETE                 = "DELETE"
	HTTP_METHOD_HEAD                   = "HEAD"
	HTTP_METHOD_PATCH                  = "PATCH"
	HTTP_METHOD_OPTIONS                = "OPTIONS"
	OCSP_STATUS_GOOD                   = "good"
	OCSP_STATUS_REVOKED                = "revoked"
	OCSP_STATUS_SERVER_FAILED          = "server_failed"
	OCSP_STATUS_UNKNOWN                = "unknown"
	OCSP_REASON_UNSPECIFIED            = "unspecified"
	OCSP_REASON_KEY_COMPROMISE         = "key_compromise"
	OCSP_REASON_CA_COMPROMISE          = "ca_compromise"
	OCSP_REASON_AFFILIATION_CHANGED    = "affiliation_changed"
	OCSP_REASON_SUPERSEDED             = "superseded"
	OCSP_REASON_CESSATION_OF_OPERATION = "cessation_of_operation"
	OCSP_REASON_CERTIFICATE_HOLD       = "certificate_hold"
	OCSP_REASON_REMOVE_FROM_CRL        = "remove_from_crl"
	OCSP_REASON_PRIVILEGE_WITHDRAWN    = "privilege_withdrawn"
	OCSP_REASON_AA_COMPROMISE          = "aa_compromise"
	SSL_3_0                            = "ssl3.0"
	TLS_1_0                            = "tls1.0"
	TLS_1_1                            = "tls1.1"
	TLS_1_2                            = "tls1.2"
)

type HTTPCookie struct {
	Name, Value, Domain, Path string
	HttpOnly, Secure          bool
	MaxAge                    int
	Expires                   int64
}

type HTTPRequestCookie struct {
	Name, Value string
	Replace     bool
}

type HTTP struct {
	SSL_3_0                            string `js:"SSL_3_0"`
	TLS_1_0                            string `js:"TLS_1_0"`
	TLS_1_1                            string `js:"TLS_1_1"`
	TLS_1_2                            string `js:"TLS_1_2"`
	OCSP_STATUS_GOOD                   string `js:"OCSP_STATUS_GOOD"`
	OCSP_STATUS_REVOKED                string `js:"OCSP_STATUS_REVOKED"`
	OCSP_STATUS_SERVER_FAILED          string `js:"OCSP_STATUS_SERVER_FAILED"`
	OCSP_STATUS_UNKNOWN                string `js:"OCSP_STATUS_UNKNOWN"`
	OCSP_REASON_UNSPECIFIED            string `js:"OCSP_REASON_UNSPECIFIED"`
	OCSP_REASON_KEY_COMPROMISE         string `js:"OCSP_REASON_KEY_COMPROMISE"`
	OCSP_REASON_CA_COMPROMISE          string `js:"OCSP_REASON_CA_COMPROMISE"`
	OCSP_REASON_AFFILIATION_CHANGED    string `js:"OCSP_REASON_AFFILIATION_CHANGED"`
	OCSP_REASON_SUPERSEDED             string `js:"OCSP_REASON_SUPERSEDED"`
	OCSP_REASON_CESSATION_OF_OPERATION string `js:"OCSP_REASON_CESSATION_OF_OPERATION"`
	OCSP_REASON_CERTIFICATE_HOLD       string `js:"OCSP_REASON_CERTIFICATE_HOLD"`
	OCSP_REASON_REMOVE_FROM_CRL        string `js:"OCSP_REASON_REMOVE_FROM_CRL"`
	OCSP_REASON_PRIVILEGE_WITHDRAWN    string `js:"OCSP_REASON_PRIVILEGE_WITHDRAWN"`
	OCSP_REASON_AA_COMPROMISE          string `js:"OCSP_REASON_AA_COMPROMISE"`
}

func New() *HTTP {
	return &HTTP{
		SSL_3_0:                            SSL_3_0,
		TLS_1_0:                            TLS_1_0,
		TLS_1_1:                            TLS_1_1,
		TLS_1_2:                            TLS_1_2,
		OCSP_STATUS_GOOD:                   OCSP_STATUS_GOOD,
		OCSP_STATUS_REVOKED:                OCSP_STATUS_REVOKED,
		OCSP_STATUS_SERVER_FAILED:          OCSP_STATUS_SERVER_FAILED,
		OCSP_STATUS_UNKNOWN:                OCSP_STATUS_UNKNOWN,
		OCSP_REASON_UNSPECIFIED:            OCSP_REASON_UNSPECIFIED,
		OCSP_REASON_KEY_COMPROMISE:         OCSP_REASON_KEY_COMPROMISE,
		OCSP_REASON_CA_COMPROMISE:          OCSP_REASON_CA_COMPROMISE,
		OCSP_REASON_AFFILIATION_CHANGED:    OCSP_REASON_AFFILIATION_CHANGED,
		OCSP_REASON_SUPERSEDED:             OCSP_REASON_SUPERSEDED,
		OCSP_REASON_CESSATION_OF_OPERATION: OCSP_REASON_CESSATION_OF_OPERATION,
		OCSP_REASON_CERTIFICATE_HOLD:       OCSP_REASON_CERTIFICATE_HOLD,
		OCSP_REASON_REMOVE_FROM_CRL:        OCSP_REASON_REMOVE_FROM_CRL,
		OCSP_REASON_PRIVILEGE_WITHDRAWN:    OCSP_REASON_PRIVILEGE_WITHDRAWN,
		OCSP_REASON_AA_COMPROMISE:          OCSP_REASON_AA_COMPROMISE,
	}
}

func (*HTTP) XCookieJar(ctx *context.Context) *HTTPCookieJar {
	return newCookieJar(ctx)
}

func (*HTTP) CookieJar(ctx context.Context) *HTTPCookieJar {
	state := common.GetState(ctx)
	return &HTTPCookieJar{state.CookieJar, &ctx}
}

func (*HTTP) setRequestCookies(req *http.Request, jar *cookiejar.Jar, reqCookies map[string]*HTTPRequestCookie) {
	jarCookies := make(map[string][]*http.Cookie)
	for _, c := range jar.Cookies(req.URL) {
		jarCookies[c.Name] = append(jarCookies[c.Name], c)
	}
	for key, reqCookie := range reqCookies {
		if jc := jarCookies[key]; jc != nil && reqCookie.Replace {
			jarCookies[key] = []*http.Cookie{{Name: key, Value: reqCookie.Value}}
		} else {
			jarCookies[key] = append(jarCookies[key], &http.Cookie{Name: key, Value: reqCookie.Value})
		}
	}
	for _, cookies := range jarCookies {
		for _, c := range cookies {
			req.AddCookie(c)
		}
	}
}

func (*HTTP) debugRequest(state *common.State, req *http.Request, description string) {
	if state.Options.HttpDebug.String != "" {
		dump, err := httputil.DumpRequestOut(req, state.Options.HttpDebug.String == "full")
		if err != nil {
			log.Fatal(err)
		}
		logDump(description, dump)
	}
}

func (*HTTP) debugResponse(state *common.State, res *http.Response, description string) {
	if state.Options.HttpDebug.String != "" {
		dump, err := httputil.DumpResponse(res, state.Options.HttpDebug.String == "full")
		if err != nil {
			log.Fatal(err)
		}
		logDump(description, dump)
	}
}

func logDump(description string, dump []byte) {
	fmt.Printf("%s:\n%s\n", description, dump)
}
<commit_msg>Added nil check on response in debugResponse.<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package http

import (
	"context"
	"net/http"
	"net/http/cookiejar"
	"reflect"

	"fmt"
	"github.com/loadimpact/k6/js/common"
	log "github.com/sirupsen/logrus"
	"net/http/httputil"
)

var (
	typeString                     = reflect.TypeOf("")
	typeURL                        = reflect.TypeOf(URL{})
	typeMapKeyStringValueInterface = reflect.TypeOf(map[string]interface{}{})
)

const (
	HTTP_METHOD_GET                    = "GET"
	HTTP_METHOD_POST                   = "POST"
	HTTP_METHOD_PUT                    = "PUT"
	HTTP_METHOD_DELETE                 = "DELETE"
	HTTP_METHOD_HEAD                   = "HEAD"
	HTTP_METHOD_PATCH                  = "PATCH"
	HTTP_METHOD_OPTIONS                = "OPTIONS"
	OCSP_STATUS_GOOD                   = "good"
	OCSP_STATUS_REVOKED                = "revoked"
	OCSP_STATUS_SERVER_FAILED          = "server_failed"
	OCSP_STATUS_UNKNOWN                = "unknown"
	OCSP_REASON_UNSPECIFIED            = "unspecified"
	OCSP_REASON_KEY_COMPROMISE         = "key_compromise"
	OCSP_REASON_CA_COMPROMISE          = "ca_compromise"
	OCSP_REASON_AFFILIATION_CHANGED    = "affiliation_changed"
	OCSP_REASON_SUPERSEDED             = "superseded"
	OCSP_REASON_CESSATION_OF_OPERATION = "cessation_of_operation"
	OCSP_REASON_CERTIFICATE_HOLD       = "certificate_hold"
	OCSP_REASON_REMOVE_FROM_CRL        = "remove_from_crl"
	OCSP_REASON_PRIVILEGE_WITHDRAWN    = "privilege_withdrawn"
	OCSP_REASON_AA_COMPROMISE          = "aa_compromise"
	SSL_3_0                            = "ssl3.0"
	TLS_1_0                            = "tls1.0"
	TLS_1_1                            = "tls1.1"
	TLS_1_2                            = "tls1.2"
)

type HTTPCookie struct {
	Name, Value, Domain, Path string
	HttpOnly, Secure          bool
	MaxAge                    int
	Expires                   int64
}

type HTTPRequestCookie struct {
	Name, Value string
	Replace     bool
}

type HTTP struct {
	SSL_3_0                            string `js:"SSL_3_0"`
	TLS_1_0                            string `js:"TLS_1_0"`
	TLS_1_1                            string `js:"TLS_1_1"`
	TLS_1_2                            string `js:"TLS_1_2"`
	OCSP_STATUS_GOOD                   string `js:"OCSP_STATUS_GOOD"`
	OCSP_STATUS_REVOKED                string `js:"OCSP_STATUS_REVOKED"`
	OCSP_STATUS_SERVER_FAILED          string `js:"OCSP_STATUS_SERVER_FAILED"`
	OCSP_STATUS_UNKNOWN                string `js:"OCSP_STATUS_UNKNOWN"`
	OCSP_REASON_UNSPECIFIED            string `js:"OCSP_REASON_UNSPECIFIED"`
	OCSP_REASON_KEY_COMPROMISE         string `js:"OCSP_REASON_KEY_COMPROMISE"`
	OCSP_REASON_CA_COMPROMISE          string `js:"OCSP_REASON_CA_COMPROMISE"`
	OCSP_REASON_AFFILIATION_CHANGED    string `js:"OCSP_REASON_AFFILIATION_CHANGED"`
	OCSP_REASON_SUPERSEDED             string `js:"OCSP_REASON_SUPERSEDED"`
	OCSP_REASON_CESSATION_OF_OPERATION string `js:"OCSP_REASON_CESSATION_OF_OPERATION"`
	OCSP_REASON_CERTIFICATE_HOLD       string `js:"OCSP_REASON_CERTIFICATE_HOLD"`
	OCSP_REASON_REMOVE_FROM_CRL        string `js:"OCSP_REASON_REMOVE_FROM_CRL"`
	OCSP_REASON_PRIVILEGE_WITHDRAWN    string `js:"OCSP_REASON_PRIVILEGE_WITHDRAWN"`
	OCSP_REASON_AA_COMPROMISE          string `js:"OCSP_REASON_AA_COMPROMISE"`
}

func New() *HTTP {
	return &HTTP{
		SSL_3_0:                            SSL_3_0,
		TLS_1_0:                            TLS_1_0,
		TLS_1_1:                            TLS_1_1,
		TLS_1_2:                            TLS_1_2,
		OCSP_STATUS_GOOD:                   OCSP_STATUS_GOOD,
		OCSP_STATUS_REVOKED:                OCSP_STATUS_REVOKED,
		OCSP_STATUS_SERVER_FAILED:          OCSP_STATUS_SERVER_FAILED,
		OCSP_STATUS_UNKNOWN:                OCSP_STATUS_UNKNOWN,
		OCSP_REASON_UNSPECIFIED:            OCSP_REASON_UNSPECIFIED,
		OCSP_REASON_KEY_COMPROMISE:         OCSP_REASON_KEY_COMPROMISE,
		OCSP_REASON_CA_COMPROMISE:          OCSP_REASON_CA_COMPROMISE,
		OCSP_REASON_AFFILIATION_CHANGED:    OCSP_REASON_AFFILIATION_CHANGED,
		OCSP_REASON_SUPERSEDED:             OCSP_REASON_SUPERSEDED,
		OCSP_REASON_CESSATION_OF_OPERATION: OCSP_REASON_CESSATION_OF_OPERATION,
		OCSP_REASON_CERTIFICATE_HOLD:       OCSP_REASON_CERTIFICATE_HOLD,
		OCSP_REASON_REMOVE_FROM_CRL:        OCSP_REASON_REMOVE_FROM_CRL,
		OCSP_REASON_PRIVILEGE_WITHDRAWN:    OCSP_REASON_PRIVILEGE_WITHDRAWN,
		OCSP_REASON_AA_COMPROMISE:          OCSP_REASON_AA_COMPROMISE,
	}
}

func (*HTTP) XCookieJar(ctx *context.Context) *HTTPCookieJar {
	return newCookieJar(ctx)
}

func (*HTTP) CookieJar(ctx context.Context) *HTTPCookieJar {
	state := common.GetState(ctx)
	return &HTTPCookieJar{state.CookieJar, &ctx}
}

func (*HTTP) setRequestCookies(req *http.Request, jar *cookiejar.Jar, reqCookies map[string]*HTTPRequestCookie) {
	jarCookies := make(map[string][]*http.Cookie)
	for _, c := range jar.Cookies(req.URL) {
		jarCookies[c.Name] = append(jarCookies[c.Name], c)
	}
	for key, reqCookie := range reqCookies {
		if jc := jarCookies[key]; jc != nil && reqCookie.Replace {
			jarCookies[key] = []*http.Cookie{{Name: key, Value: reqCookie.Value}}
		} else {
			jarCookies[key] = append(jarCookies[key], &http.Cookie{Name: key, Value: reqCookie.Value})
		}
	}
	for _, cookies := range jarCookies {
		for _, c := range cookies {
			req.AddCookie(c)
		}
	}
}

func (*HTTP) debugRequest(state *common.State, req *http.Request, description string) {
	if state.Options.HttpDebug.String != "" {
		dump, err := httputil.DumpRequestOut(req, state.Options.HttpDebug.String == "full")
		if err != nil {
			log.Fatal(err)
		}
		logDump(description, dump)
	}
}

func (*HTTP) debugResponse(state *common.State, res *http.Response, description string) {
	if state.Options.HttpDebug.String != "" && res != nil {
		dump, err := httputil.DumpResponse(res, state.Options.HttpDebug.String == "full")
		if err != nil {
			log.Fatal(err)
		}
		logDump(description, dump)
	}
}

func logDump(description string, dump []byte) {
	fmt.Printf("%s:\n%s\n", description, dump)
}
<|endoftext|>


<commit_before>package flags

import (
	"reflect"
	"unicode/utf8"
	"unsafe"
)

type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)

func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
	return &Group{
		ShortDescription: shortDescription,
		LongDescription:  longDescription,

		data: data,
	}
}

func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
	prio := 0
	var retopt *Option

	for _, opt := range g.options {
		if namematch != nil && namematch(opt, name) && prio < 4 {
			retopt = opt
			prio = 4
		}

		if name == opt.field.Name && prio < 3 {
			retopt = opt
			prio = 3
		}

		if name == opt.LongName && prio < 2 {
			retopt = opt
			prio = 2
		}

		if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
			retopt = opt
			prio = 1
		}
	}

	return retopt
}

func (g *Group) storeDefaults() {
	for _, option := range g.options {
		// First. empty out the value
		if len(option.Default) > 0 {
			option.clear()
		}

		for _, d := range option.Default {
			option.set(&d)
		}

		if !option.value.CanSet() {
			continue
		}

		option.defaultValue = reflect.ValueOf(option.value.Interface())
	}
}

func (g *Group) eachGroup(f func(*Group)) {
	f(g)

	for _, gg := range g.groups {
		gg.eachGroup(f)
	}
}

func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
	stype := realval.Type()

	if sfield != nil {
		if ok, err := handler(realval, sfield); err != nil {
			return err
		} else if ok {
			return nil
		}
	}

	for i := 0; i < stype.NumField(); i++ {
		field := stype.Field(i)

		// PkgName is set only for non-exported fields, which we ignore
		if field.PkgPath != "" {
			continue
		}

		mtag := newMultiTag(string(field.Tag))

		// Skip fields with the no-flag tag
		if mtag.Get("no-flag") != "" {
			continue
		}

		// Dive deep into structs or pointers to structs
		kind := field.Type.Kind()
		fld := realval.Field(i)

		if kind == reflect.Struct {
			if err := g.scanStruct(fld, &field, handler); err != nil {
				return err
			}
		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
			if fld.IsNil() {
				fld.Set(reflect.New(fld.Type().Elem()))
			}

			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
				return err
			}
		}

		longname := mtag.Get("long")
		shortname := mtag.Get("short")

		// Need at least either a short or long name
		if longname == "" && shortname == "" && mtag.Get("ini-name") == "" {
			continue
		}

		short := rune(0)
		rc := utf8.RuneCountInString(shortname)

		if rc > 1 {
			return newErrorf(ErrShortNameTooLong,
				"short names can only be 1 character long, not `%s'",
				shortname)

		} else if rc == 1 {
			short, _ = utf8.DecodeRuneInString(shortname)
		}

		description := mtag.Get("description")
		def := mtag.GetMany("default")
		optionalValue := mtag.GetMany("optional-value")
		valueName := mtag.Get("value-name")
		defaultMask := mtag.Get("default-mask")

		optional := (mtag.Get("optional") != "")
		required := (mtag.Get("required") != "")

		option := &Option{
			Description:      description,
			ShortName:        short,
			LongName:         longname,
			Default:          def,
			OptionalArgument: optional,
			OptionalValue:    optionalValue,
			Required:         required,
			ValueName:        valueName,
			DefaultMask:      defaultMask,

			field: field,
			value: realval.Field(i),
			tag:   mtag,
		}

		g.options = append(g.options, option)
	}

	if duplicateFlagErr := g.checkForDuplicateFlags(); duplicateFlagErr != nil {
		return duplicateFlagErr
	}

	return nil
}

func (g *Group) checkForDuplicateFlags() error {
	shortNames := make(map[rune]*Option)
	longNames := make(map[string]*Option)

	var duplicateError *Error
	g.eachGroup(func(g *Group) {
		for _, option := range g.options {
			if option.LongName != "" {
				if otherOption, ok := longNames[option.LongName]; ok {
					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption)
					return
				}
				longNames[option.LongName] = option
			}
			if option.ShortName != 0 {
				if otherOption, ok := shortNames[option.ShortName]; ok {
					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption)
					return
				}
				shortNames[option.ShortName] = option
			}
		}
	})

	return duplicateError
}

func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
	mtag := newMultiTag(string(sfield.Tag))

	subgroup := mtag.Get("group")

	if len(subgroup) != 0 {
		ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
		description := mtag.Get("description")

		if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}

func (g *Group) scanType(handler scanHandler) error {
	// Get all the public fields in the data struct
	ptrval := reflect.ValueOf(g.data)

	if ptrval.Type().Kind() != reflect.Ptr {
		panic(ErrNotPointerToStruct)
	}

	stype := ptrval.Type().Elem()

	if stype.Kind() != reflect.Struct {
		panic(ErrNotPointerToStruct)
	}

	realval := reflect.Indirect(ptrval)

	return g.scanStruct(realval, nil, handler)
}

func (g *Group) scan() error {
	return g.scanType(g.scanSubGroupHandler)
}

func (g *Group) groupByName(name string) *Group {
	if len(name) == 0 {
		return g
	}

	return g.Find(name)
}
<commit_msg>Moved duplicated flag check to  function<commit_after>package flags

import (
	"reflect"
	"unicode/utf8"
	"unsafe"
)

type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)

func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
	return &Group{
		ShortDescription: shortDescription,
		LongDescription:  longDescription,

		data: data,
	}
}

func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
	prio := 0
	var retopt *Option

	for _, opt := range g.options {
		if namematch != nil && namematch(opt, name) && prio < 4 {
			retopt = opt
			prio = 4
		}

		if name == opt.field.Name && prio < 3 {
			retopt = opt
			prio = 3
		}

		if name == opt.LongName && prio < 2 {
			retopt = opt
			prio = 2
		}

		if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
			retopt = opt
			prio = 1
		}
	}

	return retopt
}

func (g *Group) storeDefaults() {
	for _, option := range g.options {
		// First. empty out the value
		if len(option.Default) > 0 {
			option.clear()
		}

		for _, d := range option.Default {
			option.set(&d)
		}

		if !option.value.CanSet() {
			continue
		}

		option.defaultValue = reflect.ValueOf(option.value.Interface())
	}
}

func (g *Group) eachGroup(f func(*Group)) {
	f(g)

	for _, gg := range g.groups {
		gg.eachGroup(f)
	}
}

func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
	stype := realval.Type()

	if sfield != nil {
		if ok, err := handler(realval, sfield); err != nil {
			return err
		} else if ok {
			return nil
		}
	}

	for i := 0; i < stype.NumField(); i++ {
		field := stype.Field(i)

		// PkgName is set only for non-exported fields, which we ignore
		if field.PkgPath != "" {
			continue
		}

		mtag := newMultiTag(string(field.Tag))

		// Skip fields with the no-flag tag
		if mtag.Get("no-flag") != "" {
			continue
		}

		// Dive deep into structs or pointers to structs
		kind := field.Type.Kind()
		fld := realval.Field(i)

		if kind == reflect.Struct {
			if err := g.scanStruct(fld, &field, handler); err != nil {
				return err
			}
		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
			if fld.IsNil() {
				fld.Set(reflect.New(fld.Type().Elem()))
			}

			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
				return err
			}
		}

		longname := mtag.Get("long")
		shortname := mtag.Get("short")

		// Need at least either a short or long name
		if longname == "" && shortname == "" && mtag.Get("ini-name") == "" {
			continue
		}

		short := rune(0)
		rc := utf8.RuneCountInString(shortname)

		if rc > 1 {
			return newErrorf(ErrShortNameTooLong,
				"short names can only be 1 character long, not `%s'",
				shortname)

		} else if rc == 1 {
			short, _ = utf8.DecodeRuneInString(shortname)
		}

		description := mtag.Get("description")
		def := mtag.GetMany("default")
		optionalValue := mtag.GetMany("optional-value")
		valueName := mtag.Get("value-name")
		defaultMask := mtag.Get("default-mask")

		optional := (mtag.Get("optional") != "")
		required := (mtag.Get("required") != "")

		option := &Option{
			Description:      description,
			ShortName:        short,
			LongName:         longname,
			Default:          def,
			OptionalArgument: optional,
			OptionalValue:    optionalValue,
			Required:         required,
			ValueName:        valueName,
			DefaultMask:      defaultMask,

			field: field,
			value: realval.Field(i),
			tag:   mtag,
		}

		g.options = append(g.options, option)
	}

	return nil
}

func (g *Group) checkForDuplicateFlags() *Error {
	shortNames := make(map[rune]*Option)
	longNames := make(map[string]*Option)

	var duplicateError *Error = nil

	g.eachGroup(func(g *Group) {
		for _, option := range g.options {
			if option.LongName != "" {
				if otherOption, ok := longNames[option.LongName]; ok {
					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption)
					return
				}
				longNames[option.LongName] = option
			}
			if option.ShortName != 0 {
				if otherOption, ok := shortNames[option.ShortName]; ok {
					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption)
					return
				}
				shortNames[option.ShortName] = option
			}
		}
	})

	return duplicateError
}

func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
	mtag := newMultiTag(string(sfield.Tag))

	subgroup := mtag.Get("group")

	if len(subgroup) != 0 {
		ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr()))
		description := mtag.Get("description")

		if _, err := g.AddGroup(subgroup, description, ptrval.Interface()); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}

func (g *Group) scanType(handler scanHandler) error {
	// Get all the public fields in the data struct
	ptrval := reflect.ValueOf(g.data)

	if ptrval.Type().Kind() != reflect.Ptr {
		panic(ErrNotPointerToStruct)
	}

	stype := ptrval.Type().Elem()

	if stype.Kind() != reflect.Struct {
		panic(ErrNotPointerToStruct)
	}

	realval := reflect.Indirect(ptrval)

	if err := g.scanStruct(realval, nil, handler); err != nil {
		return err
	}

	if err := g.checkForDuplicateFlags(); err != nil {
		return err
	}

	return nil
}

func (g *Group) scan() error {
	return g.scanType(g.scanSubGroupHandler)
}

func (g *Group) groupByName(name string) *Group {
	if len(name) == 0 {
		return g
	}

	return g.Find(name)
}
<|endoftext|>