<commit_before>package api

import (
	"chain/api/appdb"
	"chain/api/asset"
	"chain/api/utxodb"
	"chain/database/pg"
	"chain/errors"
	"chain/net/http/httpjson"
)

// errorInfo contains a set of error codes to send to the user.
type errorInfo struct {
	HTTPStatus int    `json:"-"`
	ChainCode  string `json:"code"`
	Message    string `json:"message"`
}

var (
	// infoInternal holds the codes we use for an internal error.
	// It is defined here for easy reference.
	infoInternal = errorInfo{500, "CH000", "Chain API Error"}

	// Map error values to standard chain error codes.
	// Missing entries will map to infoInternal.
	// See chain.com/docs.
	errorInfoTab = map[error]errorInfo{
		pg.ErrUserInputNotFound:     errorInfo{404, "CH005", "Not found."},
		errNoAccessToResource:       errorInfo{404, "CH005", "Not found."},
		httpjson.ErrBadRequest:      errorInfo{400, "CH007", "Invalid request body"},
		errBadReqHeader:             errorInfo{400, "CH008", "Invalid request header"},
		appdb.ErrBadEmail:           errorInfo{400, "CH101", "Invalid email."},
		appdb.ErrBadPassword:        errorInfo{400, "CH102", "Invalid password."},
		appdb.ErrPasswordCheck:      errorInfo{400, "CH103", "Unable to verify password."},
		appdb.ErrNoUserForEmail:     errorInfo{400, "CH104", "No user corresponds to the provided email address."},
		asset.ErrBadAddr:            errorInfo{400, "CH300", "Invalid address"},
		appdb.ErrBadLabel:           errorInfo{400, "CH704", "Invalid label"},
		asset.ErrBadSigsRequired:    errorInfo{400, "CH712", "signatures_required must be at least 1."},
		asset.ErrBadKeySpec:         errorInfo{400, "CH713", "Invalid xpub."},
		asset.ErrTooFewKeys:         errorInfo{400, "CH715", "Cannot have more signatures required than keys."},
		appdb.ErrBadAccountKeyCount: errorInfo{400, "CH716", "Accounts must provide the correct number of keys for a manager node."},
		appdb.ErrPastExpires:        errorInfo{400, "CH720", "Expires, if set, must be in the future"},
		utxodb.ErrInsufficient:      errorInfo{400, "CH733", "Insufficient funds for tx"},
		utxodb.ErrReserved:          errorInfo{400, "CH743", "Some outputs are reserved; try again"},
		asset.ErrBadOutDest:         errorInfo{400, "CH744", "Invalid input sources or output destinations"},
		asset.ErrBadTx:              errorInfo{400, "CH755", "Invalid transaction template"},
		appdb.ErrBadAsset:           errorInfo{400, "CH761", "Invalid asset"},
		appdb.ErrBadProjectName:     errorInfo{400, "CH770", "Invalid project name."},
		appdb.ErrCannotDelete:       errorInfo{400, "CH901", "Cannot delete non-empty object"},
		appdb.ErrBadRole:            errorInfo{400, "CH800", "Member role must be \"developer\" or \"admin\"."},
		appdb.ErrAlreadyMember:      errorInfo{400, "CH801", "User is already a member of the project."},
		errNotAdmin:                 errorInfo{403, "CH781", "Admin privileges are required perform this action"},

		// Error codes imported from papi for convenient reference.
		// Please delete lines from this block when you add them
		// to the live code above or when you know they won't be used.
		//
		// ErrAPITryAgain     = errorInfo{500, "CH009", "Chain API Error, Try Again"}
		// ErrRateLimit       = errorInfo{429, "CH011", "Exceeded rate limit. Email enterprise@chain.com to learn about our production services."}
		//
		// ErrTxStatusUnknown = errorInfo{500, "CH203", "Transaction relayed, status unknown"}
		//
		// ErrBadNotifURL   = errorInfo{400, "CH400", "Invalid notification URL"}
		// ErrDupNotif      = errorInfo{400, "CH401", "New notification conflicts with an existing notification"}
		// ErrBadBlockChain = errorInfo{400, "CH403", "Invalid block chain"}
		// ErrBadNotifType  = errorInfo{400, "CH408", "Invalid notification type"}
		//
		// ErrMissingWallet       = errorInfo{404, "CH703", "Requested wallet could not be found"}
		// ErrMissingWallet400    = errorInfo{400, "CH703", "Requested wallet could not be found"}
		// ErrBadAppID            = errorInfo{400, "CH705", "Invalid application ID"}
		// ErrBadKeyRotate        = errorInfo{400, "CH706", "Old XPub is not in current wallet key rotation"}
		// ErrWalletOwnership     = errorInfo{400, "CH707", "Chain must provide fewer keys than required signatures"}
		// ErrZeroSigReq          = errorInfo{400, "CH708", "Signatures required must be at least one"}
		// ErrRequestedKeys       = errorInfo{400, "CH709", "Chain can only provide one key"}
		// ErrMissingBucket400    = errorInfo{400, "CH710", "Requested bucket could not be found"}
		// ErrMissingApp          = errorInfo{404, "CH711", "Requested application could not be found"}
		// ErrMissingReceiver     = errorInfo{404, "CH721", "Requested receiver could not be found"}
		// ErrMaxInputs           = errorInfo{400, "CH730", "Maximum number of inputs passed"}
		// ErrNoInputs            = errorInfo{400, "CH731", "No inputs provided"}
		// ErrNoOutputs           = errorInfo{400, "CH732", "No outputs provided"}
		//
		// ErrZeroInput           = errorInfo{400, "CH734", "Input amount must be greater than 0"}
		// ErrZeroOutput          = errorInfo{400, "CH735", "Output amount must be greater than 0"}
		// ErrSoloWallet          = errorInfo{400, "CH736", "Wallet input must be the only input"}
		// ErrBadOut              = errorInfo{400, "CH737", "Invalid output"}
		//
		// ErrFeePayer            = errorInfo{400, "CH739", "There must be exactly one fee payer"}
		// ErrMetadataHex         = errorInfo{400, "CH740", "Metadata must be hex encoded"}
		// ErrMetadataLen         = errorInfo{400, "CH741", "Metadata cannot be longer than 40 bytes"}
		// ErrTxTooBig            = errorInfo{400, "CH742", "Transaction byte size is too big"}
		//
		// ErrMetaAndOA           = errorInfo{400, "CH745", "Metadata cannot be added to open asset transactions"}
		//
		// ErrInvalidSig          = errorInfo{400, "CH751", "Signature was not valid for transaction"}
		// ErrNTplInput           = errorInfo{400, "CH752", "Transaction template has wrong number of inputs"}
		// ErrExtraSig            = errorInfo{400, "CH754", "Too many signatures"}
		//
		// ErrBadRedeem           = errorInfo{400, "CH756", "Redeem script is not a valid multisig script"}
		// ErrMissingAsset        = errorInfo{404, "CH760", "Requested asset could not be found"}
		//
		// ErrAssetOpRetTooBig    = errorInfo{400, "CH762", "Too many outputs and/or asset defintion too large"}
		// ErrAssetDefIDForbidden = errorInfo{400, "CH763", "Asset definition should not have asset IDs"}
		// ErrInvalidPolicy       = errorInfo{400, "CH772", "Invalid policy"}
		// ErrMissingApproval     = errorInfo{404, "CH773", "Requested approval could not be found"}
		// ErrBadApprovals        = errorInfo{400, "CH774", "Approval request cannot be satisfied"}
		// ErrMissingPolicy       = errorInfo{404, "CH775", "Requested policy could not be found"}
		//
		// ErrNoTxActivity        = errorInfo{404, "CH790", "Transaction details could not be found."}
	}
)

// errInfo returns the HTTP status code to use
// and a suitable response body describing err
// by consulting the global lookup table.
// If no entry is found, it returns infoInternal.
func errInfo(err error) (body interface{}, info errorInfo) {
	root := errors.Root(err)
	// Some types cannot be used as map keys, for example slices.
	// If an error's underlying type is one of these, don't panic.
	// Just treat it like any other missing entry.
	defer func() {
		if err := recover(); err != nil {
			info = infoInternal
			body = infoInternal
		}
	}()
	info, ok := errorInfoTab[root]
	if !ok {
		info = infoInternal
	}

	if s := errors.Detail(err); s != "" {
		return struct {
			errorInfo
			Detail string `json:"detail"`
		}{info, s}, info
	}

	return info, info
}
<commit_msg>api: remove list of papi errors in comments<commit_after>package api

import (
	"chain/api/appdb"
	"chain/api/asset"
	"chain/api/utxodb"
	"chain/database/pg"
	"chain/errors"
	"chain/net/http/httpjson"
)

// errorInfo contains a set of error codes to send to the user.
type errorInfo struct {
	HTTPStatus int    `json:"-"`
	ChainCode  string `json:"code"`
	Message    string `json:"message"`
}

var (
	// infoInternal holds the codes we use for an internal error.
	// It is defined here for easy reference.
	infoInternal = errorInfo{500, "CH000", "Chain API Error"}

	// Map error values to standard chain error codes.
	// Missing entries will map to infoInternal.
	// See chain.com/docs.
	errorInfoTab = map[error]errorInfo{
		pg.ErrUserInputNotFound:     errorInfo{404, "CH005", "Not found."},
		errNoAccessToResource:       errorInfo{404, "CH005", "Not found."},
		httpjson.ErrBadRequest:      errorInfo{400, "CH007", "Invalid request body"},
		errBadReqHeader:             errorInfo{400, "CH008", "Invalid request header"},
		appdb.ErrBadEmail:           errorInfo{400, "CH101", "Invalid email."},
		appdb.ErrBadPassword:        errorInfo{400, "CH102", "Invalid password."},
		appdb.ErrPasswordCheck:      errorInfo{400, "CH103", "Unable to verify password."},
		appdb.ErrNoUserForEmail:     errorInfo{400, "CH104", "No user corresponds to the provided email address."},
		asset.ErrBadAddr:            errorInfo{400, "CH300", "Invalid address"},
		appdb.ErrBadLabel:           errorInfo{400, "CH704", "Invalid label"},
		asset.ErrBadSigsRequired:    errorInfo{400, "CH712", "signatures_required must be at least 1."},
		asset.ErrBadKeySpec:         errorInfo{400, "CH713", "Invalid xpub."},
		asset.ErrTooFewKeys:         errorInfo{400, "CH715", "Cannot have more signatures required than keys."},
		appdb.ErrBadAccountKeyCount: errorInfo{400, "CH716", "Accounts must provide the correct number of keys for a manager node."},
		appdb.ErrPastExpires:        errorInfo{400, "CH720", "Expires, if set, must be in the future"},
		utxodb.ErrInsufficient:      errorInfo{400, "CH733", "Insufficient funds for tx"},
		utxodb.ErrReserved:          errorInfo{400, "CH743", "Some outputs are reserved; try again"},
		asset.ErrBadOutDest:         errorInfo{400, "CH744", "Invalid input sources or output destinations"},
		asset.ErrBadTx:              errorInfo{400, "CH755", "Invalid transaction template"},
		appdb.ErrBadAsset:           errorInfo{400, "CH761", "Invalid asset"},
		appdb.ErrBadProjectName:     errorInfo{400, "CH770", "Invalid project name."},
		appdb.ErrCannotDelete:       errorInfo{400, "CH901", "Cannot delete non-empty object"},
		appdb.ErrBadRole:            errorInfo{400, "CH800", "Member role must be \"developer\" or \"admin\"."},
		appdb.ErrAlreadyMember:      errorInfo{400, "CH801", "User is already a member of the project."},
		errNotAdmin:                 errorInfo{403, "CH781", "Admin privileges are required perform this action"},
	}
)

// errInfo returns the HTTP status code to use
// and a suitable response body describing err
// by consulting the global lookup table.
// If no entry is found, it returns infoInternal.
func errInfo(err error) (body interface{}, info errorInfo) {
	root := errors.Root(err)
	// Some types cannot be used as map keys, for example slices.
	// If an error's underlying type is one of these, don't panic.
	// Just treat it like any other missing entry.
	defer func() {
		if err := recover(); err != nil {
			info = infoInternal
			body = infoInternal
		}
	}()
	info, ok := errorInfoTab[root]
	if !ok {
		info = infoInternal
	}

	if s := errors.Detail(err); s != "" {
		return struct {
			errorInfo
			Detail string `json:"detail"`
		}{info, s}, info
	}

	return info, info
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"sync"

	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/node"
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

func coalesceErrors(local bool, errors map[string]error) error {
	if len(errors) == 0 {
		return nil
	}

	var errorMsg string
	if local {
		errorMsg += "The following instances failed to update state:\n"
	}

	for instName, err := range errors {
		if local {
			errorMsg += fmt.Sprintf(" - Instance: %s: %v\n", instName, err)
		} else {
			errorMsg += strings.TrimSpace(fmt.Sprintf("%v\n", err))
		}
	}

	return fmt.Errorf("%s", errorMsg)
}

// swagger:operation PUT /1.0/instances instances instances_put
//
// Bulk instance state update
//
// Changes the running state of all instances.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: body
//     name: state
//     description: State
//     required: false
//     schema:
//       $ref: "#/definitions/InstancesPut"
// responses:
//   "202":
//     $ref: "#/responses/Operation"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func instancesPut(d *Daemon, r *http.Request) response.Response {
	projectName := projectParam(r)

	// Don't mess with instances while in setup mode.
	<-d.waitReady.Done()

	c, err := instance.LoadNodeAll(d.State(), instancetype.Any)
	if err != nil {
		return response.BadRequest(err)
	}

	req := api.InstancesPut{}
	req.State = &api.InstanceStatePut{}
	req.State.Timeout = -1
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	action := shared.InstanceAction(req.State.Action)

	var names []string
	var instances []instance.Instance
	for _, inst := range c {
		if inst.Project().Name != projectName {
			continue
		}

		switch action {
		case shared.Freeze:
			if !inst.IsRunning() {
				continue
			}

		case shared.Restart:
			if !inst.IsRunning() {
				continue
			}

		case shared.Start:
			if inst.IsRunning() {
				continue
			}

		case shared.Stop:
			if !inst.IsRunning() {
				continue
			}

		case shared.Unfreeze:
			if inst.IsRunning() {
				continue
			}
		}

		instances = append(instances, inst)
		names = append(names, inst.Name())
	}

	// Determine operation type.
	opType, err := instanceActionToOptype(req.State.Action)
	if err != nil {
		return response.BadRequest(err)
	}

	// Batch the changes.
	do := func(op *operations.Operation) error {
		localAction := func(local bool) error {
			failures := map[string]error{}
			failuresLock := sync.Mutex{}
			wgAction := sync.WaitGroup{}

			for _, inst := range instances {
				wgAction.Add(1)
				go func(inst instance.Instance) {
					defer wgAction.Done()

					inst.SetOperation(op)
					err := doInstanceStatePut(inst, *req.State)
					if err != nil {
						failuresLock.Lock()
						failures[inst.Name()] = err
						failuresLock.Unlock()
					}
				}(inst)
			}

			wgAction.Wait()
			return coalesceErrors(local, failures)
		}

		// Only return the local data if asked by cluster member.
		if isClusterNotification(r) {
			return localAction(false)
		}

		// Check if clustered.
		clustered, err := cluster.Enabled(d.db.Node)
		if err != nil {
			return err
		}

		// If not clustered, return the local data.
		if !clustered {
			return localAction(true)
		}

		// Get all online nodes.
		var nodes []db.NodeInfo
		err = d.db.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
			var err error

			nodes, err = tx.GetNodes(ctx)
			if err != nil {
				return err
			}

			return nil
		})
		if err != nil {
			return err
		}

		// Get local address.
		localAddress, err := node.HTTPSAddress(d.db.Node)
		if err != nil {
			return err
		}

		// Record the results.
		failures := map[string]error{}
		failuresLock := sync.Mutex{}
		wgAction := sync.WaitGroup{}

		networkCert := d.endpoints.NetworkCert()
		for _, node := range nodes {
			wgAction.Add(1)
			go func(node db.NodeInfo) {
				defer wgAction.Done()

				// Special handling for the local member.
				if node.Address == localAddress {
					err := localAction(false)
					if err != nil {
						failuresLock.Lock()
						failures[node.Name] = err
						failuresLock.Unlock()
					}

					return
				}

				// Connect to the remote server.
				client, err := cluster.Connect(node.Address, networkCert, d.serverCert(), r, true)
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}

				client = client.UseProject(projectName)

				// Perform the action.
				op, err := client.UpdateInstances(req, "")
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}

				err = op.Wait()
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}
			}(node)
		}

		wgAction.Wait()
		return coalesceErrors(true, failures)
	}

	resources := map[string][]string{}
	resources["instances"] = names
	op, err := operations.OperationCreate(d.State(), projectName, operations.OperationClassTask, opType, resources, nil, do, nil, nil, r)
	if err != nil {
		return response.InternalError(err)
	}

	return operations.OperationResponse(op)
}
<commit_msg>lxd/instances/put: Use local cluster address for local cluster member identification in instancesPut<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"sync"

	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

func coalesceErrors(local bool, errors map[string]error) error {
	if len(errors) == 0 {
		return nil
	}

	var errorMsg string
	if local {
		errorMsg += "The following instances failed to update state:\n"
	}

	for instName, err := range errors {
		if local {
			errorMsg += fmt.Sprintf(" - Instance: %s: %v\n", instName, err)
		} else {
			errorMsg += strings.TrimSpace(fmt.Sprintf("%v\n", err))
		}
	}

	return fmt.Errorf("%s", errorMsg)
}

// swagger:operation PUT /1.0/instances instances instances_put
//
// Bulk instance state update
//
// Changes the running state of all instances.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: body
//     name: state
//     description: State
//     required: false
//     schema:
//       $ref: "#/definitions/InstancesPut"
// responses:
//   "202":
//     $ref: "#/responses/Operation"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func instancesPut(d *Daemon, r *http.Request) response.Response {
	projectName := projectParam(r)

	// Don't mess with instances while in setup mode.
	<-d.waitReady.Done()

	c, err := instance.LoadNodeAll(d.State(), instancetype.Any)
	if err != nil {
		return response.BadRequest(err)
	}

	req := api.InstancesPut{}
	req.State = &api.InstanceStatePut{}
	req.State.Timeout = -1
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	action := shared.InstanceAction(req.State.Action)

	var names []string
	var instances []instance.Instance
	for _, inst := range c {
		if inst.Project().Name != projectName {
			continue
		}

		switch action {
		case shared.Freeze:
			if !inst.IsRunning() {
				continue
			}

		case shared.Restart:
			if !inst.IsRunning() {
				continue
			}

		case shared.Start:
			if inst.IsRunning() {
				continue
			}

		case shared.Stop:
			if !inst.IsRunning() {
				continue
			}

		case shared.Unfreeze:
			if inst.IsRunning() {
				continue
			}
		}

		instances = append(instances, inst)
		names = append(names, inst.Name())
	}

	// Determine operation type.
	opType, err := instanceActionToOptype(req.State.Action)
	if err != nil {
		return response.BadRequest(err)
	}

	// Batch the changes.
	do := func(op *operations.Operation) error {
		localAction := func(local bool) error {
			failures := map[string]error{}
			failuresLock := sync.Mutex{}
			wgAction := sync.WaitGroup{}

			for _, inst := range instances {
				wgAction.Add(1)
				go func(inst instance.Instance) {
					defer wgAction.Done()

					inst.SetOperation(op)
					err := doInstanceStatePut(inst, *req.State)
					if err != nil {
						failuresLock.Lock()
						failures[inst.Name()] = err
						failuresLock.Unlock()
					}
				}(inst)
			}

			wgAction.Wait()
			return coalesceErrors(local, failures)
		}

		// Only return the local data if asked by cluster member.
		if isClusterNotification(r) {
			return localAction(false)
		}

		// Check if clustered.
		clustered, err := cluster.Enabled(d.db.Node)
		if err != nil {
			return err
		}

		// If not clustered, return the local data.
		if !clustered {
			return localAction(true)
		}

		// Get all online nodes.
		var nodes []db.NodeInfo
		err = d.db.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
			var err error

			nodes, err = tx.GetNodes(ctx)
			if err != nil {
				return err
			}

			return nil
		})
		if err != nil {
			return err
		}

		// Get local cluster address.
		localClusterAddress := d.State().LocalConfig.ClusterAddress()

		// Record the results.
		failures := map[string]error{}
		failuresLock := sync.Mutex{}
		wgAction := sync.WaitGroup{}

		networkCert := d.endpoints.NetworkCert()
		for _, node := range nodes {
			wgAction.Add(1)
			go func(node db.NodeInfo) {
				defer wgAction.Done()

				// Special handling for the local member.
				if node.Address == localClusterAddress {
					err := localAction(false)
					if err != nil {
						failuresLock.Lock()
						failures[node.Name] = err
						failuresLock.Unlock()
					}

					return
				}

				// Connect to the remote server.
				client, err := cluster.Connect(node.Address, networkCert, d.serverCert(), r, true)
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}

				client = client.UseProject(projectName)

				// Perform the action.
				op, err := client.UpdateInstances(req, "")
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}

				err = op.Wait()
				if err != nil {
					failuresLock.Lock()
					failures[node.Name] = err
					failuresLock.Unlock()
					return
				}
			}(node)
		}

		wgAction.Wait()
		return coalesceErrors(true, failures)
	}

	resources := map[string][]string{}
	resources["instances"] = names
	op, err := operations.OperationCreate(d.State(), projectName, operations.OperationClassTask, opType, resources, nil, do, nil, nil, r)
	if err != nil {
		return response.InternalError(err)
	}

	return operations.OperationResponse(op)
}
<|endoftext|>


<commit_before>// History: Oct 03 14 tcolar Creation

package main

import (
	"fmt"

	"github.com/tcolar/termbox-go"
)

func (e *Editor) Size() (int, int) {
	return termbox.Size()
}

func (e *Editor) FB(fg, bg Style) {
	e.Fg = fg
	e.Bg = bg
}

func (e *Editor) Char(x, y int, c rune) {
	termbox.SetCell(x, y, c, termbox.Attribute(e.Fg.uint16), termbox.Attribute(e.Bg.uint16))
}

func (e *Editor) Str(x, y int, s string) {
	for _, c := range s {
		e.Char(x, y, c)
		x++
	}
}

func (e *Editor) Strv(x, y int, s string) {
	for _, c := range s {
		e.Char(x, y, c)
		y++
	}
}

func (e *Editor) Fill(c rune, x1, y1, x2, y2 int) {
	if x1 > x2 {
		x1, x2 = x2, x1
	}
	if y1 > y2 {
		y1, y2 = y2, y1
	}
	for x := x1; x <= x2; x++ {
		for y := y1; y <= y2; y++ {
			e.Char(x, y, c)
		}
	}
}

// Print colors to terminal to try it.
func testTerm() {
	fmt.Printf("Standard Colors (16):\n Plain      : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[3%dm%d ", i, i)
	}
	fmt.Printf("\n Bold       : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[1;3%dm%d ", i, i)
	}
	fmt.Printf("\033[0m\n Underlined : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[4;3%dm%d ", i, i)
	}
	fmt.Println("\033[0m\n\nExtended Colors (256):")
	for i := 0; i != 256; i++ {
		fmt.Printf("\033[0;38;5;%dm%d ", i, i)
	}
	fmt.Println("\n\nAscii Chars: a A 6 ¼ Ø \nUnicode chars: \u0E5B  ಠﭛಠ")
}

func detectColors() int {
	// TBD
	return 256
}
<commit_msg>testerm colors in Hex format<commit_after>// History: Oct 03 14 tcolar Creation

package main

import (
	"fmt"

	"github.com/tcolar/termbox-go"
)

func (e *Editor) Size() (int, int) {
	return termbox.Size()
}

func (e *Editor) FB(fg, bg Style) {
	e.Fg = fg
	e.Bg = bg
}

func (e *Editor) Char(x, y int, c rune) {
	termbox.SetCell(x, y, c, termbox.Attribute(e.Fg.uint16), termbox.Attribute(e.Bg.uint16))
}

func (e *Editor) Str(x, y int, s string) {
	for _, c := range s {
		e.Char(x, y, c)
		x++
	}
}

func (e *Editor) Strv(x, y int, s string) {
	for _, c := range s {
		e.Char(x, y, c)
		y++
	}
}

func (e *Editor) Fill(c rune, x1, y1, x2, y2 int) {
	if x1 > x2 {
		x1, x2 = x2, x1
	}
	if y1 > y2 {
		y1, y2 = y2, y1
	}
	for x := x1; x <= x2; x++ {
		for y := y1; y <= y2; y++ {
			e.Char(x, y, c)
		}
	}
}

// Print colors to terminal to try it.
func testTerm() {
	fmt.Printf("Standard Colors (16):\n Plain      : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[3%dm%02X ", i, i)
	}
	fmt.Printf("\n Bold       : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[1;3%dm%02X ", i, i)
	}
	fmt.Printf("\033[0m\n Underlined : ")
	for i := 0; i != 16; i++ {
		fmt.Printf("\033[4;3%dm%02X ", i, i)
	}
	fmt.Println("\033[0m\n\nExtended Colors (256):")
	for i := 0; i != 256; i++ {
		fmt.Printf("\033[0;38;5;%dm%02X ", i, i)
	}
	fmt.Println("\n\nAscii Chars: a A 6 ¼ Ø \nUnicode chars: \u0E5B  ಠﭛಠ")
}

func detectColors() int {
	// TBD
	return 256
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/units"
)

// For 'btrfs' storage backend.
func btrfsSubVolumeCreate(subvol string) error {
	parentDestPath := filepath.Dir(subvol)
	if !shared.PathExists(parentDestPath) {
		err := os.MkdirAll(parentDestPath, 0711)
		if err != nil {
			return err
		}
	}

	_, err := shared.RunCommand(
		"btrfs",
		"subvolume",
		"create",
		subvol)
	if err != nil {
		return err
	}

	return nil
}

func btrfsSubVolumeQGroup(subvol string) (string, error) {
	output, err := shared.RunCommand(
		"btrfs",
		"qgroup",
		"show",
		"-e",
		"-f",
		subvol)

	if err != nil {
		return "", fmt.Errorf("Quotas disabled on filesystem")
	}

	var qgroup string
	for _, line := range strings.Split(output, "\n") {
		if line == "" || strings.HasPrefix(line, "qgroupid") || strings.HasPrefix(line, "---") {
			continue
		}

		fields := strings.Fields(line)
		if len(fields) != 4 {
			continue
		}

		qgroup = fields[0]
	}

	if qgroup == "" {
		return "", fmt.Errorf("Unable to find quota group")
	}

	return qgroup, nil
}

func btrfsSubVolumeDelete(subvol string) error {
	// Attempt (but don't fail on) to delete any qgroup on the subvolume
	qgroup, err := btrfsSubVolumeQGroup(subvol)
	if err == nil {
		shared.RunCommand(
			"btrfs",
			"qgroup",
			"destroy",
			qgroup,
			subvol)
	}

	// Attempt to make the subvolume writable
	shared.RunCommand("btrfs", "property", "set", subvol, "ro", "false")

	// Delete the subvolume itself
	_, err = shared.RunCommand(
		"btrfs",
		"subvolume",
		"delete",
		subvol)

	return err
}

func btrfsSubVolumesDelete(subvol string) error {
	// Delete subsubvols.
	subsubvols, err := storageDrivers.BTRFSSubVolumesGet(subvol)
	if err != nil {
		return err
	}
	sort.Sort(sort.Reverse(sort.StringSlice(subsubvols)))

	for _, subsubvol := range subsubvols {
		err := btrfsSubVolumeDelete(path.Join(subvol, subsubvol))
		if err != nil {
			return err
		}
	}

	// Delete the subvol itself
	err = btrfsSubVolumeDelete(subvol)
	if err != nil {
		return err
	}

	return nil
}

func btrfsSnapshot(s *state.State, source string, dest string, readonly bool) error {
	var output string
	var err error
	if readonly && !s.OS.RunningInUserNS {
		output, err = shared.RunCommand(
			"btrfs",
			"subvolume",
			"snapshot",
			"-r",
			source,
			dest)
	} else {
		output, err = shared.RunCommand(
			"btrfs",
			"subvolume",
			"snapshot",
			source,
			dest)
	}
	if err != nil {
		return fmt.Errorf(
			"subvolume snapshot failed, source=%s, dest=%s, output=%s",
			source,
			dest,
			output,
		)
	}

	return err
}

// For 'lvm' storage backend.
func lvmLVRename(vgName string, oldName string, newName string) error {
	_, err := shared.TryRunCommand("lvrename", vgName, oldName, newName)
	if err != nil {
		return fmt.Errorf("could not rename volume group from \"%s\" to \"%s\": %v", oldName, newName, err)
	}

	return nil
}

func lvmLVExists(lvName string) (bool, error) {
	_, err := shared.RunCommand("lvs", "--noheadings", "-o", "lv_attr", lvName)
	if err != nil {
		runErr, ok := err.(shared.RunError)
		if ok {
			exitError, ok := runErr.Err.(*exec.ExitError)
			if ok {
				if exitError.ExitCode() == 5 {
					// logical volume not found
					return false, nil
				}
			}
		}

		return false, fmt.Errorf("error checking for logical volume \"%s\"", lvName)
	}

	return true, nil
}

func lvmVGActivate(lvmVolumePath string) error {
	_, err := shared.TryRunCommand("vgchange", "-ay", lvmVolumePath)
	if err != nil {
		return fmt.Errorf("could not activate volume group \"%s\": %v", lvmVolumePath, err)
	}

	return nil
}

func lvmNameToLVName(containerName string) string {
	lvName := strings.Replace(containerName, "-", "--", -1)
	return strings.Replace(lvName, shared.SnapshotDelimiter, "-", -1)
}

func lvmDevPath(projectName, lvmPool string, volumeType string, lvmVolume string) string {
	lvmVolume = project.Instance(projectName, lvmVolume)
	if volumeType == "" {
		return fmt.Sprintf("/dev/%s/%s", lvmPool, lvmVolume)
	}

	return fmt.Sprintf("/dev/%s/%s_%s", lvmPool, volumeType, lvmVolume)
}

func lvmGetLVSize(lvPath string) (string, error) {
	msg, err := shared.TryRunCommand("lvs", "--noheadings", "-o", "size", "--nosuffix", "--units", "b", lvPath)
	if err != nil {
		return "", fmt.Errorf("failed to retrieve size of logical volume: %s: %s", string(msg), err)
	}

	sizeString := string(msg)
	sizeString = strings.TrimSpace(sizeString)
	size, err := strconv.ParseInt(sizeString, 10, 64)
	if err != nil {
		return "", err
	}

	detectedSize := units.GetByteSizeString(size, 0)

	return detectedSize, nil
}

// volumeFillDefault fills default settings into a volume config.
// Deprecated. Please use FillInstanceConfig() on the storage pool.
func volumeFillDefault(config map[string]string, parentPool *api.StoragePool) error {
	if parentPool.Driver == "lvm" || parentPool.Driver == "ceph" {
		if config["block.filesystem"] == "" {
			config["block.filesystem"] = parentPool.Config["volume.block.filesystem"]
		}
		if config["block.filesystem"] == "" {
			// Unchangeable volume property: Set unconditionally.
			config["block.filesystem"] = storageDrivers.DefaultFilesystem
		}

		if config["block.mount_options"] == "" {
			config["block.mount_options"] = parentPool.Config["volume.block.mount_options"]
		}
		if config["block.mount_options"] == "" {
			// Unchangeable volume property: Set unconditionally.
			config["block.mount_options"] = "discard"
		}
	}

	return nil
}

// containerMountPoint returns the mountpoint of the given container.
// ${LXD_DIR}/storage-pools/<pool>/containers/[<project_name>_]<container_name>
// Deprecated.
func containerMountPoint(projectName string, poolName string, containerName string) string {
	return shared.VarPath("storage-pools", poolName, "containers", project.Instance(projectName, containerName))
}
<commit_msg>lxd/patches_utils: Use consistent units<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	storageDrivers "github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/units"
)

// For 'btrfs' storage backend.
func btrfsSubVolumeCreate(subvol string) error {
	parentDestPath := filepath.Dir(subvol)
	if !shared.PathExists(parentDestPath) {
		err := os.MkdirAll(parentDestPath, 0711)
		if err != nil {
			return err
		}
	}

	_, err := shared.RunCommand(
		"btrfs",
		"subvolume",
		"create",
		subvol)
	if err != nil {
		return err
	}

	return nil
}

func btrfsSubVolumeQGroup(subvol string) (string, error) {
	output, err := shared.RunCommand(
		"btrfs",
		"qgroup",
		"show",
		"-e",
		"-f",
		subvol)

	if err != nil {
		return "", fmt.Errorf("Quotas disabled on filesystem")
	}

	var qgroup string
	for _, line := range strings.Split(output, "\n") {
		if line == "" || strings.HasPrefix(line, "qgroupid") || strings.HasPrefix(line, "---") {
			continue
		}

		fields := strings.Fields(line)
		if len(fields) != 4 {
			continue
		}

		qgroup = fields[0]
	}

	if qgroup == "" {
		return "", fmt.Errorf("Unable to find quota group")
	}

	return qgroup, nil
}

func btrfsSubVolumeDelete(subvol string) error {
	// Attempt (but don't fail on) to delete any qgroup on the subvolume
	qgroup, err := btrfsSubVolumeQGroup(subvol)
	if err == nil {
		shared.RunCommand(
			"btrfs",
			"qgroup",
			"destroy",
			qgroup,
			subvol)
	}

	// Attempt to make the subvolume writable
	shared.RunCommand("btrfs", "property", "set", subvol, "ro", "false")

	// Delete the subvolume itself
	_, err = shared.RunCommand(
		"btrfs",
		"subvolume",
		"delete",
		subvol)

	return err
}

func btrfsSubVolumesDelete(subvol string) error {
	// Delete subsubvols.
	subsubvols, err := storageDrivers.BTRFSSubVolumesGet(subvol)
	if err != nil {
		return err
	}
	sort.Sort(sort.Reverse(sort.StringSlice(subsubvols)))

	for _, subsubvol := range subsubvols {
		err := btrfsSubVolumeDelete(path.Join(subvol, subsubvol))
		if err != nil {
			return err
		}
	}

	// Delete the subvol itself
	err = btrfsSubVolumeDelete(subvol)
	if err != nil {
		return err
	}

	return nil
}

func btrfsSnapshot(s *state.State, source string, dest string, readonly bool) error {
	var output string
	var err error
	if readonly && !s.OS.RunningInUserNS {
		output, err = shared.RunCommand(
			"btrfs",
			"subvolume",
			"snapshot",
			"-r",
			source,
			dest)
	} else {
		output, err = shared.RunCommand(
			"btrfs",
			"subvolume",
			"snapshot",
			source,
			dest)
	}
	if err != nil {
		return fmt.Errorf(
			"subvolume snapshot failed, source=%s, dest=%s, output=%s",
			source,
			dest,
			output,
		)
	}

	return err
}

// For 'lvm' storage backend.
func lvmLVRename(vgName string, oldName string, newName string) error {
	_, err := shared.TryRunCommand("lvrename", vgName, oldName, newName)
	if err != nil {
		return fmt.Errorf("could not rename volume group from \"%s\" to \"%s\": %v", oldName, newName, err)
	}

	return nil
}

func lvmLVExists(lvName string) (bool, error) {
	_, err := shared.RunCommand("lvs", "--noheadings", "-o", "lv_attr", lvName)
	if err != nil {
		runErr, ok := err.(shared.RunError)
		if ok {
			exitError, ok := runErr.Err.(*exec.ExitError)
			if ok {
				if exitError.ExitCode() == 5 {
					// logical volume not found
					return false, nil
				}
			}
		}

		return false, fmt.Errorf("error checking for logical volume \"%s\"", lvName)
	}

	return true, nil
}

func lvmVGActivate(lvmVolumePath string) error {
	_, err := shared.TryRunCommand("vgchange", "-ay", lvmVolumePath)
	if err != nil {
		return fmt.Errorf("could not activate volume group \"%s\": %v", lvmVolumePath, err)
	}

	return nil
}

func lvmNameToLVName(containerName string) string {
	lvName := strings.Replace(containerName, "-", "--", -1)
	return strings.Replace(lvName, shared.SnapshotDelimiter, "-", -1)
}

func lvmDevPath(projectName, lvmPool string, volumeType string, lvmVolume string) string {
	lvmVolume = project.Instance(projectName, lvmVolume)
	if volumeType == "" {
		return fmt.Sprintf("/dev/%s/%s", lvmPool, lvmVolume)
	}

	return fmt.Sprintf("/dev/%s/%s_%s", lvmPool, volumeType, lvmVolume)
}

func lvmGetLVSize(lvPath string) (string, error) {
	msg, err := shared.TryRunCommand("lvs", "--noheadings", "-o", "size", "--nosuffix", "--units", "b", lvPath)
	if err != nil {
		return "", fmt.Errorf("failed to retrieve size of logical volume: %s: %s", string(msg), err)
	}

	sizeString := string(msg)
	sizeString = strings.TrimSpace(sizeString)
	size, err := strconv.ParseInt(sizeString, 10, 64)
	if err != nil {
		return "", err
	}

	detectedSize := units.GetByteSizeStringIEC(size, 0)

	return detectedSize, nil
}

// volumeFillDefault fills default settings into a volume config.
// Deprecated. Please use FillInstanceConfig() on the storage pool.
func volumeFillDefault(config map[string]string, parentPool *api.StoragePool) error {
	if parentPool.Driver == "lvm" || parentPool.Driver == "ceph" {
		if config["block.filesystem"] == "" {
			config["block.filesystem"] = parentPool.Config["volume.block.filesystem"]
		}
		if config["block.filesystem"] == "" {
			// Unchangeable volume property: Set unconditionally.
			config["block.filesystem"] = storageDrivers.DefaultFilesystem
		}

		if config["block.mount_options"] == "" {
			config["block.mount_options"] = parentPool.Config["volume.block.mount_options"]
		}
		if config["block.mount_options"] == "" {
			// Unchangeable volume property: Set unconditionally.
			config["block.mount_options"] = "discard"
		}
	}

	return nil
}

// containerMountPoint returns the mountpoint of the given container.
// ${LXD_DIR}/storage-pools/<pool>/containers/[<project_name>_]<container_name>
// Deprecated.
func containerMountPoint(projectName string, poolName string, containerName string) string {
	return shared.VarPath("storage-pools", poolName, "containers", project.Instance(projectName, containerName))
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/mux"

	"github.com/hoffie/larasync/repository"
)

// Server represents our http environment.
type Server struct {
	adminPubkey   [PubkeySize]byte
	router        *mux.Router
	maxRequestAge time.Duration
	http          *http.Server
	rm            *repository.Manager
}

const (
	// DefaultPort specifies the server's default TCP port
	DefaultPort = 14124
)

// New returns a new Server.
func New(adminPubkey [PubkeySize]byte, maxRequestAge time.Duration, rm *repository.Manager) *Server {
	serveMux := http.NewServeMux()
	s := Server{
		adminPubkey:   adminPubkey,
		maxRequestAge: maxRequestAge,
		rm:            rm,
		router:        mux.NewRouter(),
		http: &http.Server{
			Addr:    fmt.Sprintf(":%d", DefaultPort),
			Handler: serveMux,
		},
	}
	s.setupRoutes()
	serveMux.Handle("/", s.router)
	return &s
}

func jsonHeader(rw http.ResponseWriter) {
	rw.Header().Set("Content-Type", "application/json")
}

// setupRoutes is responsible for registering API endpoints.
func (s *Server) setupRoutes() {
	s.router.HandleFunc("/repositories",
		s.requireAdminAuth(s.repositoryList)).Methods("GET")
	s.router.HandleFunc("/repositories/{repository}",
		s.requireAdminAuth(s.repositoryCreate)).Methods("PUT")
	s.router.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte("larasync\n"))
	})
}

// requireAdminAuth wraps a HandlerFunc and only calls it if the request has a
// valid admin auth header
func (s *Server) requireAdminAuth(f http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, req *http.Request) {
		if !ValidateRequest(req, s.adminPubkey, s.maxRequestAge) {
			http.Error(rw, "Unauthorized", http.StatusUnauthorized)
			return
		}
		f(rw, req)
	}
}

// ListenAndServe starts serving requests on the default port.
func (s *Server) ListenAndServe() error {
	return s.http.ListenAndServe()
}
<commit_msg>[api: server] Added function which authorizes signatures of requests to a repository against the stored public key.<commit_after>package api

import (
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/gorilla/mux"

	"github.com/hoffie/larasync/repository"
)

// Server represents our http environment.
type Server struct {
	adminPubkey   [PubkeySize]byte
	router        *mux.Router
	maxRequestAge time.Duration
	http          *http.Server
	rm            *repository.Manager
}

const (
	// DefaultPort specifies the server's default TCP port
	DefaultPort = 14124
)

// New returns a new Server.
func New(adminPubkey [PubkeySize]byte, maxRequestAge time.Duration, rm *repository.Manager) *Server {
	serveMux := http.NewServeMux()
	s := Server{
		adminPubkey:   adminPubkey,
		maxRequestAge: maxRequestAge,
		rm:            rm,
		router:        mux.NewRouter(),
		http: &http.Server{
			Addr:    fmt.Sprintf(":%d", DefaultPort),
			Handler: serveMux,
		},
	}
	s.setupRoutes()
	serveMux.Handle("/", s.router)
	return &s
}

func jsonHeader(rw http.ResponseWriter) {
	rw.Header().Set("Content-Type", "application/json")
}

// setupRoutes is responsible for registering API endpoints.
func (s *Server) setupRoutes() {
	s.router.HandleFunc("/repositories",
		s.requireAdminAuth(s.repositoryList)).Methods("GET")
	s.router.HandleFunc("/repositories/{repository}",
		s.requireAdminAuth(s.repositoryCreate)).Methods("PUT")
	s.router.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte("larasync\n"))
	})
}

// requireAdminAuth wraps a HandlerFunc and only calls it if the request has a
// valid admin auth header
func (s *Server) requireAdminAuth(f http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, req *http.Request) {
		if !ValidateRequest(req, s.adminPubkey, s.maxRequestAge) {
			http.Error(rw, "Unauthorized", http.StatusUnauthorized)
			return
		}
		f(rw, req)
	}
}

// requireAuth wraps a handlerFunc and only calls it if the request is
// authenticated
func (s *Server) requireRepositoryAuth(f http.HandlerFunc) http.HandlerFunc {
	return func(rw http.ResponseWriter, req *http.Request) {
		vars := mux.Vars(req)
		repositoryName := vars["repository"]
		repository, err := s.rm.Open(repositoryName)
		if err != nil {
			if os.IsNotExist(err) {
				http.Error(rw, "Repository not found", http.StatusNotFound)
			} else {
				http.Error(rw, "Internal Error", http.StatusInternalServerError)
			}
			return
		}

		var pubKeyArray [PubkeySize]byte
		pubKey, err := repository.GetAuthPubkey()
		if err != nil {
			http.Error(rw, "Internal Error", http.StatusInternalServerError)
		}

		copy(pubKeyArray[0:PubkeySize], pubKey[:PubkeySize])
		// TODO: Find if there is a better way for this.

		if !ValidateRequest(req, pubKeyArray, s.maxRequestAge) {
			http.Error(rw, "Unauthorized", http.StatusUnauthorized)
			return
		}

		f(rw, req)
	}
}

// ListenAndServe starts serving requests on the default port.
func (s *Server) ListenAndServe() error {
	return s.http.ListenAndServe()
}
<|endoftext|>


<commit_before>// Package host is an implementation of the host module, and is responsible for
// participating in the storage ecosystem, turning available disk space an
// internet bandwidth into profit for the user.
package host

// TODO: what happens if the renter submits the revision early, before the
// final revision. Will the host mark the contract as complete?

// TODO: Host and renter are reporting errors where the renter is not adding
// enough fees to the file contract.

// TODO: Test the safety of the builder, it should be okay to have multiple
// builders open for up to 600 seconds, which means multiple blocks could be
// received in that time period. Should also check what happens if a prent gets
// confirmed on the blockchain before the builder is finished.

// TODO: Double check that any network connection has a finite deadline -
// handling action items properly requires that the locks held on the
// obligations eventually be released. There's also some more advanced
// implementation that needs to happen with the storage obligation locks to
// make sure that someone who wants a lock is able to get it eventually.

// TODO: Add contract compensation from form contract to the storage obligation
// financial metrics, and to the host's tracking.

// TODO: merge the network interfaces stuff, don't forget to include the
// 'announced' variable as one of the outputs.

// TODO: 'announced' doesn't tell you if the announcement made it to the
// blockchain.

// TODO: Need to make sure that the revision exchange for the renter and the
// host is being handled correctly. For the host, it's not so difficult. The
// host need only send the most recent revision every time. But, the host
// should not sign a revision unless the renter has explicitly signed such that
// the 'WholeTransaction' fields cover only the revision and that the
// signatures for the revision don't depend on anything else. The renter needs
// to verify the same when checking on a file contract revision from the host.
// If the host has submitted a file contract revision where the signatures have
// signed the whole file contract, there is an issue.

// TODO: there is a mistake in the file contract revision rpc, the host, if it
// does not have the right file contract id, should be returning an error there
// to the renter (and not just to it's calling function without informing the
// renter what's up).

// TODO: Need to make sure that the correct height is being used when adding
// sectors to the storage manager - in some places right now WindowStart is
// being used but really it's WindowEnd that should be in use.

// TODO: The host needs some way to blacklist file contracts that are being
// abusive by repeatedly getting free download batches.

// TODO: clean up all of the magic numbers in the host.

// TODO: revamp the finances for the storage obligations.

// TODO: host_test.go has commented out tests.

// TODO: network_test.go has commented out tests.

// TODO: persist_test.go has commented out tests.

// TODO: update_test.go has commented out tests.

import (
	"errors"
	"fmt"
	"net"
	"path/filepath"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/host/storagemanager"
	"github.com/NebulousLabs/Sia/persist"
	siasync "github.com/NebulousLabs/Sia/sync"
	"github.com/NebulousLabs/Sia/types"
)

const (
	// Names of the various persistent files in the host.
	dbFilename   = modules.HostDir + ".db"
	logFile      = modules.HostDir + ".log"
	settingsFile = modules.HostDir + ".json"
)

var (
	// dbMetadata is a header that gets put into the database to identify a
	// version and indicate that the database holds host information.
	dbMetadata = persist.Metadata{
		Header:  "Sia Host DB",
		Version: "0.5.2",
	}

	// persistMetadata is the header that gets written to the persist file, and is
	// used to recognize other persist files.
	persistMetadata = persist.Metadata{
		Header:  "Sia Host",
		Version: "0.5",
	}

	// errHostClosed gets returned when a call is rejected due to the host
	// having been closed.
	errHostClosed = errors.New("call is disabled because the host is closed")

	// Nil dependency errors.
	errNilCS     = errors.New("host cannot use a nil state")
	errNilTpool  = errors.New("host cannot use a nil transaction pool")
	errNilWallet = errors.New("host cannot use a nil wallet")
)

// A Host contains all the fields necessary for storing files for clients and
// performing the storage proofs on the received files.
type Host struct {
	// RPC Metrics - atomic variables need to be placed at the top to preserve
	// compatibility with 32bit systems.
	atomicDownloadCalls       uint64
	atomicErroredCalls        uint64
	atomicFormContractCalls   uint64
	atomicRenewCalls          uint64
	atomicReviseCalls         uint64
	atomicRecentRevisionCalls uint64
	atomicSettingsCalls       uint64
	atomicUnrecognizedCalls   uint64

	// Error management. There are a few different types of errors returned by
	// the host. These errors intentionally not persistent, so that the logging
	// limits of each error type will be reset each time the host is reset.
	atomicCommunicationErrors uint64
	atomicConnectionErrors    uint64
	atomicConsensusErrors     uint64
	atomicInternalErrors      uint64
	atomicNormalErrors        uint64

	// Dependencies.
	cs     modules.ConsensusSet
	tpool  modules.TransactionPool
	wallet modules.Wallet
	dependencies
	modules.StorageManager

	// Consensus Tracking.
	blockHeight  types.BlockHeight
	recentChange modules.ConsensusChangeID

	// Host Identity
	//
	// The revision number keeps track of the current revision number on the
	// host external settingse
	//
	// The auto address is the address that is fetched automatically by the
	// host. The host will ignore the automatic address if settings.NetAddress
	// has been set by the user. If settings.NetAddress is blank, then the host
	// will track its own ip address and make an announcement on the blockchain
	// every time that the address changes.
	//
	// The announced bool indicates whether the host remembers having a
	// successful announcement with the current address.
	announced        bool
	autoAddress      modules.NetAddress
	financialMetrics modules.HostFinancialMetrics
	publicKey        types.SiaPublicKey
	revisionNumber   uint64
	secretKey        crypto.SecretKey
	settings         modules.HostInternalSettings
	unlockHash       types.UnlockHash // A wallet address that can receive coins.

	// A map of storage obligations that are currently being modified. Locks on
	// storage obligations can be long-running, and each storage obligation can
	// be locked separately.
	lockedStorageObligations map[types.FileContractID]*siasync.TryMutex

	// Utilities.
	db         *persist.BoltDatabase
	listener   net.Listener
	log        *persist.Logger
	mu         *siasync.RWMutex
	persistDir string
	port       string
	tg         siasync.ThreadGroup
}

// checkUnlockHash will check that the host has an unlock hash. If the host
// does not have an unlock hash, an attempt will be made to get an unlock hash
// from the wallet. That may fail due to the wallet being locked, in which case
// an error is returned.
func (h *Host) checkUnlockHash() error {
	if h.unlockHash == (types.UnlockHash{}) {
		uc, err := h.wallet.NextAddress()
		if err != nil {
			return err
		}

		// Set the unlock hash and save the host. Saving is important, because
		// the host will be using this unlock hash to establish identity, and
		// losing it will mean silently losing part of the host identity.
		h.unlockHash = uc.UnlockHash()
		err = h.save()
		if err != nil {
			return err
		}
	}
	return nil
}

// newHost returns an initialized Host, taking a set of dependencies as input.
// By making the dependencies an argument of the 'new' call, the host can be
// mocked such that the dependencies can return unexpected errors or unique
// behaviors during testing, enabling easier testing of the failure modes of
// the Host.
func newHost(dependencies dependencies, cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, listenerAddress string, persistDir string) (*Host, error) {
	// Check that all the dependencies were provided.
	if cs == nil {
		return nil, errNilCS
	}
	if tpool == nil {
		return nil, errNilTpool
	}
	if wallet == nil {
		return nil, errNilWallet
	}

	// Create the host object.
	h := &Host{
		cs:           cs,
		tpool:        tpool,
		wallet:       wallet,
		dependencies: dependencies,

		lockedStorageObligations: make(map[types.FileContractID]*siasync.TryMutex),

		mu:         siasync.New(modules.SafeMutexDelay, 2),
		persistDir: persistDir,
	}

	// Call stop in the event of a partial startup.
	var err error
	defer func() {
		if err != nil {
			err = composeErrors(h.tg.Stop(), err)
		}
	}()

	// Create the perist directory if it does not yet exist.
	err = dependencies.mkdirAll(h.persistDir, 0700)
	if err != nil {
		return nil, err
	}

	// Initialize the logger, and set up the stop call that will close the
	// logger.
	h.log, err = dependencies.newLogger(filepath.Join(h.persistDir, logFile))
	if err != nil {
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.log.Close()
		if err != nil {
			// State of the logger is uncertain, a Println will have to
			// suffice.
			fmt.Println("Error when closing the logger:", err)
		}
	})

	// Add the storage manager to the host, and set up the stop call that will
	// close the storage manager.
	h.StorageManager, err = storagemanager.New(filepath.Join(persistDir, "storagemanager"))
	if err != nil {
		h.log.Println("Could not open the storage manager:", err)
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.StorageManager.Close()
		if err != nil {
			h.log.Println("Could not close storage manager:", err)
		}
	})

	// After opening the database, it must be initialized. Most commonly,
	// nothing happens. But for new databases, a set of buckets must be
	// created. Initialization is also a good time to run sanity checks.
	err = h.initDB()
	if err != nil {
		h.log.Println("Could not initalize database:", err)
		return nil, err
	}

	// Load the prior persistence structures, and configure the host to save
	// before shutting down.
	err = h.load()
	if err != nil {
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.saveSync()
		if err != nil {
			h.log.Println("Could not save host upon shutdown:", err)
		}
	})

	// Initialize the networking.
	err = h.initNetworking(listenerAddress)
	if err != nil {
		h.log.Println("Could not initialize host networking:", err)
		return nil, err
	}
	return h, nil
}

// New returns an initialized Host.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, address string, persistDir string) (*Host, error) {
	return newHost(productionDependencies{}, cs, tpool, wallet, address, persistDir)
}

// Close shuts down the host.
func (h *Host) Close() error {
	return h.tg.Stop()
}

// ExternalSettings returns the hosts external settings. These values cannot be
// set by the user (host is configured through InternalSettings), and are the
// values that get displayed to other hosts on the network.
func (h *Host) ExternalSettings() modules.HostExternalSettings {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		build.Critical("Call to ExternalSettings after close")
	}
	defer h.tg.Done()
	return h.externalSettings()
}

// FinancialMetrics returns information about the financial commitments,
// rewards, and activities of the host.
func (h *Host) FinancialMetrics() modules.HostFinancialMetrics {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		build.Critical("Call to FinancialMetrics after close")
	}
	defer h.tg.Done()
	return h.financialMetrics
}

// SetInternalSettings updates the host's internal HostInternalSettings object.
func (h *Host) SetInternalSettings(settings modules.HostInternalSettings) error {
	lockID := h.mu.Lock()
	defer h.mu.Unlock(lockID)
	err := h.tg.Add()
	if err != nil {
		return err
	}
	defer h.tg.Done()

	// The host should not be accepting file contracts if it does not have an
	// unlock hash.
	if settings.AcceptingContracts {
		err := h.checkUnlockHash()
		if err != nil {
			return errors.New("internal settings not updated, no unlock hash: " + err.Error())
		}
	}

	if settings.NetAddress != "" {
		err := settings.NetAddress.IsValid()
		if err != nil {
			return errors.New("internal settings not updated, invalid NetAddress: " + err.Error())
		}
	}

	// Check if the net address for the host has changed. If it has, and it's
	// not equal to the auto address, then the host is going to need to make
	// another blockchain announcement.
	if h.settings.NetAddress != settings.NetAddress && settings.NetAddress != h.autoAddress {
		h.announced = false
	}

	h.settings = settings
	h.revisionNumber++

	err = h.saveSync()
	if err != nil {
		return errors.New("internal settings updated, but failed saving to disk: " + err.Error())
	}
	return nil
}

// InternalSettings returns the settings of a host.
func (h *Host) InternalSettings() modules.HostInternalSettings {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		build.Critical("call to InternalSettings after close")
	}
	defer h.tg.Done()
	return h.settings
}
<commit_msg>saveSync when getting address<commit_after>// Package host is an implementation of the host module, and is responsible for
// participating in the storage ecosystem, turning available disk space an
// internet bandwidth into profit for the user.
package host

// TODO: what happens if the renter submits the revision early, before the
// final revision. Will the host mark the contract as complete?

// TODO: Host and renter are reporting errors where the renter is not adding
// enough fees to the file contract.

// TODO: Test the safety of the builder, it should be okay to have multiple
// builders open for up to 600 seconds, which means multiple blocks could be
// received in that time period. Should also check what happens if a prent gets
// confirmed on the blockchain before the builder is finished.

// TODO: Double check that any network connection has a finite deadline -
// handling action items properly requires that the locks held on the
// obligations eventually be released. There's also some more advanced
// implementation that needs to happen with the storage obligation locks to
// make sure that someone who wants a lock is able to get it eventually.

// TODO: Add contract compensation from form contract to the storage obligation
// financial metrics, and to the host's tracking.

// TODO: merge the network interfaces stuff, don't forget to include the
// 'announced' variable as one of the outputs.

// TODO: 'announced' doesn't tell you if the announcement made it to the
// blockchain.

// TODO: Need to make sure that the revision exchange for the renter and the
// host is being handled correctly. For the host, it's not so difficult. The
// host need only send the most recent revision every time. But, the host
// should not sign a revision unless the renter has explicitly signed such that
// the 'WholeTransaction' fields cover only the revision and that the
// signatures for the revision don't depend on anything else. The renter needs
// to verify the same when checking on a file contract revision from the host.
// If the host has submitted a file contract revision where the signatures have
// signed the whole file contract, there is an issue.

// TODO: there is a mistake in the file contract revision rpc, the host, if it
// does not have the right file contract id, should be returning an error there
// to the renter (and not just to it's calling function without informing the
// renter what's up).

// TODO: Need to make sure that the correct height is being used when adding
// sectors to the storage manager - in some places right now WindowStart is
// being used but really it's WindowEnd that should be in use.

// TODO: The host needs some way to blacklist file contracts that are being
// abusive by repeatedly getting free download batches.

// TODO: clean up all of the magic numbers in the host.

// TODO: revamp the finances for the storage obligations.

// TODO: host_test.go has commented out tests.

// TODO: network_test.go has commented out tests.

// TODO: persist_test.go has commented out tests.

// TODO: update_test.go has commented out tests.

import (
	"errors"
	"fmt"
	"net"
	"path/filepath"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/host/storagemanager"
	"github.com/NebulousLabs/Sia/persist"
	siasync "github.com/NebulousLabs/Sia/sync"
	"github.com/NebulousLabs/Sia/types"
)

const (
	// Names of the various persistent files in the host.
	dbFilename   = modules.HostDir + ".db"
	logFile      = modules.HostDir + ".log"
	settingsFile = modules.HostDir + ".json"
)

var (
	// dbMetadata is a header that gets put into the database to identify a
	// version and indicate that the database holds host information.
	dbMetadata = persist.Metadata{
		Header:  "Sia Host DB",
		Version: "0.5.2",
	}

	// persistMetadata is the header that gets written to the persist file, and is
	// used to recognize other persist files.
	persistMetadata = persist.Metadata{
		Header:  "Sia Host",
		Version: "0.5",
	}

	// errHostClosed gets returned when a call is rejected due to the host
	// having been closed.
	errHostClosed = errors.New("call is disabled because the host is closed")

	// Nil dependency errors.
	errNilCS     = errors.New("host cannot use a nil state")
	errNilTpool  = errors.New("host cannot use a nil transaction pool")
	errNilWallet = errors.New("host cannot use a nil wallet")
)

// A Host contains all the fields necessary for storing files for clients and
// performing the storage proofs on the received files.
type Host struct {
	// RPC Metrics - atomic variables need to be placed at the top to preserve
	// compatibility with 32bit systems.
	atomicDownloadCalls       uint64
	atomicErroredCalls        uint64
	atomicFormContractCalls   uint64
	atomicRenewCalls          uint64
	atomicReviseCalls         uint64
	atomicRecentRevisionCalls uint64
	atomicSettingsCalls       uint64
	atomicUnrecognizedCalls   uint64

	// Error management. There are a few different types of errors returned by
	// the host. These errors intentionally not persistent, so that the logging
	// limits of each error type will be reset each time the host is reset.
	atomicCommunicationErrors uint64
	atomicConnectionErrors    uint64
	atomicConsensusErrors     uint64
	atomicInternalErrors      uint64
	atomicNormalErrors        uint64

	// Dependencies.
	cs     modules.ConsensusSet
	tpool  modules.TransactionPool
	wallet modules.Wallet
	dependencies
	modules.StorageManager

	// Consensus Tracking.
	blockHeight  types.BlockHeight
	recentChange modules.ConsensusChangeID

	// Host Identity
	//
	// The revision number keeps track of the current revision number on the
	// host external settingse
	//
	// The auto address is the address that is fetched automatically by the
	// host. The host will ignore the automatic address if settings.NetAddress
	// has been set by the user. If settings.NetAddress is blank, then the host
	// will track its own ip address and make an announcement on the blockchain
	// every time that the address changes.
	//
	// The announced bool indicates whether the host remembers having a
	// successful announcement with the current address.
	announced        bool
	autoAddress      modules.NetAddress
	financialMetrics modules.HostFinancialMetrics
	publicKey        types.SiaPublicKey
	revisionNumber   uint64
	secretKey        crypto.SecretKey
	settings         modules.HostInternalSettings
	unlockHash       types.UnlockHash // A wallet address that can receive coins.

	// A map of storage obligations that are currently being modified. Locks on
	// storage obligations can be long-running, and each storage obligation can
	// be locked separately.
	lockedStorageObligations map[types.FileContractID]*siasync.TryMutex

	// Utilities.
	db         *persist.BoltDatabase
	listener   net.Listener
	log        *persist.Logger
	mu         *siasync.RWMutex
	persistDir string
	port       string
	tg         siasync.ThreadGroup
}

// checkUnlockHash will check that the host has an unlock hash. If the host
// does not have an unlock hash, an attempt will be made to get an unlock hash
// from the wallet. That may fail due to the wallet being locked, in which case
// an error is returned.
func (h *Host) checkUnlockHash() error {
	if h.unlockHash == (types.UnlockHash{}) {
		uc, err := h.wallet.NextAddress()
		if err != nil {
			return err
		}

		// Set the unlock hash and save the host. Saving is important, because
		// the host will be using this unlock hash to establish identity, and
		// losing it will mean silently losing part of the host identity.
		h.unlockHash = uc.UnlockHash()
		err = h.saveSync()
		if err != nil {
			return err
		}
	}
	return nil
}

// newHost returns an initialized Host, taking a set of dependencies as input.
// By making the dependencies an argument of the 'new' call, the host can be
// mocked such that the dependencies can return unexpected errors or unique
// behaviors during testing, enabling easier testing of the failure modes of
// the Host.
func newHost(dependencies dependencies, cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, listenerAddress string, persistDir string) (*Host, error) {
	// Check that all the dependencies were provided.
	if cs == nil {
		return nil, errNilCS
	}
	if tpool == nil {
		return nil, errNilTpool
	}
	if wallet == nil {
		return nil, errNilWallet
	}

	// Create the host object.
	h := &Host{
		cs:           cs,
		tpool:        tpool,
		wallet:       wallet,
		dependencies: dependencies,

		lockedStorageObligations: make(map[types.FileContractID]*siasync.TryMutex),

		mu:         siasync.New(modules.SafeMutexDelay, 2),
		persistDir: persistDir,
	}

	// Call stop in the event of a partial startup.
	var err error
	defer func() {
		if err != nil {
			err = composeErrors(h.tg.Stop(), err)
		}
	}()

	// Create the perist directory if it does not yet exist.
	err = dependencies.mkdirAll(h.persistDir, 0700)
	if err != nil {
		return nil, err
	}

	// Initialize the logger, and set up the stop call that will close the
	// logger.
	h.log, err = dependencies.newLogger(filepath.Join(h.persistDir, logFile))
	if err != nil {
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.log.Close()
		if err != nil {
			// State of the logger is uncertain, a Println will have to
			// suffice.
			fmt.Println("Error when closing the logger:", err)
		}
	})

	// Add the storage manager to the host, and set up the stop call that will
	// close the storage manager.
	h.StorageManager, err = storagemanager.New(filepath.Join(persistDir, "storagemanager"))
	if err != nil {
		h.log.Println("Could not open the storage manager:", err)
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.StorageManager.Close()
		if err != nil {
			h.log.Println("Could not close storage manager:", err)
		}
	})

	// After opening the database, it must be initialized. Most commonly,
	// nothing happens. But for new databases, a set of buckets must be
	// created. Initialization is also a good time to run sanity checks.
	err = h.initDB()
	if err != nil {
		h.log.Println("Could not initalize database:", err)
		return nil, err
	}

	// Load the prior persistence structures, and configure the host to save
	// before shutting down.
	err = h.load()
	if err != nil {
		return nil, err
	}
	h.tg.AfterStop(func() {
		err = h.saveSync()
		if err != nil {
			h.log.Println("Could not save host upon shutdown:", err)
		}
	})

	// Initialize the networking.
	err = h.initNetworking(listenerAddress)
	if err != nil {
		h.log.Println("Could not initialize host networking:", err)
		return nil, err
	}
	return h, nil
}

// New returns an initialized Host.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, wallet modules.Wallet, address string, persistDir string) (*Host, error) {
	return newHost(productionDependencies{}, cs, tpool, wallet, address, persistDir)
}

// Close shuts down the host.
func (h *Host) Close() error {
	return h.tg.Stop()
}

// ExternalSettings returns the hosts external settings. These values cannot be
// set by the user (host is configured through InternalSettings), and are the
// values that get displayed to other hosts on the network.
func (h *Host) ExternalSettings() modules.HostExternalSettings {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		build.Critical("Call to ExternalSettings after close")
	}
	defer h.tg.Done()
	return h.externalSettings()
}

// FinancialMetrics returns information about the financial commitments,
// rewards, and activities of the host.
func (h *Host) FinancialMetrics() modules.HostFinancialMetrics {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		build.Critical("Call to FinancialMetrics after close")
	}
	defer h.tg.Done()
	return h.financialMetrics
}

// SetInternalSettings updates the host's internal HostInternalSettings object.
func (h *Host) SetInternalSettings(settings modules.HostInternalSettings) error {
	lockID := h.mu.Lock()
	defer h.mu.Unlock(lockID)
	err := h.tg.Add()
	if err != nil {
		return err
	}
	defer h.tg.Done()

	// The host should not be accepting file contracts if it does not have an
	// unlock hash.
	if settings.AcceptingContracts {
		err := h.checkUnlockHash()
		if err != nil {
			return errors.New("internal settings not updated, no unlock hash: " + err.Error())
		}
	}

	if settings.NetAddress != "" {
		err := settings.NetAddress.IsValid()
		if err != nil {
			return errors.New("internal settings not updated, invalid NetAddress: " + err.Error())
		}
	}

	// Check if the net address for the host has changed. If it has, and it's
	// not equal to the auto address, then the host is going to need to make
	// another blockchain announcement.
	if h.settings.NetAddress != settings.NetAddress && settings.NetAddress != h.autoAddress {
		h.announced = false
	}

	h.settings = settings
	h.revisionNumber++

	err = h.saveSync()
	if err != nil {
		return errors.New("internal settings updated, but failed saving to disk: " + err.Error())
	}
	return nil
}

// InternalSettings returns the settings of a host.
func (h *Host) InternalSettings() modules.HostInternalSettings {
	lockID := h.mu.RLock()
	defer h.mu.RUnlock(lockID)
	err := h.tg.Add()
	if err != nil {
		return modules.HostInternalSettings{}
	}
	defer h.tg.Done()
	return h.settings
}
<|endoftext|>


<commit_before>package main

import (
	"ircclient"
	"fmt"
)

func main() {
	args := []string{"!das hier ist ein  \"Test! \\\"für\" das  "}
	msg := &ircclient.IRCMessage{"", "", "PRIVMSG", args, ""}
	ret := ircclient.ParseCommand(msg, '!')
	fmt.Printf("%#v", ret.Args)
}
<commit_msg>removed old, unused test.go file<commit_after><|endoftext|>


<commit_before>package lzma

import (
	"errors"
	"io"
)

// Errors produced by readOp and fillBuffer
var (
	eos              = errors.New("end of stream")
	errClosed        = errors.New("stream is closed")
	errDataAfterEOS  = errors.New("data after end of stream")
	errUnexpectedEOS = errors.New("unexpected eos")
)

type Reader struct {
	Params    Parameters
	state     *State
	rd        *rangeDecoder
	pendingOp operation
	buf       *buffer
	head      int64
	limited   bool
	// limit marks the expected size of the decompressed byte stream
	limit  int64
	closed bool
}

func NewStreamReader(lzma io.Reader, p Parameters) (r *Reader, err error) {
	if err = p.Verify(); err != nil {
		return nil, err
	}
	buf, err := newBuffer(p.DictSize + p.ExtraBufSize)
	if err != nil {
		return
	}
	dict, err := newSyncDict(buf, p.DictSize)
	if err != nil {
		return
	}
	state := NewState(p.Properties(), dict)
	rd, err := newRangeDecoder(lzma)
	if err != nil {
		return
	}
	r = &Reader{Params: p, state: state, rd: rd, buf: buf, head: buf.bottom}
	if p.SizeInHeader {
		if err = r.setSize(p.Size); err != nil {
			return nil, err
		}
	} else {
		r.move(0)
	}
	return r, nil
}

// decodeLiteral reads a literal.
func (r *Reader) decodeLiteral() (op operation, err error) {
	litState := r.state.litState()
	match := r.state.dict.byteAt(int64(r.state.rep[0]) + 1)
	s, err := r.state.litCodec.Decode(r.rd, r.state.state, match, litState)
	if err != nil {
		return nil, err
	}
	return lit{s}, nil
}

// readOp decodes the next operation from the compressed stream. It returns the
// operation. If an explicit end of stream marker is identified the eos error is
// returned.
func (r *Reader) readOp() (op operation, err error) {
	// Value of the end of stream (EOS) marker
	const eosDist = 1<<32 - 1

	state, state2, posState := r.state.states()

	b, err := r.state.isMatch[state2].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// literal
		op, err := r.decodeLiteral()
		if err != nil {
			return nil, err
		}
		r.state.updateStateLiteral()
		return op, nil
	}
	b, err = r.state.isRep[state].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// simple match
		r.state.rep[3], r.state.rep[2], r.state.rep[1] = r.state.rep[2], r.state.rep[1], r.state.rep[0]

		r.state.updateStateMatch()
		// The length decoder returns the length offset.
		n, err := r.state.lenCodec.Decode(r.rd, posState)
		if err != nil {
			return nil, err
		}
		// The dist decoder returns the distance offset. The actual
		// distance is 1 higher.
		r.state.rep[0], err = r.state.distCodec.Decode(r.rd, n)
		if err != nil {
			return nil, err
		}
		if r.state.rep[0] == eosDist {
			return nil, eos
		}
		op = match{n: int(n) + MinLength,
			distance: int64(r.state.rep[0]) + minDistance}
		return op, nil
	}
	b, err = r.state.isRepG0[state].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	dist := r.state.rep[0]
	if b == 0 {
		// rep match 0
		b, err = r.state.isRepG0Long[state2].Decode(r.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			r.state.updateStateShortRep()
			op = match{n: 1, distance: int64(dist) + minDistance}
			return op, nil
		}
	} else {
		b, err = r.state.isRepG1[state].Decode(r.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			dist = r.state.rep[1]
		} else {
			b, err = r.state.isRepG2[state].Decode(r.rd)
			if err != nil {
				return nil, err
			}
			if b == 0 {
				dist = r.state.rep[2]
			} else {
				dist = r.state.rep[3]
				r.state.rep[3] = r.state.rep[2]
			}
			r.state.rep[2] = r.state.rep[1]
		}
		r.state.rep[1] = r.state.rep[0]
		r.state.rep[0] = dist
	}
	n, err := r.state.repLenCodec.Decode(r.rd, posState)
	if err != nil {
		return nil, err
	}
	r.state.updateStateRep()
	op = match{n: int(n) + MinLength, distance: int64(dist) + minDistance}
	return op, nil
}

func (r *Reader) close() error {
	if r.closed {
		return errClosed
	}
	if r.pendingOp != nil {
		return errDataAfterEOS
	}
	if !r.rd.possiblyAtEnd() {
		_, err := r.readOp()
		if err != eos {
			if err != nil {
				return err
			}
			return errDataAfterEOS
		}
		if !r.rd.possiblyAtEnd() {
			return errDataAfterEOS
		}
	}
	r.closed = true
	return nil
}

func (r *Reader) outsideLimits(op operation) (outside bool, err error) {
	off := r.buf.top + int64(op.Len())
	if off > r.buf.writeLimit {
		if r.limited && off > r.limit {
			return true, errLimit
		}
		return true, nil
	}
	return false, nil
}

// fillBuffer fills the buffer with data read from the LZMA stream.
func (r *Reader) fillBuffer() error {
	if r.closed {
		return nil
	}
	d := r.state.dict.(*syncDict)
	if r.pendingOp != nil {
		op := r.pendingOp
		if outside, err := r.outsideLimits(op); outside || err != nil {
			return err
		}
		if err := op.Apply(d); err != nil {
			return err
		}
		r.pendingOp = nil
	}
	for r.buf.top < r.buf.writeLimit {
		op, err := r.readOp()
		if err != nil {
			switch err {
			case eos:
				r.closed = true
				if !r.rd.possiblyAtEnd() {
					return errDataAfterEOS
				}
				return eos
			case io.EOF:
				r.closed = true
				return io.ErrUnexpectedEOF
			default:
				return err
			}
		}
		if outside, err := r.outsideLimits(op); outside || err != nil {
			r.pendingOp = op
			return err
		}
		if err = op.Apply(d); err != nil {
			return err
		}
	}
	return nil
}

func (r *Reader) move(n int) {
	off := r.head + int64(n)
	if !(r.buf.bottom <= off && off <= r.buf.top) {
		panic("new offset out of range")
	}
	limit := off + int64(r.buf.capacity())
	if r.limited && limit > r.limit {
		limit = r.limit
	}
	if limit < r.buf.top {
		panic("limit out of range")
	}
	r.head = off
	r.buf.writeLimit = limit
}

func (r *Reader) eof() bool {
	return r.closed && r.head == r.buf.top
}

// readBuffer reads data from the buffer into the p slice.
func (r *Reader) readBuffer(p []byte) (n int, err error) {
	n, err = r.buf.ReadAt(p, r.head)
	r.move(n)
	if r.eof() {
		err = io.EOF
	}
	return
}

// Read reads uncompressed data from the raw LZMA data stream.
func (r *Reader) Read(p []byte) (n int, err error) {
	if r.eof() {
		return 0, io.EOF
	}
	if len(p) == 0 {
		return 0, nil
	}
	for {
		var k int
		k, err = r.readBuffer(p)
		n += k
		if err != nil {
			return
		}
		if k >= len(p) {
			return
		}
		p = p[k:]
		err = r.fillBuffer()
		if err != nil {
			if err == eos {
				if r.limited && r.buf.top != r.limit {
					return n, errUnexpectedEOS
				}
			} else {
				return n, err
			}
		}
		if r.limited && r.buf.top == r.limit {
			err = r.close()
			if err != nil {
				return n, err
			}
		}
	}
}

func (r *Reader) setSize(size int64) error {
	limit := r.head + size
	if limit < r.buf.top {
		return errors.New("limit out of range")
	}
	r.limited = true
	r.limit = limit
	r.move(0)
	return nil
}

func (r *Reader) Restart(lzma io.Reader) {
	panic("TODO")
}

func (r *Reader) ResetState() {
	panic("TODO")
}

func (r *Reader) ResetProperties(p Properties) {
	panic("TODO")
}

func (r *Reader) ResetDictionary(p Properties) {
	panic("TODO")
}
<commit_msg>lzma: removed limited field from Reader<commit_after>package lzma

import (
	"errors"
	"io"
)

// Errors produced by readOp and fillBuffer
var (
	eos              = errors.New("end of stream")
	errClosed        = errors.New("stream is closed")
	errDataAfterEOS  = errors.New("data after end of stream")
	errUnexpectedEOS = errors.New("unexpected eos")
)

type Reader struct {
	Params    Parameters
	state     *State
	rd        *rangeDecoder
	pendingOp operation
	buf       *buffer
	head      int64
	// limit marks the expected size of the decompressed byte stream
	limit  int64
	closed bool
}

func NewStreamReader(lzma io.Reader, p Parameters) (r *Reader, err error) {
	if err = p.Verify(); err != nil {
		return nil, err
	}
	buf, err := newBuffer(p.DictSize + p.ExtraBufSize)
	if err != nil {
		return
	}
	dict, err := newSyncDict(buf, p.DictSize)
	if err != nil {
		return
	}
	state := NewState(p.Properties(), dict)
	rd, err := newRangeDecoder(lzma)
	if err != nil {
		return
	}
	r = &Reader{Params: p, state: state, rd: rd, buf: buf, head: buf.bottom}
	if p.SizeInHeader {
		r.limit = r.head + p.Size
		if r.limit < r.buf.top {
			return nil, errors.New("limit out of range")
		}
	}
	r.move(0)
	return r, nil
}

// decodeLiteral reads a literal.
func (r *Reader) decodeLiteral() (op operation, err error) {
	litState := r.state.litState()
	match := r.state.dict.byteAt(int64(r.state.rep[0]) + 1)
	s, err := r.state.litCodec.Decode(r.rd, r.state.state, match, litState)
	if err != nil {
		return nil, err
	}
	return lit{s}, nil
}

// readOp decodes the next operation from the compressed stream. It returns the
// operation. If an explicit end of stream marker is identified the eos error is
// returned.
func (r *Reader) readOp() (op operation, err error) {
	// Value of the end of stream (EOS) marker
	const eosDist = 1<<32 - 1

	state, state2, posState := r.state.states()

	b, err := r.state.isMatch[state2].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// literal
		op, err := r.decodeLiteral()
		if err != nil {
			return nil, err
		}
		r.state.updateStateLiteral()
		return op, nil
	}
	b, err = r.state.isRep[state].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// simple match
		r.state.rep[3], r.state.rep[2], r.state.rep[1] = r.state.rep[2], r.state.rep[1], r.state.rep[0]

		r.state.updateStateMatch()
		// The length decoder returns the length offset.
		n, err := r.state.lenCodec.Decode(r.rd, posState)
		if err != nil {
			return nil, err
		}
		// The dist decoder returns the distance offset. The actual
		// distance is 1 higher.
		r.state.rep[0], err = r.state.distCodec.Decode(r.rd, n)
		if err != nil {
			return nil, err
		}
		if r.state.rep[0] == eosDist {
			return nil, eos
		}
		op = match{n: int(n) + MinLength,
			distance: int64(r.state.rep[0]) + minDistance}
		return op, nil
	}
	b, err = r.state.isRepG0[state].Decode(r.rd)
	if err != nil {
		return nil, err
	}
	dist := r.state.rep[0]
	if b == 0 {
		// rep match 0
		b, err = r.state.isRepG0Long[state2].Decode(r.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			r.state.updateStateShortRep()
			op = match{n: 1, distance: int64(dist) + minDistance}
			return op, nil
		}
	} else {
		b, err = r.state.isRepG1[state].Decode(r.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			dist = r.state.rep[1]
		} else {
			b, err = r.state.isRepG2[state].Decode(r.rd)
			if err != nil {
				return nil, err
			}
			if b == 0 {
				dist = r.state.rep[2]
			} else {
				dist = r.state.rep[3]
				r.state.rep[3] = r.state.rep[2]
			}
			r.state.rep[2] = r.state.rep[1]
		}
		r.state.rep[1] = r.state.rep[0]
		r.state.rep[0] = dist
	}
	n, err := r.state.repLenCodec.Decode(r.rd, posState)
	if err != nil {
		return nil, err
	}
	r.state.updateStateRep()
	op = match{n: int(n) + MinLength, distance: int64(dist) + minDistance}
	return op, nil
}

func (r *Reader) close() error {
	if r.closed {
		return errClosed
	}
	if r.pendingOp != nil {
		return errDataAfterEOS
	}
	if !r.rd.possiblyAtEnd() {
		_, err := r.readOp()
		if err != eos {
			if err != nil {
				return err
			}
			return errDataAfterEOS
		}
		if !r.rd.possiblyAtEnd() {
			return errDataAfterEOS
		}
	}
	r.closed = true
	return nil
}

func (r *Reader) outsideLimits(op operation) (outside bool, err error) {
	off := r.buf.top + int64(op.Len())
	if off > r.buf.writeLimit {
		if r.Params.SizeInHeader && off > r.limit {
			return true, errLimit
		}
		return true, nil
	}
	return false, nil
}

// fillBuffer fills the buffer with data read from the LZMA stream.
func (r *Reader) fillBuffer() error {
	if r.closed {
		return nil
	}
	d := r.state.dict.(*syncDict)
	if r.pendingOp != nil {
		op := r.pendingOp
		if outside, err := r.outsideLimits(op); outside || err != nil {
			return err
		}
		if err := op.Apply(d); err != nil {
			return err
		}
		r.pendingOp = nil
	}
	for r.buf.top < r.buf.writeLimit {
		op, err := r.readOp()
		if err != nil {
			switch err {
			case eos:
				r.closed = true
				if !r.rd.possiblyAtEnd() {
					return errDataAfterEOS
				}
				return eos
			case io.EOF:
				r.closed = true
				return io.ErrUnexpectedEOF
			default:
				return err
			}
		}
		if outside, err := r.outsideLimits(op); outside || err != nil {
			r.pendingOp = op
			return err
		}
		if err = op.Apply(d); err != nil {
			return err
		}
	}
	return nil
}

func (r *Reader) move(n int) {
	off := r.head + int64(n)
	if !(r.buf.bottom <= off && off <= r.buf.top) {
		panic("new offset out of range")
	}
	limit := off + int64(r.buf.capacity())
	if r.Params.SizeInHeader && limit > r.limit {
		limit = r.limit
	}
	if limit < r.buf.top {
		panic("limit out of range")
	}
	r.head = off
	r.buf.writeLimit = limit
}

func (r *Reader) eof() bool {
	return r.closed && r.head == r.buf.top
}

// readBuffer reads data from the buffer into the p slice.
func (r *Reader) readBuffer(p []byte) (n int, err error) {
	n, err = r.buf.ReadAt(p, r.head)
	r.move(n)
	if r.eof() {
		err = io.EOF
	}
	return
}

// Read reads uncompressed data from the raw LZMA data stream.
func (r *Reader) Read(p []byte) (n int, err error) {
	if r.eof() {
		return 0, io.EOF
	}
	if len(p) == 0 {
		return 0, nil
	}
	for {
		var k int
		k, err = r.readBuffer(p)
		n += k
		if err != nil {
			return
		}
		if k >= len(p) {
			return
		}
		p = p[k:]
		err = r.fillBuffer()
		if err != nil {
			if err == eos {
				if r.Params.SizeInHeader && r.buf.top != r.limit {
					return n, errUnexpectedEOS
				}
			} else {
				return n, err
			}
		}
		if r.Params.SizeInHeader && r.buf.top == r.limit {
			err = r.close()
			if err != nil {
				return n, err
			}
		}
	}
}

func (r *Reader) setSize(size int64) error {
	return nil
}

func (r *Reader) Restart(lzma io.Reader) {
	panic("TODO")
}

func (r *Reader) ResetState() {
	panic("TODO")
}

func (r *Reader) ResetProperties(p Properties) {
	panic("TODO")
}

func (r *Reader) ResetDictionary(p Properties) {
	panic("TODO")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/coreos/go-etcd/etcd"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"time"
)

var client = http.Client{Transport: &http.Transport{
	Dial: dialTimeoutFast,
},
}

// Sending set commands
func set(stop chan bool) {

	stopSet := false
	i := 0

	for {
		key := fmt.Sprintf("%s_%v", "foo", i)

		result, err := etcd.Set(key, "bar", 0)

		if err != nil || result.Key != "/"+key || result.Value != "bar" {
			select {
			case <-stop:
				stopSet = true

			default:
			}
		}

		select {
		case <-stop:
			stopSet = true

		default:
		}

		if stopSet {
			break
		}

		i++
	}
	fmt.Println("set stop")
	stop <- true
}

// Create a cluster of etcd nodes
func createCluster(size int, procAttr *os.ProcAttr) ([][]string, []*os.Process, error) {
	argGroup := make([][]string, size)
	for i := 0; i < size; i++ {
		if i == 0 {
			argGroup[i] = []string{"etcd", "-d=/tmp/node1"}
		} else {
			strI := strconv.Itoa(i + 1)
			argGroup[i] = []string{"etcd", "-c=400" + strI, "-s=700" + strI, "-d=/tmp/node" + strI, "-C=127.0.0.1:7001"}
		}
	}

	etcds := make([]*os.Process, size)

	for i, _ := range etcds {
		var err error
		etcds[i], err = os.StartProcess("etcd", append(argGroup[i], "-i"), procAttr)
		if err != nil {
			return nil, nil, err
		}
	}

	return argGroup, etcds, nil
}

// Destroy all the nodes in the cluster
func destroyCluster(etcds []*os.Process) error {
	for i, etcd := range etcds {
		err := etcd.Kill()
		fmt.Println("kill ", i)
		if err != nil {
			panic(err.Error())
		}
		etcd.Release()
	}
	return nil
}

//
func leaderMonitor(size int, allowDeadNum int, leaderChan chan string) {
	leaderMap := make(map[int]string)
	baseAddrFormat := "http://0.0.0.0:400%d/leader"
	for {
		knownLeader := "unknown"
		dead := 0
		var i int
		for i = 0; i < size; i++ {
			leader, err := getLeader(fmt.Sprintf(baseAddrFormat, i+1))
			if err == nil {
				leaderMap[i] = leader

				if knownLeader == "unknown" {
					knownLeader = leader
				} else {
					if leader != knownLeader {
						break
					}
				}
			} else {
				dead++
				if dead > allowDeadNum {
					break
				}
			}
		}
		if i == size {
			select {
			case <-leaderChan:
				leaderChan <- knownLeader
			default:
				leaderChan <- knownLeader
			}

		}
		time.Sleep(time.Millisecond * 10)
	}
}

func getLeader(addr string) (string, error) {

	resp, err := client.Get(addr)

	if err != nil {
		return "", err
	}

	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return "", fmt.Errorf("no leader")
	}

	b, err := ioutil.ReadAll(resp.Body)

	resp.Body.Close()

	if err != nil {
		return "", err
	}

	return string(b), nil

}

// Dial with timeout
func dialTimeoutFast(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Millisecond*10)
}
<commit_msg>add space<commit_after>package main

import (
	"fmt"
	"github.com/coreos/go-etcd/etcd"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"time"
)

var client = http.Client{
	Transport: &http.Transport{
		Dial: dialTimeoutFast,
	},
}

// Sending set commands
func set(stop chan bool) {

	stopSet := false
	i := 0

	for {
		key := fmt.Sprintf("%s_%v", "foo", i)

		result, err := etcd.Set(key, "bar", 0)

		if err != nil || result.Key != "/"+key || result.Value != "bar" {
			select {
			case <-stop:
				stopSet = true

			default:
			}
		}

		select {
		case <-stop:
			stopSet = true

		default:
		}

		if stopSet {
			break
		}

		i++
	}
	fmt.Println("set stop")
	stop <- true
}

// Create a cluster of etcd nodes
func createCluster(size int, procAttr *os.ProcAttr) ([][]string, []*os.Process, error) {
	argGroup := make([][]string, size)
	for i := 0; i < size; i++ {
		if i == 0 {
			argGroup[i] = []string{"etcd", "-d=/tmp/node1"}
		} else {
			strI := strconv.Itoa(i + 1)
			argGroup[i] = []string{"etcd", "-c=400" + strI, "-s=700" + strI, "-d=/tmp/node" + strI, "-C=127.0.0.1:7001"}
		}
	}

	etcds := make([]*os.Process, size)

	for i, _ := range etcds {
		var err error
		etcds[i], err = os.StartProcess("etcd", append(argGroup[i], "-i"), procAttr)
		if err != nil {
			return nil, nil, err
		}
	}

	return argGroup, etcds, nil
}

// Destroy all the nodes in the cluster
func destroyCluster(etcds []*os.Process) error {
	for i, etcd := range etcds {
		err := etcd.Kill()
		fmt.Println("kill ", i)
		if err != nil {
			panic(err.Error())
		}
		etcd.Release()
	}
	return nil
}

//
func leaderMonitor(size int, allowDeadNum int, leaderChan chan string) {
	leaderMap := make(map[int]string)
	baseAddrFormat := "http://0.0.0.0:400%d/leader"

	for {
		knownLeader := "unknown"
		dead := 0
		var i int

		for i = 0; i < size; i++ {
			leader, err := getLeader(fmt.Sprintf(baseAddrFormat, i+1))

			if err == nil {
				leaderMap[i] = leader

				if knownLeader == "unknown" {
					knownLeader = leader
				} else {
					if leader != knownLeader {
						break
					}

				}

			} else {
				dead++
				if dead > allowDeadNum {
					break
				}
			}

		}

		if i == size {
			select {
			case <-leaderChan:
				leaderChan <- knownLeader
			default:
				leaderChan <- knownLeader
			}

		}

		time.Sleep(time.Millisecond * 10)
	}

}

func getLeader(addr string) (string, error) {

	resp, err := client.Get(addr)

	if err != nil {
		return "", err
	}

	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return "", fmt.Errorf("no leader")
	}

	b, err := ioutil.ReadAll(resp.Body)

	resp.Body.Close()

	if err != nil {
		return "", err
	}

	return string(b), nil

}

// Dial with timeout
func dialTimeoutFast(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Millisecond*10)
}
<|endoftext|>