<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package spotty

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"syscall"
)

func sameFile(ss1 *syscall.Stat_t, fi os.FileInfo) bool {
	if ss2, ok := fi.Sys().(*syscall.Stat_t); ok {
		return ss1.Dev == ss2.Dev && ss1.Rdev == ss2.Rdev && ss1.Ino == ss2.Ino
	}
	return false
}

// Discover which named TTY we have open as FD=0. Will return empty string or an error
// if nothing was found, or if there was a problem, respectively. Will not work on Windows.
func Discover() (string, error) {
	var sstat syscall.Stat_t
	if err := syscall.Fstat(0, &sstat); err != nil {
		return "", err
	}
	res, err := findFileIn(&sstat, "/dev", regexp.MustCompile(`^tty[A-Za-z0-9]+$`))
	if err != nil {
		return "", err
	}
	if len(res) > 0 {
		return res, nil
	}
	res, err = findFileIn(&sstat, "/dev/pts", regexp.MustCompile(`^[0-9]+$`))
	return res, err
}

func findFileIn(ss *syscall.Stat_t, dir string, re *regexp.Regexp) (string, error) {
	v, err := ioutil.ReadDir(dir)
	if err != nil {
		if _, ok := err.(*os.PathError); ok {
			return "", nil
		}
		return "", err
	}
	for _, fi := range v {
		if !re.MatchString(fi.Name()) {
			continue
		}
		if sameFile(ss, fi) {
			return filepath.Join(dir, fi.Name()), nil
		}
	}
	return "", nil
}
<commit_msg>better doc<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package spotty

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"syscall"
)

func sameFile(ss1 *syscall.Stat_t, fi os.FileInfo) bool {
	if ss2, ok := fi.Sys().(*syscall.Stat_t); ok {
		return ss1.Dev == ss2.Dev && ss1.Rdev == ss2.Rdev && ss1.Ino == ss2.Ino
	}
	return false
}

// Discover which named TTY we have open as FD=0. Will return empty string if nothing
// was found, and an non-nil error if there was a problem. Will noop on Windows.
func Discover() (string, error) {
	var sstat syscall.Stat_t
	if err := syscall.Fstat(0, &sstat); err != nil {
		return "", err
	}
	res, err := findFileIn(&sstat, "/dev", regexp.MustCompile(`^tty[A-Za-z0-9]+$`))
	if err != nil {
		return "", err
	}
	if len(res) > 0 {
		return res, nil
	}
	res, err = findFileIn(&sstat, "/dev/pts", regexp.MustCompile(`^[0-9]+$`))
	return res, err
}

func findFileIn(ss *syscall.Stat_t, dir string, re *regexp.Regexp) (string, error) {
	v, err := ioutil.ReadDir(dir)
	if err != nil {
		if _, ok := err.(*os.PathError); ok {
			return "", nil
		}
		return "", err
	}
	for _, fi := range v {
		if !re.MatchString(fi.Name()) {
			continue
		}
		if sameFile(ss, fi) {
			return filepath.Join(dir, fi.Name()), nil
		}
	}
	return "", nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

package vtctl

import (
	"flag"
	"fmt"
	"time"

	"github.com/youtube/vitess/go/vt/topo/topoproto"
	"github.com/youtube/vitess/go/vt/wrangler"
	"golang.org/x/net/context"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

var (
	// DisableActiveReparents is a flag to disable active
	// reparents for safety reasons. It is used in two places:
	// 1. in this file to skip registering the commands.
	// 2. in vtctld so it can be exported to the UI (different
	// package, that's why it's exported). That way we can disable
	// menu items there, using features.
	DisableActiveReparents = flag.Bool("disable_active_reparents", false, "if set, do not allow active reparents. Use this to protect a cluster using external reparents.")
)

func init() {
	addCommand("Tablets", command{
		"ReparentTablet",
		commandReparentTablet,
		"<tablet alias>",
		"Reparent a tablet to the current master in the shard. This only works if the current slave position matches the last known reparent action."})

	addCommand("Shards", command{
		"InitShardMaster",
		commandInitShardMaster,
		"[-force] [-wait_slave_timeout=<duration>] <keyspace/shard> <tablet alias>",
		"Sets the initial master for a shard. Will make all other tablets in the shard slaves of the provided master. WARNING: this could cause data loss on an already replicating shard. PlannedReparentShard or EmergencyReparentShard should be used instead."})
	addCommand("Shards", command{
		"PlannedReparentShard",
		commandPlannedReparentShard,
		"-keyspace_shard=<keyspace/shard> [-new_master=<tablet alias>] [-avoid_master=<tablet alias>]",
		"Reparents the shard to the new master, or away from old master. Both old and new master need to be up and running."})
	addCommand("Shards", command{
		"EmergencyReparentShard",
		commandEmergencyReparentShard,
		"-keyspace_shard=<keyspace/shard> -new_master=<tablet alias>",
		"Reparents the shard to the new master. Assumes the old master is dead and not responsding."})
}

func commandReparentTablet(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled")
	}

	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() != 1 {
		return fmt.Errorf("action ReparentTablet requires <tablet alias>")
	}
	tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(0))
	if err != nil {
		return err
	}
	return wr.ReparentTablet(ctx, tabletAlias)
}

func commandInitShardMaster(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled")
	}

	force := subFlags.Bool("force", false, "will force the reparent even if the provided tablet is not a master or the shard master")
	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() != 2 {
		return fmt.Errorf("action InitShardMaster requires <keyspace/shard> <tablet alias>")
	}
	keyspace, shard, err := topoproto.ParseKeyspaceShard(subFlags.Arg(0))
	if err != nil {
		return err
	}
	tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(1))
	if err != nil {
		return err
	}
	return wr.InitShardMaster(ctx, keyspace, shard, tabletAlias, *force, *waitSlaveTimeout)
}

func commandPlannedReparentShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled")
	}

	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	keyspaceShard := subFlags.String("keyspace_shard", "", "keyspace/shard of the shard that needs to be reparented")
	newMaster := subFlags.String("new_master", "", "alias of a tablet that should be the new master")
	avoidMaster := subFlags.String("avoid_master", "", "alias of a tablet that should not be the master, i.e. reparent to any other tablet if this one is the master")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() == 2 {
		// Legacy syntax: "<keyspace/shard> <tablet alias>".
		if *keyspaceShard != "" || *newMaster != "" {
			return fmt.Errorf("cannot use legacy syntax and flags -keyspace_shard and -new_master for action PlannedReparentShard at the same time")
		}
		*keyspaceShard = subFlags.Arg(0)
		*newMaster = subFlags.Arg(1)
	} else if subFlags.NArg() != 0 {
		return fmt.Errorf("action PlannedReparentShard requires -keyspace_shard=<keyspace/shard> [-new_master=<tablet alias>] [-avoid_master=<tablet alias>]")
	}

	keyspace, shard, err := topoproto.ParseKeyspaceShard(*keyspaceShard)
	if err != nil {
		return err
	}
	var newMasterAlias, avoidMasterAlias *topodatapb.TabletAlias
	if *newMaster != "" {
		newMasterAlias, err = topoproto.ParseTabletAlias(*newMaster)
		if err != nil {
			return err
		}
	}
	if *avoidMaster != "" {
		avoidMasterAlias, err = topoproto.ParseTabletAlias(*avoidMaster)
		if err != nil {
			return err
		}
	}
	return wr.PlannedReparentShard(ctx, keyspace, shard, newMasterAlias, avoidMasterAlias, *waitSlaveTimeout)
}

func commandEmergencyReparentShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled")
	}

	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	keyspaceShard := subFlags.String("keyspace_shard", "", "keyspace/shard of the shard that needs to be reparented")
	newMaster := subFlags.String("new_master", "", "alias of a tablet that should be the new master")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() == 2 {
		// Legacy syntax: "<keyspace/shard> <tablet alias>".
		if *newMaster != "" {
			return fmt.Errorf("cannot use legacy syntax and flag -new_master for action EmergencyReparentShard at the same time")
		}
		*keyspaceShard = subFlags.Arg(0)
		*newMaster = subFlags.Arg(1)
	} else if subFlags.NArg() != 0 {
		return fmt.Errorf("action EmergencyReparentShard requires -keyspace_shard=<keyspace/shard> -new_master=<tablet alias>")
	}

	keyspace, shard, err := topoproto.ParseKeyspaceShard(*keyspaceShard)
	if err != nil {
		return err
	}
	tabletAlias, err := topoproto.ParseTabletAlias(*newMaster)
	if err != nil {
		return err
	}
	return wr.EmergencyReparentShard(ctx, keyspace, shard, tabletAlias, *waitSlaveTimeout)
}
<commit_msg>tweak the error messages and comments for reparent commands<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

package vtctl

import (
	"flag"
	"fmt"
	"time"

	"github.com/youtube/vitess/go/vt/topo/topoproto"
	"github.com/youtube/vitess/go/vt/wrangler"
	"golang.org/x/net/context"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

var (
	// DisableActiveReparents is a flag to disable active
	// reparents for safety reasons. It is used in vtctld so it can be
	// exported to the UI (different package, that's why it's exported).
	// That way we can disable menu items there, using features.
	DisableActiveReparents = flag.Bool("disable_active_reparents", false, "if set, do not allow active reparents. Use this to protect a cluster using external reparents.")
)

func init() {
	addCommand("Tablets", command{
		"ReparentTablet",
		commandReparentTablet,
		"<tablet alias>",
		"Reparent a tablet to the current master in the shard. This only works if the current slave position matches the last known reparent action."})

	addCommand("Shards", command{
		"InitShardMaster",
		commandInitShardMaster,
		"[-force] [-wait_slave_timeout=<duration>] <keyspace/shard> <tablet alias>",
		"Sets the initial master for a shard. Will make all other tablets in the shard slaves of the provided master. WARNING: this could cause data loss on an already replicating shard. PlannedReparentShard or EmergencyReparentShard should be used instead."})
	addCommand("Shards", command{
		"PlannedReparentShard",
		commandPlannedReparentShard,
		"-keyspace_shard=<keyspace/shard> [-new_master=<tablet alias>] [-avoid_master=<tablet alias>]",
		"Reparents the shard to the new master, or away from old master. Both old and new master need to be up and running."})
	addCommand("Shards", command{
		"EmergencyReparentShard",
		commandEmergencyReparentShard,
		"-keyspace_shard=<keyspace/shard> -new_master=<tablet alias>",
		"Reparents the shard to the new master. Assumes the old master is dead and not responsding."})
}

func commandReparentTablet(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled (unset the -disable_active_reparents flag to enable)")
	}

	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() != 1 {
		return fmt.Errorf("action ReparentTablet requires <tablet alias>")
	}
	tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(0))
	if err != nil {
		return err
	}
	return wr.ReparentTablet(ctx, tabletAlias)
}

func commandInitShardMaster(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled (unset the -disable_active_reparents flag to enable)")
	}

	force := subFlags.Bool("force", false, "will force the reparent even if the provided tablet is not a master or the shard master")
	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() != 2 {
		return fmt.Errorf("action InitShardMaster requires <keyspace/shard> <tablet alias>")
	}
	keyspace, shard, err := topoproto.ParseKeyspaceShard(subFlags.Arg(0))
	if err != nil {
		return err
	}
	tabletAlias, err := topoproto.ParseTabletAlias(subFlags.Arg(1))
	if err != nil {
		return err
	}
	return wr.InitShardMaster(ctx, keyspace, shard, tabletAlias, *force, *waitSlaveTimeout)
}

func commandPlannedReparentShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled (unset the -disable_active_reparents flag to enable)")
	}

	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	keyspaceShard := subFlags.String("keyspace_shard", "", "keyspace/shard of the shard that needs to be reparented")
	newMaster := subFlags.String("new_master", "", "alias of a tablet that should be the new master")
	avoidMaster := subFlags.String("avoid_master", "", "alias of a tablet that should not be the master, i.e. reparent to any other tablet if this one is the master")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() == 2 {
		// Legacy syntax: "<keyspace/shard> <tablet alias>".
		if *keyspaceShard != "" || *newMaster != "" {
			return fmt.Errorf("cannot use legacy syntax and flags -keyspace_shard and -new_master for action PlannedReparentShard at the same time")
		}
		*keyspaceShard = subFlags.Arg(0)
		*newMaster = subFlags.Arg(1)
	} else if subFlags.NArg() != 0 {
		return fmt.Errorf("action PlannedReparentShard requires -keyspace_shard=<keyspace/shard> [-new_master=<tablet alias>] [-avoid_master=<tablet alias>]")
	}

	keyspace, shard, err := topoproto.ParseKeyspaceShard(*keyspaceShard)
	if err != nil {
		return err
	}
	var newMasterAlias, avoidMasterAlias *topodatapb.TabletAlias
	if *newMaster != "" {
		newMasterAlias, err = topoproto.ParseTabletAlias(*newMaster)
		if err != nil {
			return err
		}
	}
	if *avoidMaster != "" {
		avoidMasterAlias, err = topoproto.ParseTabletAlias(*avoidMaster)
		if err != nil {
			return err
		}
	}
	return wr.PlannedReparentShard(ctx, keyspace, shard, newMasterAlias, avoidMasterAlias, *waitSlaveTimeout)
}

func commandEmergencyReparentShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
	if *DisableActiveReparents {
		return fmt.Errorf("active reparent commands disabled (unset the -disable_active_reparents flag to enable)")
	}

	waitSlaveTimeout := subFlags.Duration("wait_slave_timeout", 30*time.Second, "time to wait for slaves to catch up in reparenting")
	keyspaceShard := subFlags.String("keyspace_shard", "", "keyspace/shard of the shard that needs to be reparented")
	newMaster := subFlags.String("new_master", "", "alias of a tablet that should be the new master")
	if err := subFlags.Parse(args); err != nil {
		return err
	}
	if subFlags.NArg() == 2 {
		// Legacy syntax: "<keyspace/shard> <tablet alias>".
		if *newMaster != "" {
			return fmt.Errorf("cannot use legacy syntax and flag -new_master for action EmergencyReparentShard at the same time")
		}
		*keyspaceShard = subFlags.Arg(0)
		*newMaster = subFlags.Arg(1)
	} else if subFlags.NArg() != 0 {
		return fmt.Errorf("action EmergencyReparentShard requires -keyspace_shard=<keyspace/shard> -new_master=<tablet alias>")
	}

	keyspace, shard, err := topoproto.ParseKeyspaceShard(*keyspaceShard)
	if err != nil {
		return err
	}
	tabletAlias, err := topoproto.ParseTabletAlias(*newMaster)
	if err != nil {
		return err
	}
	return wr.EmergencyReparentShard(ctx, keyspace, shard, tabletAlias, *waitSlaveTimeout)
}
<|endoftext|>


<commit_before>package goat

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync/atomic"
)

// HTTPConnHandler handles incoming HTTP (TCP) network connections
type HTTPConnHandler struct {
}

// Handle incoming HTTP connections and serve
func (h HTTPConnHandler) Handle(l net.Listener, httpDoneChan chan bool) {
	// Create shutdown function
	go func(l net.Listener, httpDoneChan chan bool) {
		// Wait for done signal
		Static.ShutdownChan <- <-Static.ShutdownChan

		// Close listener
		l.Close()
		httpDoneChan <- true
	}(l, httpDoneChan)

	// Add API route if configured
	if Static.Config.API {
		log.Println("API functionality enabled")
		http.HandleFunc("/api", parseAPI)
	}

	// Set up HTTP routes for handling functions
	http.HandleFunc("/", parseHTTP)

	// Serve HTTP requests
	http.Serve(l, nil)
}

// Parse incoming HTTP connections to API, before making API calls
func parseAPI(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Add header to identify goat and JSON response
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))
	w.Header().Add("Content-Type", "application/json")

	// Store current URL path
	url := r.URL.Path

	// Split URL into segments
	urlArr := strings.Split(url, "/")

	// If configured, Detect if client is making an API call
	fmt.Println(urlArr)
	url = urlArr[1]

	// Create channel to return response to client
	resChan := make(chan []byte)

	// Handle API calls
	go APIRouter(r, resChan)

	// Wait for response, and send it when ready
	w.Write(<-resChan)
	close(resChan)
	return
}

// Parse incoming HTTP connections before making tracker calls
func parseHTTP(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Parse querystring
	querystring := r.URL.Query()

	// Flatten arrays into single values
	query := map[string]string{}
	for k, v := range querystring {
		query[k] = v[0]
	}

	// Check if IP was previously set
	if _, ok := query["ip"]; !ok {
		// If no IP set, detect and store it in query map
		query["ip"] = strings.Split(r.RemoteAddr, ":")[0]
	}

	// Add header to identify goat
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))

	// Store current URL path
	url := r.URL.Path

	// Split URL into segments
	urlArr := strings.Split(url, "/")

	// Detect if passkey present in URL
	url = urlArr[1]
	var passkey string
	if len(urlArr) == 3 {
		passkey = urlArr[1]
		url = urlArr[2]
	}

	// Verify that torrent client is advertising its User-Agent, so we can use a whitelist
	if _, ok := r.Header["User-Agent"]; !ok {
		w.Write(HTTPTrackerError("Your client is not identifying itself"))
		return
	}

	client := r.Header["User-Agent"][0]

	// If configured, verify that torrent client is on whitelist
	if Static.Config.Whitelist {
		whitelist := new(WhitelistRecord).Load(client, "client")
		if whitelist == (WhitelistRecord{}) || !whitelist.Approved {
			w.Write(HTTPTrackerError("Your client is not whitelisted"))

			// Block things like browsers and web crawlers, because they will just clutter up the table
			if strings.Contains(client, "Mozilla") || strings.Contains(client, "Opera") {
				return
			}

			// Insert unknown clients into list for later approval
			if whitelist == (WhitelistRecord{}) {
				whitelist.Client = client
				whitelist.Approved = false

				log.Printf("whitelist: detected new client '%s', awaiting manual approval", client)

				go whitelist.Save()
			}

			return
		}
	}

	// Put client in query map
	query["client"] = client

	// Check if server is configured for passkey announce
	if Static.Config.Passkey && passkey == "" {
		w.Write(HTTPTrackerError("No passkey found in announce URL"))
		return
	}

	// Validate passkey if needed
	user := new(UserRecord).Load(passkey, "passkey")
	if Static.Config.Passkey && user == (UserRecord{}) {
		w.Write(HTTPTrackerError("Invalid passkey"))
		return
	}

	// Put passkey in query map
	query["passkey"] = user.Passkey

	// Mark client as HTTP
	query["udp"] = "0"

	// Create channel to return response to client
	resChan := make(chan []byte)

	// Handle tracker functions via different URLs
	switch url {
	// Tracker announce
	case "announce":
		// Validate required parameter input
		required := []string{"info_hash", "ip", "port", "uploaded", "downloaded", "left"}
		// Validate required integer input
		reqInt := []string{"port", "uploaded", "downloaded", "left"}

		// Check for required parameters
		for _, r := range required {
			if _, ok := query[r]; !ok {
				w.Write(HTTPTrackerError("Missing required parameter: " + r))
				close(resChan)
				return
			}
		}

		// Check for all valid integers
		for _, r := range reqInt {
			if _, ok := query[r]; ok {
				_, err := strconv.Atoi(query[r])
				if err != nil {
					w.Write(HTTPTrackerError("Invalid integer parameter: " + r))
					close(resChan)
					return
				}
			}
		}

		// Only allow compact announce
		if _, ok := query["compact"]; !ok || query["compact"] != "1" {
			w.Write(HTTPTrackerError("Your client does not support compact announce"))
			close(resChan)
			return
		}

		// Perform tracker announce
		go TrackerAnnounce(user, query, nil, resChan)
	// Tracker scrape
	case "scrape":
		go TrackerScrape(user, query, resChan)
	// Any undefined handlers
	default:
		w.Write(HTTPTrackerError("Malformed announce"))
		close(resChan)
		return
	}

	// Wait for response, and send it when ready
	w.Write(<-resChan)
	close(resChan)
	return
}
<commit_msg>Move API parsing section to allow more flexibility<commit_after>package goat

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync/atomic"
)

// HTTPConnHandler handles incoming HTTP (TCP) network connections
type HTTPConnHandler struct {
}

// Handle incoming HTTP connections and serve
func (h HTTPConnHandler) Handle(l net.Listener, httpDoneChan chan bool) {
	// Create shutdown function
	go func(l net.Listener, httpDoneChan chan bool) {
		// Wait for done signal
		Static.ShutdownChan <- <-Static.ShutdownChan

		// Close listener
		l.Close()
		httpDoneChan <- true
	}(l, httpDoneChan)

	// Log API configuration
	if Static.Config.API {
		log.Println("API functionality enabled")
	}

	// Set up HTTP routes for handling functions
	http.HandleFunc("/", parseHTTP)

	// Serve HTTP requests
	http.Serve(l, nil)
}

// Parse incoming HTTP connections to API, before making API calls
func parseAPI(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Add header to identify goat and JSON response
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))
}

// Parse incoming HTTP connections before making tracker calls
func parseHTTP(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Parse querystring
	querystring := r.URL.Query()

	// Flatten arrays into single values
	query := map[string]string{}
	for k, v := range querystring {
		query[k] = v[0]
	}

	// Check if IP was previously set
	if _, ok := query["ip"]; !ok {
		// If no IP set, detect and store it in query map
		query["ip"] = strings.Split(r.RemoteAddr, ":")[0]
	}

	// Add header to identify goat
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))

	// Create channel to return response to client
	resChan := make(chan []byte)

	// Store current URL path
	url := r.URL.Path

	// Split URL into segments
	urlArr := strings.Split(url, "/")

	// If configured, Detect if client is making an API call
	url = urlArr[1]
	if Static.Config.API && url == "api" {
		// Log API calls
		log.Printf("API: %s\n", r.URL.Path)

		// Handle API calls
		go APIRouter(r, resChan)

		// Wait for response, and send it when ready
		w.Write(<-resChan)
		close(resChan)
		return
	}

	// Detect if passkey present in URL
	var passkey string
	if len(urlArr) == 3 {
		passkey = urlArr[1]
		url = urlArr[2]
	}

	// Verify that torrent client is advertising its User-Agent, so we can use a whitelist
	if _, ok := r.Header["User-Agent"]; !ok {
		w.Write(HTTPTrackerError("Your client is not identifying itself"))
		return
	}

	client := r.Header["User-Agent"][0]

	// If configured, verify that torrent client is on whitelist
	if Static.Config.Whitelist {
		whitelist := new(WhitelistRecord).Load(client, "client")
		if whitelist == (WhitelistRecord{}) || !whitelist.Approved {
			w.Write(HTTPTrackerError("Your client is not whitelisted"))

			// Block things like browsers and web crawlers, because they will just clutter up the table
			if strings.Contains(client, "Mozilla") || strings.Contains(client, "Opera") {
				return
			}

			// Insert unknown clients into list for later approval
			if whitelist == (WhitelistRecord{}) {
				whitelist.Client = client
				whitelist.Approved = false

				log.Printf("whitelist: detected new client '%s', awaiting manual approval", client)

				go whitelist.Save()
			}

			return
		}
	}

	// Put client in query map
	query["client"] = client

	// Check if server is configured for passkey announce
	if Static.Config.Passkey && passkey == "" {
		w.Write(HTTPTrackerError("No passkey found in announce URL"))
		return
	}

	// Validate passkey if needed
	user := new(UserRecord).Load(passkey, "passkey")
	if Static.Config.Passkey && user == (UserRecord{}) {
		w.Write(HTTPTrackerError("Invalid passkey"))
		return
	}

	// Put passkey in query map
	query["passkey"] = user.Passkey

	// Mark client as HTTP
	query["udp"] = "0"

	// Handle tracker functions via different URLs
	switch url {
	// Tracker announce
	case "announce":
		// Validate required parameter input
		required := []string{"info_hash", "ip", "port", "uploaded", "downloaded", "left"}
		// Validate required integer input
		reqInt := []string{"port", "uploaded", "downloaded", "left"}

		// Check for required parameters
		for _, r := range required {
			if _, ok := query[r]; !ok {
				w.Write(HTTPTrackerError("Missing required parameter: " + r))
				close(resChan)
				return
			}
		}

		// Check for all valid integers
		for _, r := range reqInt {
			if _, ok := query[r]; ok {
				_, err := strconv.Atoi(query[r])
				if err != nil {
					w.Write(HTTPTrackerError("Invalid integer parameter: " + r))
					close(resChan)
					return
				}
			}
		}

		// Only allow compact announce
		if _, ok := query["compact"]; !ok || query["compact"] != "1" {
			w.Write(HTTPTrackerError("Your client does not support compact announce"))
			close(resChan)
			return
		}

		// Perform tracker announce
		go TrackerAnnounce(user, query, nil, resChan)
	// Tracker scrape
	case "scrape":
		go TrackerScrape(user, query, resChan)
	// Any undefined handlers
	default:
		w.Write(HTTPTrackerError("Malformed announce"))
		close(resChan)
		return
	}

	// Wait for response, and send it when ready
	w.Write(<-resChan)
	close(resChan)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)
import (
	"runtime/pprof"
	"runtime"
	"flag"
)

func main() {
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	commandtype := flag.String("type", "", "server or client")
	service := flag.String("service", "", "like :8080")
	times := flag.Int("times", 1, "client exec times")
	flag.Parse()
	runtime.SetBlockProfileRate(1)
	log.Println(*cpuprofile)
	if *cpuprofile != "" {
		log.Println("cpuprofiling")
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if *commandtype == "client" {
		client(*service, *times)
	} else if *commandtype == "server" {
		server(*service)
	} else {
		log.Fatal("not exists type: " + *commandtype)
		log.Fatal(flag.Usage)
	}
}

func dieIfError(err error) {
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
}

func client(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	dieIfError(err)
	for i := 0; i < times; i++ {
		conn, err := net.DialTCP("tcp", nil, tcpAddr)
		dieIfError(err)
		_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
		dieIfError(err)
		result, err := ioutil.ReadAll(conn)
		dieIfError(err)
		log.Println(string(result))
	}
}

func server(service string) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	dieIfError(err)
	listener, err := net.ListenTCP("tcp", tcpAddr)
	dieIfError(err)
	count := 0
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		count += 1
		responce(conn, count)
		if count == 10 {
			return
		}
	}

}

func responce(conn net.Conn, count int) {
	defer conn.Close()
	now := time.Now().String()
	log.Println(strconv.Itoa(count) + " Access come !")
	conn.Write([]byte(now))
}
<commit_msg>server側もlimitを指定できるように<commit_after>package main

import (
	"io/ioutil"
	"log"
	"net"
	"os"
	"strconv"
	"time"
)
import (
	"runtime/pprof"
	"runtime"
	"flag"
)

func main() {
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	commandtype := flag.String("type", "", "server or client")
	service := flag.String("service", "", "like :8080")
	times := flag.Int("times", 1, "client exec times")
	flag.Parse()
	runtime.SetBlockProfileRate(1)
	log.Println(*cpuprofile)
	if *cpuprofile != "" {
		log.Println("cpuprofiling")
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if *commandtype == "client" {
		client(*service, *times)
	} else if *commandtype == "server" {
		server(*service, *times)
	} else {
		log.Fatal("not exists type: " + *commandtype)
		log.Fatal(flag.Usage)
	}
}

func dieIfError(err error) {
	if err != nil {
		log.Fatal("Fatal error: %s", err.Error())
	}
}

func client(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	dieIfError(err)
	for i := 0; i < times; i++ {
		conn, err := net.DialTCP("tcp", nil, tcpAddr)
		dieIfError(err)
		_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
		dieIfError(err)
		result, err := ioutil.ReadAll(conn)
		dieIfError(err)
		log.Println(string(result))
	}
}

func server(service string, times int) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	dieIfError(err)
	listener, err := net.ListenTCP("tcp", tcpAddr)
	dieIfError(err)
	count := 0
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		count += 1
		responce(conn, count)
		if count == times {
			return
		}
	}

}

func responce(conn net.Conn, count int) {
	defer conn.Close()
	now := time.Now().String()
	log.Println(strconv.Itoa(count) + " Access come !")
	conn.Write([]byte(now))
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"regexp"
)

const (
	globalLinkTemplate             = "projects/%s/global/%s/%s"
	globalLinkBasePattern          = "projects/(.+)/global/%s/(.+)"
	zonalLinkTemplate              = "projects/%s/zones/%s/%s/%s"
	zonalLinkBasePattern           = "projects/(.+)/zones/(.+)/%s/(.+)"
	zonalPartialLinkBasePattern    = "zones/(.+)/%s/(.+)"
	regionalLinkTemplate           = "projects/%s/regions/%s/%s/%s"
	regionalLinkBasePattern        = "projects/(.+)/regions/(.+)/%s/(.+)"
	regionalPartialLinkBasePattern = "regions/(.+)/%s/(.+)"
	organizationLinkTemplate       = "organizations/%s/%s/%s"
	organizationBasePattern        = "organizations/(.+)/%s/(.+)"
)

// ------------------------------------------------------------
// Field helpers
// ------------------------------------------------------------

func ParseNetworkFieldValue(network string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("networks", network, "project", d, config, true)
}

func ParseSubnetworkFieldValue(subnetwork string, d TerraformResourceData, config *Config) (*RegionalFieldValue, error) {
	return parseRegionalFieldValue("subnetworks", subnetwork, "project", "region", "zone", d, config, true)
}

func ParseSubnetworkFieldValueWithProjectField(subnetwork, projectField string, d TerraformResourceData, config *Config) (*RegionalFieldValue, error) {
	return parseRegionalFieldValue("subnetworks", subnetwork, projectField, "region", "zone", d, config, true)
}

func ParseSslCertificateFieldValue(sslCertificate string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("sslCertificates", sslCertificate, "project", d, config, false)
}

func ParseHttpHealthCheckFieldValue(healthCheck string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("httpHealthChecks", healthCheck, "project", d, config, false)
}

func ParseDiskFieldValue(disk string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("disks", disk, "project", "zone", d, config, false)
}

func ParseOrganizationCustomRoleName(role string) (*OrganizationFieldValue, error) {
	return parseOrganizationFieldValue("roles", role, false)
}

func ParseAcceleratorFieldValue(accelerator string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("acceleratorTypes", accelerator, "project", "zone", d, config, false)
}

func ParseMachineTypesFieldValue(machineType string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("machineTypes", machineType, "project", "zone", d, config, false)
}

func ParseInstanceGroupFieldValue(instanceGroup string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("instanceGroups", instanceGroup, "project", "zone", d, config, false)
}

func ParseSecurityPolicyFieldValue(securityPolicy string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("securityPolicies", securityPolicy, "project", d, config, true)
}

// ------------------------------------------------------------
// Base helpers used to create helpers for specific fields.
// ------------------------------------------------------------

type GlobalFieldValue struct {
	Project string
	Name    string

	resourceType string
}

func (f GlobalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(globalLinkTemplate, f.Project, f.resourceType, f.Name)
}

// Parses a global field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/global/{resource_type}/{resource_name}
// - projects/{my_project}/global/{resource_type}/{resource_name}
// - global/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
func parseGlobalFieldValue(resourceType, fieldValue, projectSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*GlobalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &GlobalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The global field for resource %s cannot be empty", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(globalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &GlobalFieldValue{
			Project: parts[1],
			Name:    parts[2],

			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	return &GlobalFieldValue{
		Project: project,
		Name:    GetResourceNameFromSelfLink(fieldValue),

		resourceType: resourceType,
	}, nil
}

type ZonalFieldValue struct {
	Project string
	Zone    string
	Name    string

	resourceType string
}

func (f ZonalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(zonalLinkTemplate, f.Project, f.Zone, f.resourceType, f.Name)
}

// Parses a zonal field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - zones/{zone}/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
// If the zone is not specified, it takes the value of `zoneSchemaField`.
func parseZonalFieldValue(resourceType, fieldValue, projectSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*ZonalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &ZonalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The zonal field for resource %s cannot be empty.", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(zonalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &ZonalFieldValue{
			Project:      parts[1],
			Zone:         parts[2],
			Name:         parts[3],
			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	r = regexp.MustCompile(fmt.Sprintf(zonalPartialLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &ZonalFieldValue{
			Project:      project,
			Zone:         parts[1],
			Name:         parts[2],
			resourceType: resourceType,
		}, nil
	}

	if len(zoneSchemaField) == 0 {
		return nil, fmt.Errorf("Invalid field format. Got '%s', expected format '%s'", fieldValue, fmt.Sprintf(globalLinkTemplate, "{project}", resourceType, "{name}"))
	}

	zone, ok := d.GetOk(zoneSchemaField)
	if !ok {
		return nil, fmt.Errorf("A zone must be specified")
	}

	return &ZonalFieldValue{
		Project:      project,
		Zone:         zone.(string),
		Name:         GetResourceNameFromSelfLink(fieldValue),
		resourceType: resourceType,
	}, nil
}

func getProjectFromSchema(projectSchemaField string, d TerraformResourceData, config *Config) (string, error) {
	res, ok := d.GetOk(projectSchemaField)
	if ok && projectSchemaField != "" {
		return res.(string), nil
	}
	if config.Project != "" {
		return config.Project, nil
	}
	return "", fmt.Errorf("%s: required field is not set", projectSchemaField)
}

type OrganizationFieldValue struct {
	OrgId string
	Name  string

	resourceType string
}

func (f OrganizationFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(organizationLinkTemplate, f.OrgId, f.resourceType, f.Name)
}

// Parses an organization field with the following formats:
// - organizations/{my_organizations}/{resource_type}/{resource_name}
func parseOrganizationFieldValue(resourceType, fieldValue string, isEmptyValid bool) (*OrganizationFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &OrganizationFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The organization field for resource %s cannot be empty", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(organizationBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &OrganizationFieldValue{
			OrgId: parts[1],
			Name:  parts[2],

			resourceType: resourceType,
		}, nil
	}

	return nil, fmt.Errorf("Invalid field format. Got '%s', expected format '%s'", fieldValue, fmt.Sprintf(organizationLinkTemplate, "{org_id}", resourceType, "{name}"))
}

type RegionalFieldValue struct {
	Project string
	Region  string
	Name    string

	resourceType string
}

func (f RegionalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(regionalLinkTemplate, f.Project, f.Region, f.resourceType, f.Name)
}

// Parses a regional field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/regions/{region}/{resource_type}/{resource_name}
// - projects/{my_project}/regions/{region}/{resource_type}/{resource_name}
// - regions/{region}/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
// If the region is not specified, see function documentation for `getRegionFromSchema`.
func parseRegionalFieldValue(resourceType, fieldValue, projectSchemaField, regionSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*RegionalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &RegionalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The regional field for resource %s cannot be empty.", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(regionalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &RegionalFieldValue{
			Project:      parts[1],
			Region:       parts[2],
			Name:         parts[3],
			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	r = regexp.MustCompile(fmt.Sprintf(regionalPartialLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &RegionalFieldValue{
			Project:      project,
			Region:       parts[1],
			Name:         parts[2],
			resourceType: resourceType,
		}, nil
	}

	region, err := getRegionFromSchema(regionSchemaField, zoneSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	return &RegionalFieldValue{
		Project:      project,
		Region:       region,
		Name:         GetResourceNameFromSelfLink(fieldValue),
		resourceType: resourceType,
	}, nil
}

// Infers the region based on the following (in order of priority):
// - `regionSchemaField` in resource schema
// - region extracted from the `zoneSchemaField` in resource schema
// - provider-level region
// - region extracted from the provider-level zone
func getRegionFromSchema(regionSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config) (string, error) {
	if v, ok := d.GetOk(regionSchemaField); ok && regionSchemaField != "" {
		return GetResourceNameFromSelfLink(v.(string)), nil
	}
	if v, ok := d.GetOk(zoneSchemaField); ok && zoneSchemaField != "" {
		return getRegionFromZone(v.(string)), nil
	}
	if config.Region != "" {
		return config.Region, nil
	}
	if config.Zone != "" {
		return getRegionFromZone(config.Zone), nil
	}

	return "", fmt.Errorf("Cannot determine region: set in this resource, or set provider-level 'region' or 'zone'.")
}
<commit_msg>Check provider level zone as well when parsing zonal values. (#1455)<commit_after>package google

import (
	"fmt"
	"regexp"
)

const (
	globalLinkTemplate             = "projects/%s/global/%s/%s"
	globalLinkBasePattern          = "projects/(.+)/global/%s/(.+)"
	zonalLinkTemplate              = "projects/%s/zones/%s/%s/%s"
	zonalLinkBasePattern           = "projects/(.+)/zones/(.+)/%s/(.+)"
	zonalPartialLinkBasePattern    = "zones/(.+)/%s/(.+)"
	regionalLinkTemplate           = "projects/%s/regions/%s/%s/%s"
	regionalLinkBasePattern        = "projects/(.+)/regions/(.+)/%s/(.+)"
	regionalPartialLinkBasePattern = "regions/(.+)/%s/(.+)"
	organizationLinkTemplate       = "organizations/%s/%s/%s"
	organizationBasePattern        = "organizations/(.+)/%s/(.+)"
)

// ------------------------------------------------------------
// Field helpers
// ------------------------------------------------------------

func ParseNetworkFieldValue(network string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("networks", network, "project", d, config, true)
}

func ParseSubnetworkFieldValue(subnetwork string, d TerraformResourceData, config *Config) (*RegionalFieldValue, error) {
	return parseRegionalFieldValue("subnetworks", subnetwork, "project", "region", "zone", d, config, true)
}

func ParseSubnetworkFieldValueWithProjectField(subnetwork, projectField string, d TerraformResourceData, config *Config) (*RegionalFieldValue, error) {
	return parseRegionalFieldValue("subnetworks", subnetwork, projectField, "region", "zone", d, config, true)
}

func ParseSslCertificateFieldValue(sslCertificate string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("sslCertificates", sslCertificate, "project", d, config, false)
}

func ParseHttpHealthCheckFieldValue(healthCheck string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("httpHealthChecks", healthCheck, "project", d, config, false)
}

func ParseDiskFieldValue(disk string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("disks", disk, "project", "zone", d, config, false)
}

func ParseOrganizationCustomRoleName(role string) (*OrganizationFieldValue, error) {
	return parseOrganizationFieldValue("roles", role, false)
}

func ParseAcceleratorFieldValue(accelerator string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("acceleratorTypes", accelerator, "project", "zone", d, config, false)
}

func ParseMachineTypesFieldValue(machineType string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("machineTypes", machineType, "project", "zone", d, config, false)
}

func ParseInstanceGroupFieldValue(instanceGroup string, d TerraformResourceData, config *Config) (*ZonalFieldValue, error) {
	return parseZonalFieldValue("instanceGroups", instanceGroup, "project", "zone", d, config, false)
}

func ParseSecurityPolicyFieldValue(securityPolicy string, d TerraformResourceData, config *Config) (*GlobalFieldValue, error) {
	return parseGlobalFieldValue("securityPolicies", securityPolicy, "project", d, config, true)
}

// ------------------------------------------------------------
// Base helpers used to create helpers for specific fields.
// ------------------------------------------------------------

type GlobalFieldValue struct {
	Project string
	Name    string

	resourceType string
}

func (f GlobalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(globalLinkTemplate, f.Project, f.resourceType, f.Name)
}

// Parses a global field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/global/{resource_type}/{resource_name}
// - projects/{my_project}/global/{resource_type}/{resource_name}
// - global/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
func parseGlobalFieldValue(resourceType, fieldValue, projectSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*GlobalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &GlobalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The global field for resource %s cannot be empty", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(globalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &GlobalFieldValue{
			Project: parts[1],
			Name:    parts[2],

			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	return &GlobalFieldValue{
		Project: project,
		Name:    GetResourceNameFromSelfLink(fieldValue),

		resourceType: resourceType,
	}, nil
}

type ZonalFieldValue struct {
	Project string
	Zone    string
	Name    string

	resourceType string
}

func (f ZonalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(zonalLinkTemplate, f.Project, f.Zone, f.resourceType, f.Name)
}

// Parses a zonal field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - zones/{zone}/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
// If the zone is not specified, it takes the value of `zoneSchemaField`.
func parseZonalFieldValue(resourceType, fieldValue, projectSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*ZonalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &ZonalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The zonal field for resource %s cannot be empty.", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(zonalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &ZonalFieldValue{
			Project:      parts[1],
			Zone:         parts[2],
			Name:         parts[3],
			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	r = regexp.MustCompile(fmt.Sprintf(zonalPartialLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &ZonalFieldValue{
			Project:      project,
			Zone:         parts[1],
			Name:         parts[2],
			resourceType: resourceType,
		}, nil
	}

	if len(zoneSchemaField) == 0 {
		return nil, fmt.Errorf("Invalid field format. Got '%s', expected format '%s'", fieldValue, fmt.Sprintf(globalLinkTemplate, "{project}", resourceType, "{name}"))
	}

	zone, ok := d.GetOk(zoneSchemaField)
	if !ok {
		zone = config.Zone
		if zone == "" {
			return nil, fmt.Errorf("A zone must be specified")
		}
	}

	return &ZonalFieldValue{
		Project:      project,
		Zone:         zone.(string),
		Name:         GetResourceNameFromSelfLink(fieldValue),
		resourceType: resourceType,
	}, nil
}

func getProjectFromSchema(projectSchemaField string, d TerraformResourceData, config *Config) (string, error) {
	res, ok := d.GetOk(projectSchemaField)
	if ok && projectSchemaField != "" {
		return res.(string), nil
	}
	if config.Project != "" {
		return config.Project, nil
	}
	return "", fmt.Errorf("%s: required field is not set", projectSchemaField)
}

type OrganizationFieldValue struct {
	OrgId string
	Name  string

	resourceType string
}

func (f OrganizationFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(organizationLinkTemplate, f.OrgId, f.resourceType, f.Name)
}

// Parses an organization field with the following formats:
// - organizations/{my_organizations}/{resource_type}/{resource_name}
func parseOrganizationFieldValue(resourceType, fieldValue string, isEmptyValid bool) (*OrganizationFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &OrganizationFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The organization field for resource %s cannot be empty", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(organizationBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &OrganizationFieldValue{
			OrgId: parts[1],
			Name:  parts[2],

			resourceType: resourceType,
		}, nil
	}

	return nil, fmt.Errorf("Invalid field format. Got '%s', expected format '%s'", fieldValue, fmt.Sprintf(organizationLinkTemplate, "{org_id}", resourceType, "{name}"))
}

type RegionalFieldValue struct {
	Project string
	Region  string
	Name    string

	resourceType string
}

func (f RegionalFieldValue) RelativeLink() string {
	if len(f.Name) == 0 {
		return ""
	}

	return fmt.Sprintf(regionalLinkTemplate, f.Project, f.Region, f.resourceType, f.Name)
}

// Parses a regional field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/regions/{region}/{resource_type}/{resource_name}
// - projects/{my_project}/regions/{region}/{resource_type}/{resource_name}
// - regions/{region}/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
// If the region is not specified, see function documentation for `getRegionFromSchema`.
func parseRegionalFieldValue(resourceType, fieldValue, projectSchemaField, regionSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config, isEmptyValid bool) (*RegionalFieldValue, error) {
	if len(fieldValue) == 0 {
		if isEmptyValid {
			return &RegionalFieldValue{resourceType: resourceType}, nil
		}
		return nil, fmt.Errorf("The regional field for resource %s cannot be empty.", resourceType)
	}

	r := regexp.MustCompile(fmt.Sprintf(regionalLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &RegionalFieldValue{
			Project:      parts[1],
			Region:       parts[2],
			Name:         parts[3],
			resourceType: resourceType,
		}, nil
	}

	project, err := getProjectFromSchema(projectSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	r = regexp.MustCompile(fmt.Sprintf(regionalPartialLinkBasePattern, resourceType))
	if parts := r.FindStringSubmatch(fieldValue); parts != nil {
		return &RegionalFieldValue{
			Project:      project,
			Region:       parts[1],
			Name:         parts[2],
			resourceType: resourceType,
		}, nil
	}

	region, err := getRegionFromSchema(regionSchemaField, zoneSchemaField, d, config)
	if err != nil {
		return nil, err
	}

	return &RegionalFieldValue{
		Project:      project,
		Region:       region,
		Name:         GetResourceNameFromSelfLink(fieldValue),
		resourceType: resourceType,
	}, nil
}

// Infers the region based on the following (in order of priority):
// - `regionSchemaField` in resource schema
// - region extracted from the `zoneSchemaField` in resource schema
// - provider-level region
// - region extracted from the provider-level zone
func getRegionFromSchema(regionSchemaField, zoneSchemaField string, d TerraformResourceData, config *Config) (string, error) {
	if v, ok := d.GetOk(regionSchemaField); ok && regionSchemaField != "" {
		return GetResourceNameFromSelfLink(v.(string)), nil
	}
	if v, ok := d.GetOk(zoneSchemaField); ok && zoneSchemaField != "" {
		return getRegionFromZone(v.(string)), nil
	}
	if config.Region != "" {
		return config.Region, nil
	}
	if config.Zone != "" {
		return getRegionFromZone(config.Zone), nil
	}

	return "", fmt.Errorf("Cannot determine region: set in this resource, or set provider-level 'region' or 'zone'.")
}
<|endoftext|>


<commit_before>package command

import (
	"strings"
	"os"
	"log"
	"fmt"
	"github.com/wantedly/developers-account-mapper/store"
	"github.com/wantedly/developers-account-mapper/models"
)

type RegisterCommand struct {
	Meta
}

func (c *RegisterCommand) Run(args []string) int {
	var loginName, githubUsername, slackUsername string
	if len(args) == 2 {
		loginName = os.Getenv("USER")
		githubUsername = args[0]
		slackUsername  = args[1]
	} else if len(args) == 3 {
		loginName = args[0]
		githubUsername = args[1]
		slackUsername = args[2]
	} else {
		log.Println(c.Help())
		return 1
	}

	s := store.NewDynamoDB()

	user := models.NewUser(loginName, githubUsername, slackUsername, "")
	user, err := user.RetrieveSlackUserId()
	if err != nil {
		log.Println(err)
		return 1
	}
	if err := s.AddUser(user); err != nil {
		log.Println(err)
		return 1
	}
	fmt.Printf("user %q added.\n", user)

	return 0
}

func (c *RegisterCommand) Synopsis() string {
	return "Register LoginName and GitHubUsername mapping"
}

func (c *RegisterCommand) Help() string {
	helpText := `

`
	return strings.TrimSpace(helpText)
}
<commit_msg>Add line between built-in packages and third-party ones<commit_after>package command

import (
	"strings"
	"os"
	"log"
	"fmt"

	"github.com/wantedly/developers-account-mapper/store"
	"github.com/wantedly/developers-account-mapper/models"
)

type RegisterCommand struct {
	Meta
}

func (c *RegisterCommand) Run(args []string) int {
	var loginName, githubUsername, slackUsername string
	if len(args) == 2 {
		loginName = os.Getenv("USER")
		githubUsername = args[0]
		slackUsername  = args[1]
	} else if len(args) == 3 {
		loginName = args[0]
		githubUsername = args[1]
		slackUsername = args[2]
	} else {
		log.Println(c.Help())
		return 1
	}

	s := store.NewDynamoDB()

	user := models.NewUser(loginName, githubUsername, slackUsername, "")
	user, err := user.RetrieveSlackUserId()
	if err != nil {
		log.Println(err)
		return 1
	}
	if err := s.AddUser(user); err != nil {
		log.Println(err)
		return 1
	}
	fmt.Printf("user %q added.\n", user)

	return 0
}

func (c *RegisterCommand) Synopsis() string {
	return "Register LoginName and GitHubUsername mapping"
}

func (c *RegisterCommand) Help() string {
	helpText := `

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>package gotumblr

import "encoding/json"

type taggedResponse struct {
	[]json.RawMessage
}<commit_msg>Remove tagged_response.go<commit_after><|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fs_test

import (
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestFileSystemTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// ReadDir
////////////////////////////////////////////////////////////////////////

type ReadDirTest struct {
}

func init() { RegisterTestSuite(&ReadDirTest{}) }

func (t *ReadDirTest) NonExistentPath() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) NotADirectory() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) NoReadPermissions() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) RegularFiles() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) Directories() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) Symlinks() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// OpenForReading
////////////////////////////////////////////////////////////////////////

type OpenForReadingTest struct {
}

func init() { RegisterTestSuite(&OpenForReadingTest{}) }

func (t *OpenForReadingTest) NonExistentFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) NotAFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) NoReadPermissions() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) EmptyFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) FileWithContents() {
	ExpectEq("TODO", "")
}
<commit_msg>Added SetUp and TearDown.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fs_test

import (
	. "github.com/jacobsa/ogletest"
	"io/ioutil"
	"log"
	"os"
	"testing"
)

func TestFileSystemTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// ReadDir
////////////////////////////////////////////////////////////////////////

type ReadDirTest struct {
	baseDir string
}

func init() { RegisterTestSuite(&ReadDirTest{}) }

func (t *ReadDirTest) SetUp(i *TestInfo) {
	var err error
	t.baseDir, err = ioutil.TempDir("", "ReadDirTest_")
	if err != nil {
		log.Fatalf("Creating baseDir: %v", err)
	}
}

func (t *ReadDirTest) TearDown() {
	err := os.RemoveAll(t.baseDir)
	if err != nil {
		log.Fatalf("Couldn't remove: %s", t.baseDir)
	}
}

func (t *ReadDirTest) NonExistentPath() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) NotADirectory() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) NoReadPermissions() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) RegularFiles() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) Directories() {
	ExpectEq("TODO", "")
}

func (t *ReadDirTest) Symlinks() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// OpenForReading
////////////////////////////////////////////////////////////////////////

type OpenForReadingTest struct {
}

func init() { RegisterTestSuite(&OpenForReadingTest{}) }

func (t *OpenForReadingTest) NonExistentFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) NotAFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) NoReadPermissions() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) EmptyFile() {
	ExpectEq("TODO", "")
}

func (t *OpenForReadingTest) FileWithContents() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package bitcoind

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
)

const (
	// VERSION represents bicoind package version
	VERSION = 0.1
	// DEFAULT_RPCCLIENT_TIMEOUT represent http timeout for rcp client
	RPCCLIENT_TIMEOUT = 30
)

// A bitpay represents a bitpay client wrapper
type bitcoind struct {
	client *rpcClient
}

// New return a new bitcoind
func New(host string, port int, user, passwd string, useSSL bool) (*bitcoind, error) {
	rpcClient, err := newClient(host, port, user, passwd, useSSL)
	if err != nil {
		return nil, err
	}
	return &bitcoind{rpcClient}, nil
}

// BackupWallet Safely copies wallet.dat to destination,
// which can be a directory or a path with filename on the remote server
func (b *bitcoind) BackupWallet(destination string) error {
	r, err := b.client.call("backupwallet", []string{destination})
	return handleError(err, &r)
}

// DumpPrivKey return private key as string associated to public <address>
func (b *bitcoind) DumpPrivKey(address string) (privKey string, err error) {
	r, err := b.client.call("dumpprivkey", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &privKey)
	return
}

// EncryptWallet encrypts the wallet with <passphrase>.
func (b *bitcoind) EncryptWallet(passphrase string) error {
	r, err := b.client.call("encryptwallet", []string{passphrase})
	return handleError(err, &r)
}

// GetAccount returns the account associated with the given address.
func (b *bitcoind) GetAccount(address string) (account string, err error) {
	r, err := b.client.call("getaccount", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	account = string(r.Result)
	return
}

// GetAccountAddress Returns the current bitcoin address for receiving
// payments to this account.
// If account does not exist, it will be created along with an
// associated new address that will be returned.
func (b *bitcoind) GetAccountAddress(account string) (address string, err error) {
	r, err := b.client.call("getaccountaddress", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	address = string(r.Result)
	return
}

// GetBalance return the balance of the server or of a specific account
//If [account] is "", returns the server's total available balance.
//If [account] is specified, returns the balance in the account
func (b *bitcoind) GetBalance(account string, minconf uint64) (balance float64, err error) {
	r, err := b.client.call("getbalance", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	balance, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetBestBlockhash returns the hash of the best (tip) block in the longest block chain.
func (b *bitcoind) GetBestBlockhash() (bestBlockHash string, err error) {
	r, err := b.client.call("getbestblockhash", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	bestBlockHash = string(r.Result)
	return
}

// GetBlock returns information about the block with the given hash.
func (b *bitcoind) GetBlock(blockHash string) (block block, err error) {
	r, err := b.client.call("getblock", []string{blockHash})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &block)
	return
}

// GetBlockCount returns the number of blocks in the longest block chain.
func (b *bitcoind) GetBlockCount() (count uint64, err error) {
	r, err := b.client.call("getblockcount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetBlockHash returns hash of block in best-block-chain at <index>
func (b *bitcoind) GetBlockHash(index uint64) (hash string, err error) {
	r, err := b.client.call("getblockhash", []uint64{index})
	if err = handleError(err, &r); err != nil {
		return
	}
	hash = string(r.Result)
	return
}

// getBlockTemplateParams reperesent parameters for GetBlockTemplate
type getBlockTemplateParams struct {
	Mode         string   `json:"mode,omitempty"`
	Capabilities []string `json:"capabilities,omitempty"`
}

// TODO a finir
// GetBlockTemplate Returns data needed to construct a block to work on.
// See BIP_0022 for more info on params.
func (b *bitcoind) GetBlockTemplate(capabilities []string, mode string) (template string, err error) {
	params := getBlockTemplateParams{
		Mode:         mode,
		Capabilities: capabilities,
	}
	// TODO []interface{}{mode, capa}
	r, err := b.client.call("getblocktemplate", []getBlockTemplateParams{params})
	if err = handleError(err, &r); err != nil {
		return
	}
	fmt.Println(string(r.Result))
	return
}

// GetConnectionCount returns the number of connections to other nodes.
func (b *bitcoind) GetConnectionCount() (count uint64, err error) {
	r, err := b.client.call("getconnectioncount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetDifficulty returns the proof-of-work difficulty as a multiple of
// the minimum difficulty.
func (b *bitcoind) GetDifficulty() (difficulty float64, err error) {
	r, err := b.client.call("getdifficulty", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	difficulty, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetInfo return result of "getinfo" command (Amazing !)
func (b *bitcoind) GetInfo() (i info, err error) {
	r, err := b.client.call("getinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &i)
	return
}

// GetNewAddress return a new address for account [account].
func (b *bitcoind) GetNewAddress(account ...string) (addr string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetNewAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getnewaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	addr = string(r.Result)
	return
}

// GetAddressesByAccount return addresses associated with account <account>
func (b *bitcoind) GetAddressesByAccount(account string) (addresses []string, err error) {
	r, err := b.client.call("getaddressesbyaccount", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addresses)
	return
}

// walletPassphrase stores the wallet decryption key in memory for <timeout> seconds.
func (b *bitcoind) WalletPassphrase(passPhrase string, timeout uint64) error {
	r, err := b.client.call("walletpassphrase", []interface{}{passPhrase, timeout})
	return handleError(err, &r)
}
<commit_msg>bugfix<commit_after>package bitcoind

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
)

const (
	// VERSION represents bicoind package version
	VERSION = 0.1
	// DEFAULT_RPCCLIENT_TIMEOUT represent http timeout for rcp client
	RPCCLIENT_TIMEOUT = 30
)

// A bitpay represents a bitpay client wrapper
type bitcoind struct {
	client *rpcClient
}

// New return a new bitcoind
func New(host string, port int, user, passwd string, useSSL bool) (*bitcoind, error) {
	rpcClient, err := newClient(host, port, user, passwd, useSSL)
	if err != nil {
		return nil, err
	}
	return &bitcoind{rpcClient}, nil
}

// BackupWallet Safely copies wallet.dat to destination,
// which can be a directory or a path with filename on the remote server
func (b *bitcoind) BackupWallet(destination string) error {
	r, err := b.client.call("backupwallet", []string{destination})
	return handleError(err, &r)
}

// DumpPrivKey return private key as string associated to public <address>
func (b *bitcoind) DumpPrivKey(address string) (privKey string, err error) {
	r, err := b.client.call("dumpprivkey", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &privKey)
	return
}

// EncryptWallet encrypts the wallet with <passphrase>.
func (b *bitcoind) EncryptWallet(passphrase string) error {
	r, err := b.client.call("encryptwallet", []string{passphrase})
	return handleError(err, &r)
}

// GetAccount returns the account associated with the given address.
func (b *bitcoind) GetAccount(address string) (account string, err error) {
	r, err := b.client.call("getaccount", []string{address})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &account)
	return
}

// GetAccountAddress Returns the current bitcoin address for receiving
// payments to this account.
// If account does not exist, it will be created along with an
// associated new address that will be returned.
func (b *bitcoind) GetAccountAddress(account string) (address string, err error) {
	r, err := b.client.call("getaccountaddress", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &address)
	return
}

// GetBalance return the balance of the server or of a specific account
//If [account] is "", returns the server's total available balance.
//If [account] is specified, returns the balance in the account
func (b *bitcoind) GetBalance(account string, minconf uint64) (balance float64, err error) {
	r, err := b.client.call("getbalance", []interface{}{account, minconf})
	if err = handleError(err, &r); err != nil {
		return
	}
	balance, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetBestBlockhash returns the hash of the best (tip) block in the longest block chain.
func (b *bitcoind) GetBestBlockhash() (bestBlockHash string, err error) {
	r, err := b.client.call("getbestblockhash", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &bestBlockHash)
	return
}

// GetBlock returns information about the block with the given hash.
func (b *bitcoind) GetBlock(blockHash string) (block block, err error) {
	r, err := b.client.call("getblock", []string{blockHash})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &block)
	return
}

// GetBlockCount returns the number of blocks in the longest block chain.
func (b *bitcoind) GetBlockCount() (count uint64, err error) {
	r, err := b.client.call("getblockcount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetBlockHash returns hash of block in best-block-chain at <index>
func (b *bitcoind) GetBlockHash(index uint64) (hash string, err error) {
	r, err := b.client.call("getblockhash", []uint64{index})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &hash)
	return
}

// getBlockTemplateParams reperesent parameters for GetBlockTemplate
type getBlockTemplateParams struct {
	Mode         string   `json:"mode,omitempty"`
	Capabilities []string `json:"capabilities,omitempty"`
}

// TODO a finir
// GetBlockTemplate Returns data needed to construct a block to work on.
// See BIP_0022 for more info on params.
func (b *bitcoind) GetBlockTemplate(capabilities []string, mode string) (template string, err error) {
	params := getBlockTemplateParams{
		Mode:         mode,
		Capabilities: capabilities,
	}
	// TODO []interface{}{mode, capa}
	r, err := b.client.call("getblocktemplate", []getBlockTemplateParams{params})
	if err = handleError(err, &r); err != nil {
		return
	}
	fmt.Println(string(r.Result))
	return
}

// GetConnectionCount returns the number of connections to other nodes.
func (b *bitcoind) GetConnectionCount() (count uint64, err error) {
	r, err := b.client.call("getconnectioncount", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	count, err = strconv.ParseUint(string(r.Result), 10, 64)
	return
}

// GetDifficulty returns the proof-of-work difficulty as a multiple of
// the minimum difficulty.
func (b *bitcoind) GetDifficulty() (difficulty float64, err error) {
	r, err := b.client.call("getdifficulty", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	difficulty, err = strconv.ParseFloat(string(r.Result), 64)
	return
}

// GetInfo return result of "getinfo" command (Amazing !)
func (b *bitcoind) GetInfo() (i info, err error) {
	r, err := b.client.call("getinfo", nil)
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &i)
	return
}

// GetNewAddress return a new address for account [account].
func (b *bitcoind) GetNewAddress(account ...string) (addr string, err error) {
	// 0 or 1 account
	if len(account) > 1 {
		err = errors.New("Bad parameters for GetNewAddress: you can set 0 or 1 account")
		return
	}
	r, err := b.client.call("getnewaddress", account)
	if err = handleError(err, &r); err != nil {
		return
	}
	addr = string(r.Result)
	return
}

// GetAddressesByAccount return addresses associated with account <account>
func (b *bitcoind) GetAddressesByAccount(account string) (addresses []string, err error) {
	r, err := b.client.call("getaddressesbyaccount", []string{account})
	if err = handleError(err, &r); err != nil {
		return
	}
	err = json.Unmarshal(r.Result, &addresses)
	return
}

// walletPassphrase stores the wallet decryption key in memory for <timeout> seconds.
func (b *bitcoind) WalletPassphrase(passPhrase string, timeout uint64) error {
	r, err := b.client.call("walletpassphrase", []interface{}{passPhrase, timeout})
	return handleError(err, &r)
}
<|endoftext|>


<commit_before>package backends

import (
  "time"
  "fmt"
  "strings"
  "github.com/docker/libswarm/beam"

  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/ec2"
)

type ec2Config struct {
  securityGroup string
  instanceType  string
  keypair        string
  zone           string
  ami            string
  tag            string
  region         aws.Region
}

type ec2Client struct {
  config   *ec2Config
  ec2Conn  *ec2.EC2
  Server   *beam.Server
  instance *ec2.Instance
}

func (c *ec2Client) get(ctx *beam.Message) error {
  fmt.Println("*** ec2 Get ***")
  body := `{}`
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{body}})
  return nil
}

func (c *ec2Client) start(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStart ***")

  if instance, err := c.findInstance(); err != nil {
    return err
  } else if instance != nil {
    fmt.Println("*** found existing instance ****")
    c.instance = instance
  } else {
    if err := c.startInstance(); err != nil {
      return err
    }

    if err := c.tagtInstance(); err != nil {
      return err
    }
  }

  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) log(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLog ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) spawn(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnSpawn ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) ls(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLs ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{}})
  return nil
}

func (c *ec2Client) error(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnError ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) stop(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStop ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) attach(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnAttach ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})

  for {
     time.Sleep(1 * time.Second)
     (&beam.Object{ctx.Ret}).Log("ec2: heartbeat")
  }
  return nil
}

func defaultConfigValues() (config *ec2Config) {
  config               = new(ec2Config)
  config.region        = aws.USEast
  config.instanceType  = "t1.micro"
  return config
}

func newConfig(args []string) (config *ec2Config, err error) {
  // TODO (aaron): fail fast on incorrect number of args

  var optValPair []string
  var opt, val string

  config = defaultConfigValues()

  for _, value := range args {
    optValPair = strings.Split(value, "=")
    opt, val   = optValPair[0], optValPair[1]

    switch opt {
      case "--region":
        config.region = convertToRegion(val)
      case "--zone":
        config.zone = val
      case "--tag":
        config.tag = val
      case "--ami":
        config.ami = val
      case "--keypair":
        config.keypair = val
      case "--security_group":
        config.securityGroup = val
      case "--instance_type":
        config.instanceType = val
      default:
        fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
    }
  }
  return config, nil
}

func convertToRegion(input string) aws.Region {
  // TODO (aaron): fill in more regions
  switch input {
    case "us-east-1":
      return  aws.USEast
    case "us-west-1":
      return  aws.USWest
    case "us-west-2":
      return  aws.USWest2
    case "eu-west-1":
      return  aws.EUWest
    default:
      fmt.Println("Unrecognizable region, default to: us-east-1")
      return aws.USEast
  }
}

func awsInit(config *ec2Config)  (ec2Conn *ec2.EC2, err error) {
  auth, err := aws.EnvAuth()

  if err != nil {
    return nil, err
  }

  return ec2.New(auth, config.region), nil
}

func (c *ec2Client) findInstance() (instance *ec2.Instance, err error) {
  filter := ec2.NewFilter()
  filter.Add("tag:Name", c.config.tag)
  if resp, err := c.ec2Conn.Instances([]string{}, filter); err != nil {
    return nil, err
  } else {
    if resp.Reservations == nil {
      return nil, nil
    }
    return &resp.Reservations[0].Instances[0], nil
  }
}

func (c *ec2Client) tagtInstance() error {
  ec2Tags := []ec2.Tag{ec2.Tag{"Name", c.config.tag}}
  if _, err := c.ec2Conn.CreateTags([]string{c.instance.InstanceId}, ec2Tags); err != nil {
    return err
  }
  return nil
}

func (c *ec2Client) startInstance() error {
  options := ec2.RunInstances{
    ImageId:      c.config.ami,
    InstanceType: c.config.instanceType,
    KeyName:      c.config.keypair,
  }

  resp, err := c.ec2Conn.RunInstances(&options)
  if err != nil {
    return err
  }

  // TODO (aaron): this really could be multiple instances, not just 1
  i := resp.Instances[0]

  for i.State.Name != "running" {
    time.Sleep(3 * time.Second)
    fmt.Printf("Waiting for instance to come up.  Current State: %s\n",
               i.State.Name)

    resp, err := c.ec2Conn.Instances([]string{i.InstanceId}, ec2.NewFilter())

    if err != nil {
      return err
    }

    i = resp.Reservations[0].Instances[0]
  }

  c.instance = &i

  fmt.Printf("Instance up and running - id: %s\n", i.InstanceId)
  return nil
}

func Ec2() beam.Sender {
  backend := beam.NewServer()
  backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
    fmt.Println("*** init ***")

    var config, err = newConfig(ctx.Args)

    if (err != nil) {
      return err
    }

    ec2Conn, err := awsInit(config)
    if (err != nil) {
      return err
    }

    client := &ec2Client{config, ec2Conn, beam.NewServer(), nil}
    client.Server.OnSpawn(beam.Handler(client.spawn))
    client.Server.OnStart(beam.Handler(client.start))
    client.Server.OnStop(beam.Handler(client.stop))
    client.Server.OnAttach(beam.Handler(client.attach))
    client.Server.OnLog(beam.Handler(client.log))
    client.Server.OnError(beam.Handler(client.error))
    client.Server.OnLs(beam.Handler(client.ls))
    client.Server.OnGet(beam.Handler(client.get))

    _, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})

    return err
  }))
  return backend
}
<commit_msg>make sure the instance is actually running<commit_after>package backends

import (
  "time"
  "fmt"
  "strings"
  "github.com/docker/libswarm/beam"

  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/ec2"
)

type ec2Config struct {
  securityGroup string
  instanceType  string
  keypair        string
  zone           string
  ami            string
  tag            string
  region         aws.Region
}

type ec2Client struct {
  config   *ec2Config
  ec2Conn  *ec2.EC2
  Server   *beam.Server
  instance *ec2.Instance
}

func (c *ec2Client) get(ctx *beam.Message) error {
  fmt.Println("*** ec2 Get ***")
  body := `{}`
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{body}})
  return nil
}

func (c *ec2Client) start(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStart ***")

  if instance, err := c.findInstance(); err != nil {
    return err
  } else if instance != nil {
    fmt.Println("*** found existing instance ****")
    c.instance = instance
  } else {
    if err := c.startInstance(); err != nil {
      return err
    }

    if err := c.tagtInstance(); err != nil {
      return err
    }
  }

  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) log(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLog ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) spawn(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnSpawn ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) ls(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLs ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{}})
  return nil
}

func (c *ec2Client) error(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnError ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) stop(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStop ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) attach(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnAttach ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})

  for {
     time.Sleep(1 * time.Second)
     (&beam.Object{ctx.Ret}).Log("ec2: heartbeat")
  }
  return nil
}

func defaultConfigValues() (config *ec2Config) {
  config               = new(ec2Config)
  config.region        = aws.USEast
  config.instanceType  = "t1.micro"
  return config
}

func newConfig(args []string) (config *ec2Config, err error) {
  // TODO (aaron): fail fast on incorrect number of args

  var optValPair []string
  var opt, val string

  config = defaultConfigValues()

  for _, value := range args {
    optValPair = strings.Split(value, "=")
    opt, val   = optValPair[0], optValPair[1]

    switch opt {
      case "--region":
        config.region = convertToRegion(val)
      case "--zone":
        config.zone = val
      case "--tag":
        config.tag = val
      case "--ami":
        config.ami = val
      case "--keypair":
        config.keypair = val
      case "--security_group":
        config.securityGroup = val
      case "--instance_type":
        config.instanceType = val
      default:
        fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
    }
  }
  return config, nil
}

func convertToRegion(input string) aws.Region {
  // TODO (aaron): fill in more regions
  switch input {
    case "us-east-1":
      return  aws.USEast
    case "us-west-1":
      return  aws.USWest
    case "us-west-2":
      return  aws.USWest2
    case "eu-west-1":
      return  aws.EUWest
    default:
      fmt.Println("Unrecognizable region, default to: us-east-1")
      return aws.USEast
  }
}

func awsInit(config *ec2Config)  (ec2Conn *ec2.EC2, err error) {
  auth, err := aws.EnvAuth()

  if err != nil {
    return nil, err
  }

  return ec2.New(auth, config.region), nil
}

func (c *ec2Client) findInstance() (instance *ec2.Instance, err error) {
  filter := ec2.NewFilter()
  filter.Add("tag:Name", c.config.tag)
  if resp, err := c.ec2Conn.Instances([]string{}, filter); err != nil {
    return nil, err
  } else {
    if resp.Reservations == nil {
      return nil, nil
    }

    instance := resp.Reservations[0].Instances[0]

    if (instance.State.Name != "running" || instance.State.Name != "pending") {
      return nil, nil
    }

    return &instance, nil
  }
}

func (c *ec2Client) tagtInstance() error {
  ec2Tags := []ec2.Tag{ec2.Tag{"Name", c.config.tag}}
  if _, err := c.ec2Conn.CreateTags([]string{c.instance.InstanceId}, ec2Tags); err != nil {
    return err
  }
  return nil
}

func (c *ec2Client) startInstance() error {
  options := ec2.RunInstances{
    ImageId:      c.config.ami,
    InstanceType: c.config.instanceType,
    KeyName:      c.config.keypair,
  }

  resp, err := c.ec2Conn.RunInstances(&options)
  if err != nil {
    return err
  }

  // TODO (aaron): this really could be multiple instances, not just 1
  i := resp.Instances[0]

  for i.State.Name != "running" {
    time.Sleep(3 * time.Second)
    fmt.Printf("Waiting for instance to come up.  Current State: %s\n",
               i.State.Name)

    resp, err := c.ec2Conn.Instances([]string{i.InstanceId}, ec2.NewFilter())

    if err != nil {
      return err
    }

    i = resp.Reservations[0].Instances[0]
  }

  c.instance = &i

  fmt.Printf("Instance up and running - id: %s\n", i.InstanceId)
  return nil
}

func Ec2() beam.Sender {
  backend := beam.NewServer()
  backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
    fmt.Println("*** init ***")

    var config, err = newConfig(ctx.Args)

    if (err != nil) {
      return err
    }

    ec2Conn, err := awsInit(config)
    if (err != nil) {
      return err
    }

    client := &ec2Client{config, ec2Conn, beam.NewServer(), nil}
    client.Server.OnSpawn(beam.Handler(client.spawn))
    client.Server.OnStart(beam.Handler(client.start))
    client.Server.OnStop(beam.Handler(client.stop))
    client.Server.OnAttach(beam.Handler(client.attach))
    client.Server.OnLog(beam.Handler(client.log))
    client.Server.OnError(beam.Handler(client.error))
    client.Server.OnLs(beam.Handler(client.ls))
    client.Server.OnGet(beam.Handler(client.get))

    _, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})

    return err
  }))
  return backend
}
<|endoftext|>


<commit_before>// GoAWK interpreter value type (not exported).

package interp

import (
	"fmt"
	"math"
	"strconv"

	"github.com/benhoyt/goawk/internal/strutil"
)

type valueType uint8

const (
	typeNull valueType = iota
	typeStr
	typeNum
	typeNumStr
)

// An AWK value (these are passed around by value)
type value struct {
	typ valueType // Type of value
	s   string    // String value (for typeStr)
	n   float64   // Numeric value (for typeNum and typeNumStr)
}

// Create a new null value
func null() value {
	return value{}
}

// Create a new number value
func num(n float64) value {
	return value{typ: typeNum, n: n}
}

// Create a new string value
func str(s string) value {
	return value{typ: typeStr, s: s}
}

// Create a new value for a "numeric string" context, converting the
// string to a number if possible.
func numStr(s string) value {
	f, err := strconv.ParseFloat(strutil.TrimSpace(s), 64)
	if err != nil {
		// Doesn't parse as number, make it a "true string"
		return value{typ: typeStr, s: s}
	}
	return value{typ: typeNumStr, s: s, n: f}
}

// Create a numeric value from a Go bool
func boolean(b bool) value {
	if b {
		return num(1)
	}
	return num(0)
}

// Return true if value is a "true string" (string but not a "numeric
// string")
func (v value) isTrueStr() bool {
	return v.typ == typeStr
}

// Return Go bool value of AWK value. For numbers or numeric strings,
// zero is false and everything else is true. For strings, empty
// string is false and everything else is true.
func (v value) boolean() bool {
	if v.isTrueStr() {
		return v.s != ""
	} else {
		return v.n != 0
	}
}

// Return value's string value, or convert to a string using given
// format if a number value. Integers are a special case and don't
// use floatFormat.
func (v value) str(floatFormat string) string {
	switch v.typ {
	case typeNum:
		if math.IsNaN(v.n) {
			return "nan"
		} else if math.IsInf(v.n, 0) {
			if v.n < 0 {
				return "-inf"
			} else {
				return "inf"
			}
		} else if v.n == float64(int(v.n)) {
			return strconv.Itoa(int(v.n))
		} else {
			return fmt.Sprintf(floatFormat, v.n)
		}
	case typeStr, typeNumStr:
		return v.s
	default:
		return ""
	}
}

// Return value's number value, converting from string if necessary
func (v value) num() float64 {
	switch v.typ {
	case typeNum:
		return v.n
	case typeStr:
		// Ensure string starts with a float and convert it
		return parseFloatPrefix(v.s)
	case typeNumStr:
		// If it's a numeric string, we already have the float value
		// from the numStr() call
		return v.n
	default:
		return 0
	}
}

// Like strconv.ParseFloat, but parses at the start of string and
// allows things like "1.5foo"
func parseFloatPrefix(s string) float64 {
	// Skip whitespace at start
	i := 0
	for i < len(s) && strutil.IsASCIISpace(s[i]) {
		i++
	}
	start := i

	// Parse mantissa: optional sign, initial digit(s), optional '.',
	// then more digits
	gotDigit := false
	if i < len(s) && (s[i] == '+' || s[i] == '-') {
		i++
	}
	for i < len(s) && s[i] >= '0' && s[i] <= '9' {
		gotDigit = true
		i++
	}
	if i < len(s) && s[i] == '.' {
		i++
	}
	for i < len(s) && s[i] >= '0' && s[i] <= '9' {
		gotDigit = true
		i++
	}
	if !gotDigit {
		return 0
	}

	// Parse exponent ("1e" and similar are allowed, but ParseFloat
	// rejects them)
	end := i
	if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
		i++
		if i < len(s) && (s[i] == '+' || s[i] == '-') {
			i++
		}
		for i < len(s) && s[i] >= '0' && s[i] <= '9' {
			i++
			end = i
		}
	}

	floatStr := s[start:end]
	f, _ := strconv.ParseFloat(floatStr, 64)
	return f // Returns infinity in case of "value out of range" error
}
<commit_msg>Simplify value.str() and .num() logic<commit_after>// GoAWK interpreter value type (not exported).

package interp

import (
	"fmt"
	"math"
	"strconv"

	"github.com/benhoyt/goawk/internal/strutil"
)

type valueType uint8

const (
	typeNull valueType = iota
	typeStr
	typeNum
	typeNumStr
)

// An AWK value (these are passed around by value)
type value struct {
	typ valueType // Type of value
	s   string    // String value (for typeStr)
	n   float64   // Numeric value (for typeNum and typeNumStr)
}

// Create a new null value
func null() value {
	return value{}
}

// Create a new number value
func num(n float64) value {
	return value{typ: typeNum, n: n}
}

// Create a new string value
func str(s string) value {
	return value{typ: typeStr, s: s}
}

// Create a new value for a "numeric string" context, converting the
// string to a number if possible.
func numStr(s string) value {
	f, err := strconv.ParseFloat(strutil.TrimSpace(s), 64)
	if err != nil {
		// Doesn't parse as number, make it a "true string"
		return value{typ: typeStr, s: s}
	}
	return value{typ: typeNumStr, s: s, n: f}
}

// Create a numeric value from a Go bool
func boolean(b bool) value {
	if b {
		return num(1)
	}
	return num(0)
}

// Return true if value is a "true string" (string but not a "numeric
// string")
func (v value) isTrueStr() bool {
	return v.typ == typeStr
}

// Return Go bool value of AWK value. For numbers or numeric strings,
// zero is false and everything else is true. For strings, empty
// string is false and everything else is true.
func (v value) boolean() bool {
	if v.isTrueStr() {
		return v.s != ""
	} else {
		return v.n != 0
	}
}

// Return value's string value, or convert to a string using given
// format if a number value. Integers are a special case and don't
// use floatFormat.
func (v value) str(floatFormat string) string {
	if v.typ == typeNum {
		switch {
		case math.IsNaN(v.n):
			return "nan"
		case math.IsInf(v.n, 0):
			if v.n < 0 {
				return "-inf"
			} else {
				return "inf"
			}
		case v.n == float64(int(v.n)):
			return strconv.Itoa(int(v.n))
		default:
			return fmt.Sprintf(floatFormat, v.n)
		}
	}
	// For typeStr and typeStrNum we already have the string, for
	// typeNull v.s == "".
	return v.s
}

// Return value's number value, converting from string if necessary
func (v value) num() float64 {
	if v.typ == typeStr {
		// Ensure string starts with a float and convert it
		return parseFloatPrefix(v.s)
	}
	// Handle case for typeNum and typeStrNum. If it's a numeric
	// string, we already have the float value from the numStr()
	// call. For typeNull v.n == 0.
	return v.n
}

// Like strconv.ParseFloat, but parses at the start of string and
// allows things like "1.5foo"
func parseFloatPrefix(s string) float64 {
	// Skip whitespace at start
	i := 0
	for i < len(s) && strutil.IsASCIISpace(s[i]) {
		i++
	}
	start := i

	// Parse mantissa: optional sign, initial digit(s), optional '.',
	// then more digits
	gotDigit := false
	if i < len(s) && (s[i] == '+' || s[i] == '-') {
		i++
	}
	for i < len(s) && s[i] >= '0' && s[i] <= '9' {
		gotDigit = true
		i++
	}
	if i < len(s) && s[i] == '.' {
		i++
	}
	for i < len(s) && s[i] >= '0' && s[i] <= '9' {
		gotDigit = true
		i++
	}
	if !gotDigit {
		return 0
	}

	// Parse exponent ("1e" and similar are allowed, but ParseFloat
	// rejects them)
	end := i
	if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
		i++
		if i < len(s) && (s[i] == '+' || s[i] == '-') {
			i++
		}
		for i < len(s) && s[i] >= '0' && s[i] <= '9' {
			i++
			end = i
		}
	}

	floatStr := s[start:end]
	f, _ := strconv.ParseFloat(floatStr, 64)
	return f // Returns infinity in case of "value out of range" error
}
<|endoftext|>