<commit_before>package checkhttp

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
)

// XXX more options
type checkHttpOpts struct {
	URL                string   `short:"u" long:"url" required:"true" description:"A URL to connect to"`
	Statuses           []string `short:"s" long:"status" description:"mapping of HTTP status"`
	NoCheckCertificate bool     `long:"no-check-certificate" description:"Do not check certificate"`
	SourceIP           string   `short:"i" long:"source-ip" description:"source IP address"`
}

// Do the plugin
func Do() {
	ckr := Run(os.Args[1:])
	ckr.Name = "HTTP"
	ckr.Exit()
}

type statusRange struct {
	min     int
	max     int
	checkSt checkers.Status
}

const invalidMapping = "Invalid mapping of status: %s"

func parseStatusRanges(opts *checkHttpOpts) ([]statusRange, error) {
	var statuses []statusRange
	for _, s := range opts.Statuses {
		token := strings.SplitN(s, "=", 2)
		if len(token) != 2 {
			return nil, fmt.Errorf(invalidMapping, s)
		}
		values := strings.Split(token[0], "-")

		var r statusRange
		var err error

		switch len(values) {
		case 1:
			r.min, err = strconv.Atoi(values[0])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			r.max = r.min
		case 2:
			r.min, err = strconv.Atoi(values[0])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			r.max, err = strconv.Atoi(values[1])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			if r.min > r.max {
				return nil, fmt.Errorf(invalidMapping, s)
			}
		default:
			return nil, fmt.Errorf(invalidMapping, s)
		}

		switch strings.ToUpper(token[1]) {
		case "OK":
			r.checkSt = checkers.OK
		case "WARNING":
			r.checkSt = checkers.WARNING
		case "CRITICAL":
			r.checkSt = checkers.CRITICAL
		case "UNKNOWN":
			r.checkSt = checkers.UNKNOWN
		default:
			return nil, fmt.Errorf(invalidMapping, s)
		}
		statuses = append(statuses, r)
	}
	return statuses, nil
}

// Run do external monitoring via HTTP
func Run(args []string) *checkers.Checker {
	opts := checkHttpOpts{}
	_, err := flags.ParseArgs(&opts, args)
	if err != nil {
		os.Exit(1)
	}

	statusRanges, err := parseStatusRanges(&opts)
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: opts.NoCheckCertificate,
		},
		Proxy: http.ProxyFromEnvironment,
	}
	if opts.SourceIP != "" {
		ip := net.ParseIP(opts.SourceIP)
		if ip == nil {
			return checkers.Unknown(fmt.Sprintf("Invalid source IP address: %v", opts.SourceIP))
		}
		tr.Dial = (&net.Dialer{
			LocalAddr: &net.TCPAddr{IP: ip},
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial
	}
	client := &http.Client{Transport: tr}

	stTime := time.Now()
	resp, err := client.Get(opts.URL)
	if err != nil {
		return checkers.Critical(err.Error())
	}
	elapsed := time.Since(stTime)
	defer resp.Body.Close()

	cLength := resp.ContentLength
	if cLength == -1 {
		byt, _ := ioutil.ReadAll(resp.Body)
		cLength = int64(len(byt))
	}

	checkSt := checkers.UNKNOWN

	found := false
	for _, st := range statusRanges {
		if st.min <= resp.StatusCode && resp.StatusCode <= st.max {
			checkSt = st.checkSt
			found = true
			break
		}
	}

	if !found {
		switch st := resp.StatusCode; true {
		case st < 400:
			checkSt = checkers.OK
		case st < 500:
			checkSt = checkers.WARNING
		default:
			checkSt = checkers.CRITICAL
		}
	}

	msg := fmt.Sprintf("%s %s - %d bytes in %f second response time",
		resp.Proto, resp.Status, cLength, elapsed.Seconds())

	return checkers.NewChecker(checkSt, msg)
}
<commit_msg>lint suggestion<commit_after>package checkhttp

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
)

// XXX more options
type checkHTTPOpts struct {
	URL                string   `short:"u" long:"url" required:"true" description:"A URL to connect to"`
	Statuses           []string `short:"s" long:"status" description:"mapping of HTTP status"`
	NoCheckCertificate bool     `long:"no-check-certificate" description:"Do not check certificate"`
	SourceIP           string   `short:"i" long:"source-ip" description:"source IP address"`
}

// Do the plugin
func Do() {
	ckr := Run(os.Args[1:])
	ckr.Name = "HTTP"
	ckr.Exit()
}

type statusRange struct {
	min     int
	max     int
	checkSt checkers.Status
}

const invalidMapping = "Invalid mapping of status: %s"

func parseStatusRanges(opts *checkHTTPOpts) ([]statusRange, error) {
	var statuses []statusRange
	for _, s := range opts.Statuses {
		token := strings.SplitN(s, "=", 2)
		if len(token) != 2 {
			return nil, fmt.Errorf(invalidMapping, s)
		}
		values := strings.Split(token[0], "-")

		var r statusRange
		var err error

		switch len(values) {
		case 1:
			r.min, err = strconv.Atoi(values[0])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			r.max = r.min
		case 2:
			r.min, err = strconv.Atoi(values[0])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			r.max, err = strconv.Atoi(values[1])
			if err != nil {
				return nil, fmt.Errorf(invalidMapping, s)
			}
			if r.min > r.max {
				return nil, fmt.Errorf(invalidMapping, s)
			}
		default:
			return nil, fmt.Errorf(invalidMapping, s)
		}

		switch strings.ToUpper(token[1]) {
		case "OK":
			r.checkSt = checkers.OK
		case "WARNING":
			r.checkSt = checkers.WARNING
		case "CRITICAL":
			r.checkSt = checkers.CRITICAL
		case "UNKNOWN":
			r.checkSt = checkers.UNKNOWN
		default:
			return nil, fmt.Errorf(invalidMapping, s)
		}
		statuses = append(statuses, r)
	}
	return statuses, nil
}

// Run do external monitoring via HTTP
func Run(args []string) *checkers.Checker {
	opts := checkHTTPOpts{}
	_, err := flags.ParseArgs(&opts, args)
	if err != nil {
		os.Exit(1)
	}

	statusRanges, err := parseStatusRanges(&opts)
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: opts.NoCheckCertificate,
		},
		Proxy: http.ProxyFromEnvironment,
	}
	if opts.SourceIP != "" {
		ip := net.ParseIP(opts.SourceIP)
		if ip == nil {
			return checkers.Unknown(fmt.Sprintf("Invalid source IP address: %v", opts.SourceIP))
		}
		tr.Dial = (&net.Dialer{
			LocalAddr: &net.TCPAddr{IP: ip},
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial
	}
	client := &http.Client{Transport: tr}

	stTime := time.Now()
	resp, err := client.Get(opts.URL)
	if err != nil {
		return checkers.Critical(err.Error())
	}
	elapsed := time.Since(stTime)
	defer resp.Body.Close()

	cLength := resp.ContentLength
	if cLength == -1 {
		byt, _ := ioutil.ReadAll(resp.Body)
		cLength = int64(len(byt))
	}

	checkSt := checkers.UNKNOWN

	found := false
	for _, st := range statusRanges {
		if st.min <= resp.StatusCode && resp.StatusCode <= st.max {
			checkSt = st.checkSt
			found = true
			break
		}
	}

	if !found {
		switch st := resp.StatusCode; true {
		case st < 400:
			checkSt = checkers.OK
		case st < 500:
			checkSt = checkers.WARNING
		default:
			checkSt = checkers.CRITICAL
		}
	}

	msg := fmt.Sprintf("%s %s - %d bytes in %f second response time",
		resp.Proto, resp.Status, cLength, elapsed.Seconds())

	return checkers.NewChecker(checkSt, msg)
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"strings"

	"github.com/hyperhq/runv/hypervisor/types"

	gflag "github.com/jessevdk/go-flags"
)

func (cli *HyperClient) HyperCmdStop(args ...string) error {

	var opts struct {
		Container bool `short:"c" long:"container" default:"false" default-mask:"-" description:"stop container"`
		Novm      bool `long:"onlypod" default:"false" description:"Stop a Pod, but left the VM running"`
	}
	var parser = gflag.NewParser(&opts, gflag.Default)
	parser.Usage = "stop [OPTIONS] CONTAINER_ID|POD_ID\n\nStop running container or pod"
	args, err := parser.ParseArgs(args)
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}
	if len(args) == 0 {
		return fmt.Errorf("\"stop\" requires a minimum of 1 argument, please provide POD ID.\n")
	}

	stopVm := "yes"
	if opts.Novm {
		stopVm = "no"
	}

	for i := range args {
		if opts.Container {
			err = cli.client.StopContainer(args[i])
			if err != nil {
				fmt.Fprintf(cli.err, "fail to stop container %s: %v", args[i], err)
			}
		} else {
			code, cause, err := cli.client.StopPod(args[i], stopVm)
			if err != nil {
				fmt.Fprintf(cli.err, "fail to stop pod %s: %v", args[i], err)
				continue
			}
			if code != types.E_POD_STOPPED && code != types.E_VM_SHUTDOWN {
				fmt.Fprintf(cli.err, "Error code is %d, cause is %s", code, cause)
				continue
			}
			fmt.Printf("Successfully shutdown the POD: %s!\n", args[i])
		}
	}

	return nil
}
<commit_msg>E_POD_STOPPED has been removed from runV<commit_after>package client

import (
	"fmt"
	"strings"

	"github.com/hyperhq/runv/hypervisor/types"

	gflag "github.com/jessevdk/go-flags"
)

func (cli *HyperClient) HyperCmdStop(args ...string) error {

	var opts struct {
		Container bool `short:"c" long:"container" default:"false" default-mask:"-" description:"stop container"`
		Novm      bool `long:"onlypod" default:"false" description:"Stop a Pod, but left the VM running"`
	}
	var parser = gflag.NewParser(&opts, gflag.Default)
	parser.Usage = "stop [OPTIONS] CONTAINER_ID|POD_ID\n\nStop running container or pod"
	args, err := parser.ParseArgs(args)
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}
	if len(args) == 0 {
		return fmt.Errorf("\"stop\" requires a minimum of 1 argument, please provide POD ID.\n")
	}

	stopVm := "yes"
	if opts.Novm {
		stopVm = "no"
	}

	for i := range args {
		if opts.Container {
			err = cli.client.StopContainer(args[i])
			if err != nil {
				fmt.Fprintf(cli.err, "fail to stop container %s: %v", args[i], err)
			}
		} else {
			code, cause, err := cli.client.StopPod(args[i], stopVm)
			if err != nil {
				fmt.Fprintf(cli.err, "fail to stop pod %s: %v", args[i], err)
				continue
			}
			if code != types.E_VM_SHUTDOWN {
				fmt.Fprintf(cli.err, "Error code is %d, cause is %s", code, cause)
				continue
			}
			fmt.Printf("Successfully shutdown the POD: %s!\n", args[i])
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package pinocchio

import (
//  "os"
  "fmt"
//  "errors"
  "math/big"
)

type IncrementingBlockCipher struct {
  IV *big.Int
  Plainblock string
  Key *big.Int
  Keybits int
}

func NewIncrementingBlockCipher() IncrementingBlockCipher {
  c := IncrementingBlockCipher{}
  return c
}

func (c *IncrementingBlockCipher) SetKey(keybits int, key *big.Int) {
  c.Keybits = keybits
  c.Key = key
}

func (c *IncrementingBlockCipher) SetIV(iv *big.Int) {
  c.IV = iv
}

/*func (c *IncrementingBlockCipher) RandomizeIV() {
  c.IV = // ?
}*/

func (c *IncrementingBlockCipher) BytesBlockCount(bytes_length int) int {
  return (bytes_length * 8 + c.Keybits - 1) / c.Keybits
}

func (c *IncrementingBlockCipher) EncodeBytes(plain_bytes []byte) ([]byte, error) {
  plain_bytes_length := len(plain_bytes)
  last_plain_bytes := c.BigIntAsBytes(c.IV)
  block_count := c.BytesBlockCount(plain_bytes_length)
  crypt_str := ""

  for i := 0; i < block_count; i++ {
    block_offset_start := i * (c.Keybits + 7) / 8
    block_offset_end := (i + 1) * (c.Keybits + 7) / 8
    if block_offset_end > plain_bytes_length {
      block_offset_end = plain_bytes_length
    }

    block_plain_bytes := plain_bytes[block_offset_start:block_offset_end]
    block_crypt_bigint, err := c.EncodeBlock(c.BytesAsBigInt(block_plain_bytes), c.BytesAsBigInt(last_plain_bytes))
    if err != nil {
      return nil, err
    }

    block_crypt_bytes := c.BigIntAsBytes(block_crypt_bigint)
    block_crypt_str := string(block_crypt_bytes)
    crypt_str += block_crypt_str
    fmt.Printf("Block %d. f('%s' ^ '%s') = '0x%x'\n", i, string(block_plain_bytes), c.BytesAsBigInt(last_plain_bytes), block_crypt_bytes)

    last_plain_bytes = block_plain_bytes
  }
  return []byte(crypt_str), nil
}

func (c *IncrementingBlockCipher) DecodeBytes(crypt_bytes []byte) ([]byte, error) {
  crypt_bytes_length := len(crypt_bytes)
  last_plain_bytes := c.BigIntAsBytes(c.IV)
  block_count := c.BytesBlockCount(crypt_bytes_length)
  plain_str := ""

  for i := 0; i < block_count; i++ {
    block_offset_start := i * (c.Keybits + 7) / 8
    if block_offset_start >= crypt_bytes_length {
      break
    }
    block_offset_end := (i + 1) * (c.Keybits + 7) / 8
    if block_offset_end > crypt_bytes_length {
      block_offset_end = crypt_bytes_length
    }

    block_crypt_bytes := crypt_bytes[block_offset_start:block_offset_end]
    block_plain_bigint, err := c.DecodeBlock(c.BytesAsBigInt(block_crypt_bytes), c.BytesAsBigInt(last_plain_bytes))
    if err != nil {
      return nil, err
    }

    block_plain_bytes := c.BigIntAsBytes(block_plain_bigint)
    block_plain_str := string(block_plain_bytes)
    plain_str += block_plain_str
    fmt.Printf("Round %d. f^-1('0x%x') ^ '%s' = '%s'\n", i, c.BytesAsBigInt(block_crypt_bytes), c.BytesAsBigInt(last_plain_bytes), block_plain_str)

    last_plain_bytes = block_plain_bytes
  }
  return []byte(plain_str), nil
}

func (c *IncrementingBlockCipher) EncodeBlock(plain *big.Int, previous_plain *big.Int) (*big.Int, error) {
  plain.Xor(plain, previous_plain) // CBC
  return plain.Xor(plain, c.Key), nil
}

func (c *IncrementingBlockCipher) DecodeBlock(block *big.Int, previous_plain *big.Int) (*big.Int, error) {
  block.Xor(block, c.Key)
  block.Xor(block, previous_plain)
  return block, nil
}

func (c *IncrementingBlockCipher) BigIntAsBytes(block *big.Int) []byte {
  block2 := big.NewInt(0)
  block2.SetString(block.String(), 10)

  plain := make([]byte, (block.BitLen() + 7) / 8)
  for i := 1; i <= len(plain); i++ {
    b := big.NewInt(0)
    b.And(block2, big.NewInt(0xff))
    block2.Rsh(block2, 8)
    plain[len(plain) - i] = byte(b.Int64())
  }
  return plain
}

func (c *IncrementingBlockCipher) BytesAsBigInt(block []byte) *big.Int {
  bigblock := big.NewInt(0)
  for i := 0; i < len(block); i++ {
    plainbyteint := big.NewInt(int64(block[uint(i)]))
    bigblock.Add(bigblock, plainbyteint)
    bigblock.Lsh(bigblock, 8)
  }
  bigblock.Rsh(bigblock, 8)
  return bigblock
}

/*func main() {
  c := NewIncrementingBlockCipher()

  key := big.NewInt(0)
  key.SetString(os.Args[1], 10)
  c.SetKey(len(os.Args[1]) * 8, key)

  iv := []byte(os.Args[2])[0:(len(os.Args[1]) * 4 + 7) / 8]
  c.SetIV(c.BytesAsBigInt(iv))

  fmt.Printf("%d-bit Key '0x%x' with %d-bit IV '0x%x'.\n\n", c.Keybits, c.Key, len(os.Args[2]) * 8, c.IV)

  input := []byte(os.Args[3])

  fmt.Printf("input: %d '%s'\n\n", len(input), input)
  cryptext, err := c.EncodeBytes(input)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Printf("cryptext: %d '0x%x'\n\n", len(cryptext), c.BytesAsBigInt(cryptext))
  decodedtext, err := c.DecodeBytes(cryptext)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Printf("decodedtext: %d '%s'\n", len(decodedtext), decodedtext)
}*/
<commit_msg>Removed block cipher. Need to think harder about useful PRNGs to include.<commit_after><|endoftext|>


<commit_before>package smitego

import (
	"fmt"
	"golang.org/x/net/context"
)

// Example of creating a session and making a function call.
func ExampleSession() {
	// First make a client to describe how you want to connect.  Each client returns a session
	// and primary function calls are done on the session.  Concurrent sessions are limited
	// by HiRez
	client := Client{
		DevID:   123,
		AuthKey: "AuthKey123",
	}

	// A context is how you can time out function calls
	ctx := context.Background()

	// Some functions don't require a session first and can be called on the client directly
	_ = client.Ping(ctx)

	// Most functions require a session

	session, _ := client.CreateSession(ctx)
	gods, _ := session.GetGods(ctx, English)
	fmt.Printf("Got %d gods\n", len(gods))
}
<commit_msg>Add some tests<commit_after>package smitego

import (
	"fmt"
	"golang.org/x/net/context"
	"testing"
	. "github.com/smartystreets/goconvey/convey"
	"net/http"
	"strings"
	"io/ioutil"
)

type errorRT struct {
}

func (t *errorRT) RoundTrip(req *http.Request) (*http.Response, error) {
	return nil, t
}

func (t *errorRT) Error() string {
	return "An error in transport"
}

type staticResp struct {
	Resp *http.Response
}

func (t *staticResp) RoundTrip(req *http.Request) (*http.Response, error) {
	return t.Resp, nil
}

// Example of creating a session and making a function call.
func ExampleSession() {
	// First make a client to describe how you want to connect.  Each client returns a session
	// and primary function calls are done on the session.  Concurrent sessions are limited
	// by HiRez
	client := Client{
		DevID:   123,
		AuthKey: "AuthKey123",
	}

	// A context is how you can time out function calls
	ctx := context.Background()

	// Some functions don't require a session first and can be called on the client directly
	_ = client.Ping(ctx)

	// Most functions require a session

	session, _ := client.CreateSession(ctx)
	gods, _ := session.GetGods(ctx, English)
	fmt.Printf("Got %d gods\n", len(gods))
}

func TestClient(t *testing.T) {
	Convey("With a client", t, func() {
		c := Client {
		}
		ctx := context.Background()
		Convey("that errors http connections", func() {
			rt := &errorRT{}
			c.HTTPClient.Transport = rt
			Convey("Connections should error", func() {
				err := c.Ping(ctx)
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldContainSubstring, rt.Error())
			})
		})
		Convey("that 404s", func() {
			sr := &staticResp{
				Resp: &http.Response{
					StatusCode: http.StatusNotFound,
					Body: ioutil.NopCloser(strings.NewReader("")),
				},
			}
			c.HTTPClient.Transport = sr
			Convey("requests should error", func() {
				err := c.Ping(ctx)
				So(err, ShouldNotBeNil)
				So(err.Error(), ShouldContainSubstring, fmt.Sprintf("%d", http.StatusNotFound))
			})
		})

	})
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 Joshua Elliott

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package turnpike

import (
	"errors"
	"net/http"
	"runtime"
	"testing"
)

func handleResult(client, uri string, args ...interface{}) (interface{}, error) {
	return "ok", nil
}

func handleResultGenericError(client, uri string, args ...interface{}) (interface{}, error) {
	return nil, errors.New("error")
}

func handleResultCustomError(client, uri string, args ...interface{}) (interface{}, error) {
	return nil, RPCError{uri, "custom error", nil}
}

func TestClient_CallResult(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_result", handleResult)
	http.Handle("/ws1", s.Handler)
	// TODO: needs better way of running multiple listen and serve.
	// Currently there is no way of closing the listener. A cusom server and
	// handler will work but requires more work. TBD.
	go func() {
		err := http.ListenAndServe(":8001", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	// Let the server goroutine start.
	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8001/ws1", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_result")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != "ok" {
		t.Fail()
	}
}

func TestClient_CallRestultGenericError(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_generic_error", handleResultGenericError)
	http.Handle("/ws2", s.Handler)
	go func() {
		err := http.ListenAndServe(":8002", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8002/ws2", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_generic_error")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != nil {
		t.Fail()
	}
	if r.Error.Error() != "turnpike: RPC error with URI rpc:test_generic_error#generic-error: error" {
		t.Fail()
	}
}

func TestClient_CallRestultCustomError(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_custom_error", handleResultCustomError)
	http.Handle("/ws3", s.Handler)
	go func() {
		err := http.ListenAndServe(":8003", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8003/ws3", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_custom_error")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != nil {
		t.Fail()
	}
	if r.Error.Error() != "turnpike: RPC error with URI rpc:test_custom_error: custom error" {
		t.Fail()
	}
}
<commit_msg>Add event handler test case<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 Joshua Elliott

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package turnpike

import (
	"errors"
	"net/http"
	"runtime"
	"testing"
	"time"
)

func handleResult(client, uri string, args ...interface{}) (interface{}, error) {
	return "ok", nil
}

func handleResultGenericError(client, uri string, args ...interface{}) (interface{}, error) {
	return nil, errors.New("error")
}

func handleResultCustomError(client, uri string, args ...interface{}) (interface{}, error) {
	return nil, RPCError{uri, "custom error", nil}
}

func TestClient_CallResult(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_result", handleResult)
	http.Handle("/ws1", s.Handler)
	// TODO: needs better way of running multiple listen and serve.
	// Currently there is no way of closing the listener. A cusom server and
	// handler will work but requires more work. TBD.
	go func() {
		err := http.ListenAndServe(":8001", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	// Let the server goroutine start.
	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8001/ws1", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_result")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != "ok" {
		t.Fail()
	}
}

func TestClient_CallRestultGenericError(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_generic_error", handleResultGenericError)
	http.Handle("/ws2", s.Handler)
	go func() {
		err := http.ListenAndServe(":8002", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8002/ws2", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_generic_error")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != nil {
		t.Fail()
	}
	if r.Error.Error() != "turnpike: RPC error with URI rpc:test_generic_error#generic-error: error" {
		t.Fail()
	}
}

func TestClient_CallRestultCustomError(t *testing.T) {
	s := NewServer()
	s.RegisterRPC("rpc:test_custom_error", handleResultCustomError)
	http.Handle("/ws3", s.Handler)
	go func() {
		err := http.ListenAndServe(":8003", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8003/ws3", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	resultCh, err := c.Call("rpc:test_custom_error")
	if err != nil {
		t.Error(err)
	}

	r := <-resultCh
	if r.Result != nil {
		t.Fail()
	}
	if r.Error.Error() != "turnpike: RPC error with URI rpc:test_custom_error: custom error" {
		t.Fail()
	}
}

func TestClient_Event(t *testing.T) {
	s := NewServer()
	http.Handle("/ws4", s.Handler)
	// TODO: needs better way of running multiple listen and serve.
	// Currently there is no way of closing the listener. A cusom server and
	// handler will work but requires more work. TBD.
	go func() {
		err := http.ListenAndServe(":8004", nil)
		if err != nil {
			t.Fatal("ListenAndServe: " + err.Error())
		}
	}()

	// Let the server goroutine start.
	runtime.Gosched()

	c := NewClient()
	err := c.Connect("ws://127.0.0.1:8004/ws4", "http://localhost/")
	if err != nil {
		t.Fatal("error connecting: " + err.Error())
	}

	eventCh := make(chan bool)
	c.Subscribe("event:test", func(uri string, event interface{}) {
		eventCh <- true
	})

	c.Publish("event:test", "test")

	select {
	case <-eventCh:
		return
	case <-time.After(time.Second):
		t.Fail()
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 Sean.ZH

package tools

import (
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

type Handler struct{}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/abc" {
		w.Header().Add("Content-Type", "application/json")
		w.Write([]byte(`{"name":"test", "email":"a@example.com"}`))
	}
}

func TestClientApi(t *testing.T) {
	var h Handler
	mock := httptest.NewServer(&h)
	defer mock.Close()
	client := New(mock.URL)
	_, err := client.Get("/abc")
	assert.Nil(t, err)
}
<commit_msg>add test for client<commit_after>// Copyright 2018 Sean.ZH

package tools

import (
	"github.com/stretchr/testify/assert"
	"net/http"
	"net/http/httptest"
	"testing"
)

type Handler struct{}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/abc" {
		w.Header().Add("Content-Type", "application/json")
		w.Write([]byte(`{"name":"test", "email":"a@example.com"}`))
	}
}

func TestClientApi(t *testing.T) {
	var h Handler
	mock := httptest.NewServer(&h)
	defer mock.Close()
	client := New(mock.URL, 1)
	_, err := client.Get("/abc")
	assert.Nil(t, err)
}
<|endoftext|>


<commit_before>package apixu

import (
	"os"
	"testing"
	"time"
)

var cities = []string{
	"Cairo",
	"London",
	"Paris",
	"Berlin",
	"New York",
}

func getAPIKey() string {
	return os.Getenv("APIXU_KEY")
}

func TestInvalidAPIKey(t *testing.T) {
	client := NewClient("Invalid_Key")
	_, err := client.Current("Paris")

	if err == nil {
		t.Error("Worked with invalid key")
	}
}

func TestCurrentWeatherValidCities(t *testing.T) {
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.Current(city)

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestCurrentWeatherInValidCity(t *testing.T) {
	client := NewClient(getAPIKey())
	_, err := client.Current("Unknown City")

	if err == nil {
		t.Error("No errors getting current weather of invalid city name")
	}
}

func TestForecastWeatherValidCities(t *testing.T) {
	days := []int{1, 5, 10}
	client := NewClient(getAPIKey())

	for _, day := range days {
		for _, city := range cities {
			_, err := client.Forecast(city, day)

			if err != nil {
				t.Errorf("There was an error getting forecast weather of %s days %d: %v", city, day, err)
			}
		}
	}
}

func TestForecastWeatherInValidCity(t *testing.T) {
	days := []int{1, 5, 10}
	client := NewClient(getAPIKey())

	for _, day := range days {
		_, err := client.Forecast("Unknown City", day)

		if err == nil {
			t.Error("No errors getting forecast weather of invalid city name")
		}
	}
}

func TestHistoryWeatherValidCities(t *testing.T) {
	yesterday := time.Now().AddDate(0, 0, -1)
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.History(city, yesterday.Format("2006 01 2"))

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestHistoryWeatherInValidCity(t *testing.T) {
	yesterday := time.Now().AddDate(0, 0, -1)
	client := NewClient(getAPIKey())

	_, err := client.History("Unknown City", yesterday.Format("2006 01 2"))

	if err == nil {
		t.Error("No errors getting history weather of invalid city name")
	}

}

func TestSearchValidCities(t *testing.T) {
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.Search(city)

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestSearchInValidCity(t *testing.T) {
	client := NewClient(getAPIKey())

	_, err := client.Search("Unknown City")

	if err == nil {
		t.Error("No errors getting seach/autocomplete of invalid city name")
	}
}
<commit_msg>add invalid city name<commit_after>package apixu

import (
	"os"
	"testing"
	"time"
)

const InvalidCityName = "INVALID-CITY-NAME"

var cities = []string{
	"Cairo",
	"London",
	"Paris",
	"Berlin",
	"New York",
}

func getAPIKey() string {
	return os.Getenv("APIXU_KEY")
}

func TestInvalidAPIKey(t *testing.T) {
	client := NewClient("Invalid_Key")
	_, err := client.Current("Paris")

	if err == nil {
		t.Error("Worked with invalid key")
	}
}

func TestCurrentWeatherValidCities(t *testing.T) {
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.Current(city)

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestCurrentWeatherInValidCity(t *testing.T) {
	client := NewClient(getAPIKey())
	_, err := client.Current(InvalidCityName)

	if err == nil {
		t.Error("No errors getting current weather of invalid city name")
	}
}

func TestForecastWeatherValidCities(t *testing.T) {
	days := []int{1, 5, 10}
	client := NewClient(getAPIKey())

	for _, day := range days {
		for _, city := range cities {
			_, err := client.Forecast(city, day)

			if err != nil {
				t.Errorf("There was an error getting forecast weather of %s days %d: %v", city, day, err)
			}
		}
	}
}

func TestForecastWeatherInValidCity(t *testing.T) {
	days := []int{1, 5, 10}
	client := NewClient(getAPIKey())

	for _, day := range days {
		_, err := client.Forecast(InvalidCityName, day)

		if err == nil {
			t.Error("No errors getting forecast weather of invalid city name")
		}
	}
}

func TestHistoryWeatherValidCities(t *testing.T) {
	yesterday := time.Now().AddDate(0, 0, -1)
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.History(city, yesterday.Format("2006 01 2"))

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestHistoryWeatherInValidCity(t *testing.T) {
	yesterday := time.Now().AddDate(0, 0, -1)
	client := NewClient(getAPIKey())

	_, err := client.History(InvalidCityName, yesterday.Format("2006 01 2"))

	if err == nil {
		t.Error("No errors getting history weather of invalid city name")
	}

}

func TestSearchValidCities(t *testing.T) {
	client := NewClient(getAPIKey())

	for _, city := range cities {
		_, err := client.Search(city)

		if err != nil {
			t.Errorf("There was an error getting current weather of %s: %v", city, err)
		}
	}
}

func TestSearchInValidCity(t *testing.T) {
	client := NewClient(getAPIKey())

	_, err := client.Search(InvalidCityName)

	if err == nil {
		t.Error("No errors getting search/autocomplete of invalid city name")
	}
}
<|endoftext|>


<commit_before>package oidc

import (
	"encoding/json"
	"errors"
	"net/http"
	"time"

	phttp "github.com/coreos/go-oidc/http"
	"github.com/coreos/go-oidc/jose"
	"github.com/coreos/go-oidc/key"
)

func NewRemotePublicKeyRepo(hc phttp.Client, ep string) *remotePublicKeyRepo {
	return &remotePublicKeyRepo{hc: hc, ep: ep}
}

type remotePublicKeyRepo struct {
	hc phttp.Client
	ep string
}

func (r *remotePublicKeyRepo) Get() (key.KeySet, error) {
	req, err := http.NewRequest("GET", r.ep, nil)
	if err != nil {
		return nil, err
	}

	resp, err := r.hc.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var d struct {
		Keys []jose.JWK `json:"keys"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
		return nil, err
	}

	if len(d.Keys) == 0 {
		return nil, errors.New("zero keys in response")
	}

	ttl, ok, err := phttp.Cacheable(resp.Header)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, errors.New("HTTP cache headers not set")
	}

	exp := time.Now().UTC().Add(ttl)
	ks := key.NewPublicKeySet(d.Keys, exp)
	return ks, nil
}
<commit_msg>oidc: public keyset default TTL<commit_after>package oidc

import (
	"encoding/json"
	"errors"
	"net/http"
	"time"

	phttp "github.com/coreos/go-oidc/http"
	"github.com/coreos/go-oidc/jose"
	"github.com/coreos/go-oidc/key"
)

// DefaultPublicKeySetTTL is the default TTL set on the PublicKeySet if no
// Cache-Control header is provided by the JWK Set document endpoint.
const DefaultPublicKeySetTTL = 24 * time.Hour

// NewRemotePublicKeyRepo is responsible for fetching the JWK Set document.
func NewRemotePublicKeyRepo(hc phttp.Client, ep string) *remotePublicKeyRepo {
	return &remotePublicKeyRepo{hc: hc, ep: ep}
}

type remotePublicKeyRepo struct {
	hc phttp.Client
	ep string
}

// Get returns a PublicKeySet fetched from the JWK Set document endpoint. A TTL
// is set on the Key Set to avoid it having to be re-retrieved for every
// encryption event. This TTL is typically controlled by the endpoint returning
// a Cache-Control header, but defaults to 24 hours if no Cache-Control header
// is found.
func (r *remotePublicKeyRepo) Get() (key.KeySet, error) {
	req, err := http.NewRequest("GET", r.ep, nil)
	if err != nil {
		return nil, err
	}

	resp, err := r.hc.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var d struct {
		Keys []jose.JWK `json:"keys"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
		return nil, err
	}

	if len(d.Keys) == 0 {
		return nil, errors.New("zero keys in response")
	}

	ttl, ok, err := phttp.Cacheable(resp.Header)
	if err != nil {
		return nil, err
	}
	if !ok {
		ttl = DefaultPublicKeySetTTL
	}

	exp := time.Now().UTC().Add(ttl)
	ks := key.NewPublicKeySet(d.Keys, exp)
	return ks, nil
}
<|endoftext|>


<commit_before>package main

import (
	//"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"

	"firepear.net/asock"
	"github.com/sboyettedh/whiplash"
)

var (
	// whiplash configuration file
	whipconf string
	// map[cephstore][]osd - lets us do per-cephstore reporting easily
	osdmap map[string][]string
	// pre-rolled messages
	success = []byte("received")
)

func init() {
	flag.StringVar(&whipconf, "whipconf", "/etc/whiplash.json", "Whiplash configuration file")
	osdmap = make(map[string][]string)
}

func clientInit(fn string) (chan os.Signal, error) {
	// set up logfile
	f, err := os.Create("/var/log/" + fn + ".log")
	if err != nil {
		return nil, err
	}
	log.SetOutput(f)
	// write pidfile
	pidstr := strconv.Itoa(os.Getpid()) + "\n"
	err = ioutil.WriteFile("/var/run/" + fn + ".pid", []byte(pidstr), 0644)
	if err != nil {
		return nil, err
	}
	// and register SIGINT/SIGTERM handler
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM)
	return sigchan, err
}

func main() {
	// parse flags and read the whiplash configuration
	flag.Parse()
	sigchan, err := clientInit("whiplash")
	if err != nil{
		log.Fatal(err)
	}
	log.Printf("whiplash-aggregator v%v beginning operations\n", whiplash.Version)

	wl, err := whiplash.New(whipconf, false)
	if err != nil {
		log.Fatalf("could not read configuration file: %v\n", err)
		os.Exit(1)
	}

	asconf := asock.Config{
		Sockname: wl.Aggregator.BindAddr + ":" + wl.Aggregator.BindPort,
		Msglvl: asock.All,
		Timeout: 100,
	}
	as, err := asock.NewTCP(asconf)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("listening for clients")

	// set up command handlers
	handlers := map[string]asock.DispatchFunc{
		"ping": pingHandler,
	}
	for name, handler := range handlers {
		err = as.AddHandler(name, "nosplit", handler)
		if err != nil {
			log.Fatal(err)
		}
	}

	// create a channel for the asock Msgr handler and launch it
	msgchan := make(chan error, 1)
	go msgHandler(as, msgchan)

	// the mainloop
	keepalive := true
	for keepalive {
		select {
		case msg := <-msgchan:
			// we've been handed a Msg over msgchan, which means that
			// our Asock has shut itself down for some reason. if this
			// were a more robust server, we would modularize Asock
			// creation and this eventloop, so that should we trap a
			// 599 we could spawn a new Asock and launch it in this
			// one's place. but we're just gonna exit this loop,
			// causing main() to terminate, and with it the server
			// instance.
			log.Println("Asock instance has shut down. Last Msg received was:")
			log.Println(msg)
			keepalive = false
			break
		case <- sigchan:
			// we've trapped a signal from the OS. tell our Asock to
			// shut down, but don't exit the eventloop because we want
			// to handle the Msgs which will be incoming.
			log.Println("OS signal received; shutting down")
			as.Quit()
		}
		// there's no default case in the select, as that would cause
		// it to be nonblocking. and that would cause main() to exit
		// immediately.
	}
}

func msgHandler(as *asock.Asock, msgchan chan error) {
	var msg *asock.Msg
	keepalive := true

	for keepalive {
		// wait on a Msg to arrive and do a switch based on status code
		msg = <-as.Msgr
		switch msg.Code {
		case 599:
			// 599 is "the Asock listener has died". this means we're
			// not accepting connections anymore. call as.Quit() to
			// clean things up, send the Msg to our main routine, then
			// kill this for loop
			as.Quit()
			keepalive = false
			msgchan <- msg
		case 199:
			// 199 is "we've been told to quit", so we want to break
			// out of the 'for' here as well
			keepalive = false
			msgchan <- msg
		default:
			// anything else we just log!
			log.Println(msg)
		}
	}
}

func pingHandler(args [][]byte) ([]byte, error) {
	log.Println(string(args[0]))
	return []byte("ok"), nil
}
<commit_msg>now storing update info from services<commit_after>package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"

	"firepear.net/asock"
	"github.com/sboyettedh/whiplash"
)

var (
	// whiplash configuration file
	whipconf string
	// storage for current status of all reporting services
	svcs = map[string]*whiplash.SvcCore{}
	// map[cephstore][]svcname - lets us do per-cephstore reporting
	// until mon reporting of 'ceph osd tree' is in
	svcmap = map[string][]string{}
	// pre-rolled messages
	success = []byte("received")
)

func init() {
	flag.StringVar(&whipconf, "whipconf", "/etc/whiplash.json", "Whiplash configuration file")
}

func clientInit(fn string) (chan os.Signal, error) {
	// set up logfile
	f, err := os.Create("/var/log/" + fn + ".log")
	if err != nil {
		return nil, err
	}
	log.SetOutput(f)
	// write pidfile
	pidstr := strconv.Itoa(os.Getpid()) + "\n"
	err = ioutil.WriteFile("/var/run/" + fn + ".pid", []byte(pidstr), 0644)
	if err != nil {
		return nil, err
	}
	// and register SIGINT/SIGTERM handler
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM)
	return sigchan, err
}

func main() {
	// parse flags and read the whiplash configuration
	flag.Parse()
	sigchan, err := clientInit("whiplash")
	if err != nil{
		log.Fatal(err)
	}
	log.Printf("whiplash-aggregator v%v beginning operations\n", whiplash.Version)

	wl, err := whiplash.New(whipconf, false)
	if err != nil {
		log.Fatalf("could not read configuration file: %v\n", err)
		os.Exit(1)
	}

	asconf := asock.Config{
		Sockname: wl.Aggregator.BindAddr + ":" + wl.Aggregator.BindPort,
		Msglvl: asock.All,
		Timeout: 100,
	}
	as, err := asock.NewTCP(asconf)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("listening for clients")

	// set up command handlers
	handlers := map[string]asock.DispatchFunc{
		"ping": pingHandler,
	}
	for name, handler := range handlers {
		err = as.AddHandler(name, "nosplit", handler)
		if err != nil {
			log.Fatal(err)
		}
	}

	// create a channel for the asock Msgr handler and launch it
	msgchan := make(chan error, 1)
	go msgHandler(as, msgchan)

	// the mainloop
	keepalive := true
	for keepalive {
		select {
		case msg := <-msgchan:
			// we've been handed a Msg over msgchan, which means that
			// our Asock has shut itself down for some reason. if this
			// were a more robust server, we would modularize Asock
			// creation and this eventloop, so that should we trap a
			// 599 we could spawn a new Asock and launch it in this
			// one's place. but we're just gonna exit this loop,
			// causing main() to terminate, and with it the server
			// instance.
			log.Println("Asock instance has shut down. Last Msg received was:")
			log.Println(msg)
			keepalive = false
			break
		case <- sigchan:
			// we've trapped a signal from the OS. tell our Asock to
			// shut down, but don't exit the eventloop because we want
			// to handle the Msgs which will be incoming.
			log.Println("OS signal received; shutting down")
			as.Quit()
		}
		// there's no default case in the select, as that would cause
		// it to be nonblocking. and that would cause main() to exit
		// immediately.
	}
}

func msgHandler(as *asock.Asock, msgchan chan error) {
	var msg *asock.Msg
	keepalive := true

	for keepalive {
		// wait on a Msg to arrive and do a switch based on status code
		msg = <-as.Msgr
		switch msg.Code {
		case 599:
			// 599 is "the Asock listener has died". this means we're
			// not accepting connections anymore. call as.Quit() to
			// clean things up, send the Msg to our main routine, then
			// kill this for loop
			as.Quit()
			keepalive = false
			msgchan <- msg
		case 199:
			// 199 is "we've been told to quit", so we want to break
			// out of the 'for' here as well
			keepalive = false
			msgchan <- msg
		default:
			// anything else we just log!
			log.Println(msg)
		}
	}
}

func pingHandler(args [][]byte) ([]byte, error) {
	req := &whiplash.Request{}
	json.Unmarshal(args[0], req)
	if svc, ok := svcs[req.Svc.Name]; !ok {
		log.Printf("adding svc %v", req.Svc.Name)
		// add sercice to svcs
		svcs[req.Svc.Name] = req.Svc
		// and to svcmap
		if _, ok := svcmap[req.Svc.Host]; !ok {
			log.Printf("adding host %v", req.Svc.Host)
			svcmap[req.Svc.Host] = []string{}
		}
		svcmap[req.Svc.Host] = append(svcmap[req.Svc.Host], req.Svc.Name)
	} else {
		// TODO handle updates
		log.Printf("got update from %v", svc.Name)
	}
	return []byte("ok"), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/coreos/go-etcd/etcd"
	"log"
	"net"
	"strconv"
	"sync"
)

type service struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

type host struct {
	key  string
	addr string
}

type backends struct {
	config     *Config
	path       string
	hosts      []host
	lastIndex  int
	watchIndex uint64
	lock       sync.RWMutex
}

func NewBackends(c *Config) *backends {
  return &backends{config: c}
}

func (b *backends) Init() {
  peers := trimsplit(b.config.etcdAddress,",")
  client := etcd.NewClient(peers)
  b.Sync(client)
  go b.Watch(client)
}

func (b *backends) Dump(action string) {
	for _, v := range b.hosts {
		log.Printf("Dump after %s %s -> %s", action, v.key, v.addr)
	}
}

func (b *backends) Remove(key string) {
	match := -1
	for k, v := range b.hosts {
		if v.key == key {
			match = k
		}
	}

	b.hosts = append(b.hosts[:match], b.hosts[match+1:]...)
	b.Dump("remove")
}

func (b *backends) Update(node *etcd.Node, action string) {
	b.lock.Lock()
	defer b.lock.Unlock()

	log.Printf("key: %s action: %s value: %s", node.Key, action, string(node.Value))

	s := &service{}
	if action == "delete" || action == "expire" {
		b.Remove(node.Key)
		return
	}

	err := json.Unmarshal([]byte(node.Value), s)
	if err != nil {
		panic(err)
	}

	addr := net.JoinHostPort(s.Host, strconv.Itoa(s.Port))

	// TODO: create an actual set data structure
	for _, v := range b.hosts {
		if v.key == node.Key {
			b.Dump(action)
			return
		}
	}

	b.hosts = append(b.hosts, host{addr: addr, key: node.Key})
}

func (b *backends) Watch(client *etcd.Client) {
	receiver := make(chan *etcd.Response)
	go client.Watch(b.config.servicePath, uint64(b.watchIndex), true, receiver, nil)

	for {
		resp := <-receiver
		b.Update(resp.Node, resp.Action)
	}
}

func (b *backends) Sync(client *etcd.Client) error {
  log.Printf("Synchronizing path : %s", b.config.servicePath)
	resp, err := client.Get(b.config.servicePath, false, true)

	if err != nil {
		return err
	}

	for _, n := range resp.Node.Nodes {
		b.Update(&n, resp.Action)
	}

	// Begin the watch after this sync from the next sync
	b.watchIndex = resp.EtcdIndex + 1

	return nil
}

func (b *backends) Next() string {
	b.lock.RLock()
	defer b.lock.RUnlock()

	if len(b.hosts) == 0 {
		return ""
	}

	index := (b.lastIndex + 1) % len(b.hosts)
	b.lastIndex = index

	return b.hosts[index].addr
}
<commit_msg>NXIO-142: update the host addr when it has changed<commit_after>package main

import (
	"encoding/json"
	"github.com/coreos/go-etcd/etcd"
	"log"
	"net"
	"strconv"
	"sync"
)

type service struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

type host struct {
	key  string
	addr string
}

type backends struct {
	config     *Config
	path       string
	hosts      []host
	lastIndex  int
	watchIndex uint64
	lock       sync.RWMutex
}

func NewBackends(c *Config) *backends {
  return &backends{config: c}
}

func (b *backends) Init() {
  peers := trimsplit(b.config.etcdAddress,",")
  client := etcd.NewClient(peers)
  b.Sync(client)
  go b.Watch(client)
}

func (b *backends) Dump(action string) {
	for _, v := range b.hosts {
		log.Printf("Dump after %s %s -> %s", action, v.key, v.addr)
	}
}

func (b *backends) Remove(key string) {
	match := -1
	for k, v := range b.hosts {
		if v.key == key {
			match = k
		}
	}

	b.hosts = append(b.hosts[:match], b.hosts[match+1:]...)
	b.Dump("remove")
}

func (b *backends) Update(node *etcd.Node, action string) {
	b.lock.Lock()
	defer b.lock.Unlock()

	log.Printf("key: %s action: %s value: %s", node.Key, action, string(node.Value))

	s := &service{}
	if action == "delete" || action == "expire" {
		b.Remove(node.Key)
		return
	}

	err := json.Unmarshal([]byte(node.Value), s)
	if err != nil {
		panic(err)
	}

	addr := net.JoinHostPort(s.Host, strconv.Itoa(s.Port))

	// TODO: create an actual set data structure
	for _, v := range b.hosts {
		if v.key == node.Key {
			b.Dump(action)
			v.addr = addr
			return
		}
	}

	b.hosts = append(b.hosts, host{addr: addr, key: node.Key})
}

func (b *backends) Watch(client *etcd.Client) {
	receiver := make(chan *etcd.Response)
	go client.Watch(b.config.servicePath, uint64(b.watchIndex), true, receiver, nil)

	for {
		resp := <-receiver
		b.Update(resp.Node, resp.Action)
	}
}

func (b *backends) Sync(client *etcd.Client) error {
  log.Printf("Synchronizing path : %s", b.config.servicePath)
	resp, err := client.Get(b.config.servicePath, false, true)

	if err != nil {
		return err
	}

	for _, n := range resp.Node.Nodes {
		b.Update(&n, resp.Action)
	}

	// Begin the watch after this sync from the next sync
	b.watchIndex = resp.EtcdIndex + 1

	return nil
}

func (b *backends) Next() string {
	b.lock.RLock()
	defer b.lock.RUnlock()

	if len(b.hosts) == 0 {
		return ""
	}

	index := (b.lastIndex + 1) % len(b.hosts)
	b.lastIndex = index

	return b.hosts[index].addr
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"log"
	"net/url"
	"strings"

	"code.google.com/p/go.net/html"
	"code.google.com/p/rsc/blog/atom"
)

func sanitise(feed *atom.Feed, t *atom.Text) string {
	log.Printf("Processing content type: %q", t.Type)
	r := strings.NewReader(t.Body)
	var w bytes.Buffer
	n, err := html.Parse(r)
	if err != nil {
		log.Print(err)
		return ""
	}
	absoluteImgTag(baseURLForFeed(feed), n)
	if err := html.Render(&w, n); err != nil {
		log.Print(err)
		return ""
	}
	return w.String()
}

// correct all <img> tags to use absolute urls.
func absoluteImgTag(base *url.URL, n *html.Node) {
	if n.Type == html.ElementNode && n.Data == "img" {
		for i, a := range n.Attr {
			if a.Key == "src" {
				u, err := url.Parse(a.Val)
				if err != nil {
					log.Fatal(err)
				}
				if u.Host == "" {
					// url is relative, append the path to the base url for the feed
					u = base.ResolveReference(u)
					n.Attr[i].Val = u.String()
				}
				break
			}
		}
	}
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		absoluteImgTag(base, c)
	}
}

// remove any class attributes, we want to add out own later.
func stripClassAttr(nn []html.Attribute) []html.Attribute {
	var v []html.Attribute
	for _, n := range nn {
		if n.Key == "class" {
			continue
		}
		v = append(v, n)
	}
	return v
}

func baseURLForFeed(f *atom.Feed) *url.URL {
	for _, l := range f.Link {
		u, _ := url.Parse(l.Href)
		u.Path = "/"
		return u
	}
	panic("no base")
}
<commit_msg>Force img-responsive<commit_after>package main

import (
	"bytes"
	"log"
	"net/url"
	"strings"

	"code.google.com/p/go.net/html"
	"code.google.com/p/rsc/blog/atom"
)

func sanitise(feed *atom.Feed, t *atom.Text) string {
	log.Printf("Processing content type: %q", t.Type)
	r := strings.NewReader(t.Body)
	var w bytes.Buffer
	n, err := html.Parse(r)
	if err != nil {
		log.Print(err)
		return ""
	}
	absoluteImgTag(baseURLForFeed(feed), n)
	if err := html.Render(&w, n); err != nil {
		log.Print(err)
		return ""
	}
	return w.String()
}

// correct all <img> tags to use absolute urls.
func absoluteImgTag(base *url.URL, n *html.Node) {
	if n.Type == html.ElementNode && n.Data == "img" {
		n.Attr = stripClassAttr(n.Attr)
		for i, a := range n.Attr {
			if a.Key == "src" {
				u, err := url.Parse(a.Val)
				if err != nil {
					log.Fatal(err)
				}
				if u.Host == "" {
					// url is relative, append the path to the base url for the feed
					u = base.ResolveReference(u)
					n.Attr[i].Val = u.String()
				}
				break
			}
		}
		n.Attr = append(n.Attr, html.Attribute{Key: "class", Val: "img-responsive"})
	}
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		absoluteImgTag(base, c)
	}
}

// remove any class attributes, we want to add out own later.
func stripClassAttr(nn []html.Attribute) []html.Attribute {
	var v []html.Attribute
	for _, n := range nn {
		if n.Key == "class" {
			continue
		}
		v = append(v, n)
	}
	return v
}

func baseURLForFeed(f *atom.Feed) *url.URL {
	for _, l := range f.Link {
		u, _ := url.Parse(l.Href)
		u.Path = "/"
		return u
	}
	panic("no base")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"log"
	"strings"

	"golang.org/x/net/html"

	"github.com/JalfResi/justext"
)

// Convert HTML
func ConvertHTML(r io.Reader, readability bool) (string, map[string]string) {
	meta := make(map[string]string)

	buf := new(bytes.Buffer)
	buf.ReadFrom(r)

	cleanXML, err := Tidy(buf, false)
	if err != nil {
		log.Println("Tidy:", err)
		// Tidy failed, so we now manually tokenize instead
		clean := cleanHTML(buf, true)
		cleanXML = []byte(clean)
		log.Println("Cleaned HTML using Golang tokenizer")
	}

	if readability {
		cleanXML = HTMLReadability(bytes.NewReader(cleanXML))
	}
	return HTMLToText(bytes.NewReader(cleanXML)), meta
}

// Tests for known friendly HTML parameters that tidy is unlikely to choke on
func acceptedHTML(str string) bool {
	tags := []string{"div", "p", "br", "span", "body", "head", "html", "ul", "ol", "li", "dl", "dt", "dd", "a", "form", "article", "section", "table", "tr", "td", "tbody", "thead", "th", "tfoot", "col", "colgroup", "caption", "form", "input", "title", "h1", "h2", "h3", "h4", "h5", "h6", "meta", "strong", "cite", "em", "address", "abbr", "acronym", "blockquote", "q", "pre", "samp", "select", "fieldset", "legend", "button", "option", "textarea", "label"}
	for _, tag := range tags {
		if tag == str {
			return true
		}
	}
	return false
}

// Removes scripts, comments, styles and parameters from HTML.
// Also removes made up tags, e.g. <fb:like>
// Can keep head elements or not. Typically not much in there.
func cleanHTML(r io.Reader, all bool) string {
	d := html.NewTokenizer(r)

	output := ""
	if !all {
		output = ""
	}
	mainsection := false
	junksection := false

	for {
		// token type
		tokenType := d.Next()
		if tokenType == html.ErrorToken {
			return output
		}
		token := d.Token()

		switch tokenType {
		case html.StartTagToken: // <tag>
			if token.Data == "body" || (token.Data == "html" && all) {
				mainsection = true
			}
			if !acceptedHTML(token.Data) {
				junksection = true
			}

			if !junksection && mainsection {
				output += "<" + token.Data + ">"
			}

		case html.TextToken: // text between start and end tag
			if !junksection && mainsection {
				output += token.Data
			}

		case html.EndTagToken: // </tag>
			if !junksection && mainsection {
				output += "</" + token.Data + ">"
			}
			if !acceptedHTML(token.Data) {
				junksection = false
			}

		case html.SelfClosingTagToken: // <tag/>
			if !junksection && mainsection {
				output += "<" + token.Data + " />" // TODO: Can probably keep attributes from the meta tags
			}
		}
	}
}

// Extract the readable text in an HTML document
func HTMLReadability(r io.Reader) []byte {
	jr := justext.NewReader(r)
	jr.Stoplist = readabilityStopList
	jr.LengthLow = *readabilityLengthLow
	jr.LengthHigh = *readabilityLengthHigh
	jr.StopwordsLow = *readabilityStopwordsLow
	jr.StopwordsHigh = *readabilityStopwordsHigh
	jr.MaxLinkDensity = *readabilityMaxLinkDensity
	jr.MaxHeadingDistance = *readabilityMaxHeadingDistance

	paragraphSet, err := jr.ReadAll()
	if err != nil {
		log.Println("Justext:", err)
		return nil
	}

	useClasses := strings.SplitN(*readabilityUseClasses, ",", 10)

	var output string = ""
	for _, paragraph := range paragraphSet {
		for _, class := range useClasses {
			if paragraph.CfClass == class {
				output += paragraph.Text + "\n"
			}
		}
	}

	return []byte(output)
}

func HTMLToText(input io.Reader) string {
	return XMLToText(input, []string{"br", "p", "h1", "h2", "h3", "h4"}, []string{}, false)
}

var readabilityStopList map[string]bool = map[string]bool{"and": true, "the": true, "a": true, "about": true, "above": true, "across": true, "after": true, "afterwards": true, "again": true, "against": true, "all": true, "almost": true, "alone": true,
	"along": true, "already": true, "also": true, "although": true, "always": true, "am": true, "among": true, "amongst": true, "amoungst": true, "amount": true, "an": true, "another": true, "any": true,
	"anyhow": true, "anyone": true, "anything": true, "anyway": true, "anywhere": true, "are": true, "around": true, "as": true, "at": true, "back": true, "be": true, "became": true, "because": true,
	"become": true, "becomes": true, "becoming": true, "been": true, "before": true, "beforehand": true, "behind": true, "being": true, "below": true, "beside": true, "besides": true, "between": true,
	"beyond": true, "both": true, "bottom": true, "but": true, "by": true, "can": true, "cannot": true, "cant": true, "co": true, "con": true, "could": true, "couldnt": true, "cry": true,
	"de": true, "describe": true, "detail": true, "do": true, "done": true, "down": true, "due": true, "during": true, "each": true, "eg": true, "eight": true, "either": true, "eleven": true, "else": true,
	"elsewhere": true, "empty": true, "enough": true, "etc": true, "even": true, "ever": true, "every": true, "everyone": true, "everything": true, "everywhere": true, "except": true, "few": true,
	"fifteen": true, "fify": true, "fill": true, "find": true, "fire": true, "first": true, "five": true, "for": true, "former": true, "formerly": true, "forty": true, "found": true, "four": true, "from": true,
	"front": true, "full": true, "further": true, "get": true, "give": true, "go": true, "had": true, "has": true, "hasnt": true, "have": true, "he": true, "hence": true, "her": true, "here": true, "hereafter": true,
	"hereby": true, "herein": true, "hereupon": true, "hers": true, "herself": true, "him": true, "himself": true, "his": true, "how": true, "however": true, "hundred": true, "ie": true, "if": true, "in": true,
	"inc": true, "indeed": true, "interest": true, "into": true, "is": true, "it": true, "its": true, "itself": true, "keep": true, "last": true, "latter": true, "latterly": true, "least": true, "less": true,
	"ltd": true, "made": true, "many": true, "may": true, "me": true, "meanwhile": true, "might": true, "mill": true, "mine": true, "more": true, "moreover": true, "most": true, "mostly": true, "move": true,
	"much": true, "must": true, "my": true, "myself": true, "name": true, "namely": true, "neither": true, "never": true, "nevertheless": true, "next": true, "nine": true, "no": true, "nobody": true,
	"none": true, "noone": true, "nor": true, "not": true, "nothing": true, "now": true, "nowhere": true, "of": true, "off": true, "often": true, "on": true, "once": true, "one": true, "only": true, "onto": true,
	"or": true, "other": true, "others": true, "otherwise": true, "our": true, "ours": true, "ourselves": true, "out": true, "over": true, "own": true, "part": true, "per": true, "perhaps": true,
	"please": true, "put": true, "rather": true, "re": true, "same": true, "see": true, "seem": true, "seemed": true, "seeming": true, "seems": true, "serious": true, "several": true, "she": true,
	"should": true, "show": true, "side": true, "since": true, "sincere": true, "six": true, "sixty": true, "so": true, "some": true, "somehow": true, "someone": true, "something": true, "sometime": true,
	"sometimes": true, "somewhere": true, "still": true, "such": true, "take": true, "ten": true, "than": true, "that": true, "their": true, "them": true, "themselves": true,
	"then": true, "thence": true, "there": true, "thereafter": true, "thereby": true, "therefore": true, "therein": true, "thereupon": true, "these": true, "they": true, "thickv": true, "thin": true,
	"third": true, "this": true, "those": true, "though": true, "three": true, "through": true, "throughout": true, "thru": true, "thus": true, "to": true, "together": true, "too": true, "top": true,
	"toward": true, "towards": true, "twelve": true, "twenty": true, "two": true, "un": true, "under": true, "until": true, "up": true, "upon": true, "us": true, "very": true, "via": true, "was": true, "we": true,
	"well": true, "were": true, "what": true, "whatever": true, "when": true, "whence": true, "whenever": true, "where": true, "whereafter": true, "whereas": true, "whereby": true, "wherein": true,
	"whereupon": true, "wherever": true, "whether": true, "which": true, "while": true, "whither": true, "who": true, "whoever": true, "whole": true, "whom": true, "whose": true, "why": true, "will": true,
	"with": true, "within": true, "without": true, "would": true, "yet": true, "you": true, "your": true, "youre": true, "yours": true, "yourself": true, "yourselves": true, "www": true, "com": true, "http": true}
<commit_msg>Small refactoring to HTML converter.<commit_after>package main

import (
	"bytes"
	"io"
	"log"
	"strings"

	"golang.org/x/net/html"

	"github.com/JalfResi/justext"
)

// Convert HTML
func ConvertHTML(r io.Reader, readability bool) (string, map[string]string) {
	meta := make(map[string]string)

	buf := new(bytes.Buffer)
	buf.ReadFrom(r)

	cleanXML, err := Tidy(buf, false)
	if err != nil {
		log.Println("Tidy:", err)
		// Tidy failed, so we now manually tokenize instead
		clean := cleanHTML(buf, true)
		cleanXML = []byte(clean)
		log.Println("Cleaned HTML using Golang tokenizer")
	}

	if readability {
		cleanXML = HTMLReadability(bytes.NewReader(cleanXML))
	}
	return HTMLToText(bytes.NewReader(cleanXML)), meta
}

var acceptedHTMLTags = [...]string{
	"div", "p", "br", "span", "body", "head", "html", "ul", "ol", "li", "dl", "dt", "dd", "a", "form", "article",
	"section", "table", "tr", "td", "tbody", "thead", "th", "tfoot", "col", "colgroup", "caption", "form", "input",
	"title", "h1", "h2", "h3", "h4", "h5", "h6", "meta", "strong", "cite", "em", "address", "abbr", "acronym",
	"blockquote", "q", "pre", "samp", "select", "fieldset", "legend", "button", "option", "textarea", "label",
}

// Tests for known friendly HTML parameters that tidy is unlikely to choke on
func acceptedHTMLTag(tagName string) bool {
	for _, tag := range acceptedHTMLTags {
		if tag == tagName {
			return true
		}
	}
	return false
}

// Removes scripts, comments, styles and parameters from HTML.
// Also removes made up tags, e.g. <fb:like>
// Can keep head elements or not. Typically not much in there.
func cleanHTML(r io.Reader, all bool) string {
	output := ""
	if !all {
		output = ""
	}
	mainSection := false
	junkSection := false

	d := html.NewTokenizer(r)
	for {
		// token type
		tokenType := d.Next()
		if tokenType == html.ErrorToken {
			return output
		}
		token := d.Token()

		switch tokenType {
		case html.StartTagToken: // <tag>
			if token.Data == "body" || (token.Data == "html" && all) {
				mainSection = true
			}
			if !acceptedHTMLTag(token.Data) {
				junkSection = true
			}

			if !junkSection && mainSection {
				output += "<" + token.Data + ">"
			}

		case html.TextToken: // text between start and end tag
			if !junkSection && mainSection {
				output += token.Data
			}

		case html.EndTagToken: // </tag>
			if !junkSection && mainSection {
				output += "</" + token.Data + ">"
			}
			if !acceptedHTMLTag(token.Data) {
				junkSection = false
			}

		case html.SelfClosingTagToken: // <tag/>
			if !junkSection && mainSection {
				output += "<" + token.Data + " />" // TODO: Can probably keep attributes from the meta tags
			}
		}
	}
}

// Extract the readable text in an HTML document
func HTMLReadability(r io.Reader) []byte {
	jr := justext.NewReader(r)
	jr.Stoplist = readabilityStopList
	jr.LengthLow = *readabilityLengthLow
	jr.LengthHigh = *readabilityLengthHigh
	jr.StopwordsLow = *readabilityStopwordsLow
	jr.StopwordsHigh = *readabilityStopwordsHigh
	jr.MaxLinkDensity = *readabilityMaxLinkDensity
	jr.MaxHeadingDistance = *readabilityMaxHeadingDistance

	paragraphSet, err := jr.ReadAll()
	if err != nil {
		log.Println("Justext:", err)
		return nil
	}

	useClasses := strings.SplitN(*readabilityUseClasses, ",", 10)

	var output string = ""
	for _, paragraph := range paragraphSet {
		for _, class := range useClasses {
			if paragraph.CfClass == class {
				output += paragraph.Text + "\n"
			}
		}
	}

	return []byte(output)
}

func HTMLToText(input io.Reader) string {
	return XMLToText(input, []string{"br", "p", "h1", "h2", "h3", "h4"}, []string{}, false)
}

var readabilityStopList map[string]bool = map[string]bool{"and": true, "the": true, "a": true, "about": true, "above": true, "across": true, "after": true, "afterwards": true, "again": true, "against": true, "all": true, "almost": true, "alone": true,
	"along": true, "already": true, "also": true, "although": true, "always": true, "am": true, "among": true, "amongst": true, "amoungst": true, "amount": true, "an": true, "another": true, "any": true,
	"anyhow": true, "anyone": true, "anything": true, "anyway": true, "anywhere": true, "are": true, "around": true, "as": true, "at": true, "back": true, "be": true, "became": true, "because": true,
	"become": true, "becomes": true, "becoming": true, "been": true, "before": true, "beforehand": true, "behind": true, "being": true, "below": true, "beside": true, "besides": true, "between": true,
	"beyond": true, "both": true, "bottom": true, "but": true, "by": true, "can": true, "cannot": true, "cant": true, "co": true, "con": true, "could": true, "couldnt": true, "cry": true,
	"de": true, "describe": true, "detail": true, "do": true, "done": true, "down": true, "due": true, "during": true, "each": true, "eg": true, "eight": true, "either": true, "eleven": true, "else": true,
	"elsewhere": true, "empty": true, "enough": true, "etc": true, "even": true, "ever": true, "every": true, "everyone": true, "everything": true, "everywhere": true, "except": true, "few": true,
	"fifteen": true, "fify": true, "fill": true, "find": true, "fire": true, "first": true, "five": true, "for": true, "former": true, "formerly": true, "forty": true, "found": true, "four": true, "from": true,
	"front": true, "full": true, "further": true, "get": true, "give": true, "go": true, "had": true, "has": true, "hasnt": true, "have": true, "he": true, "hence": true, "her": true, "here": true, "hereafter": true,
	"hereby": true, "herein": true, "hereupon": true, "hers": true, "herself": true, "him": true, "himself": true, "his": true, "how": true, "however": true, "hundred": true, "ie": true, "if": true, "in": true,
	"inc": true, "indeed": true, "interest": true, "into": true, "is": true, "it": true, "its": true, "itself": true, "keep": true, "last": true, "latter": true, "latterly": true, "least": true, "less": true,
	"ltd": true, "made": true, "many": true, "may": true, "me": true, "meanwhile": true, "might": true, "mill": true, "mine": true, "more": true, "moreover": true, "most": true, "mostly": true, "move": true,
	"much": true, "must": true, "my": true, "myself": true, "name": true, "namely": true, "neither": true, "never": true, "nevertheless": true, "next": true, "nine": true, "no": true, "nobody": true,
	"none": true, "noone": true, "nor": true, "not": true, "nothing": true, "now": true, "nowhere": true, "of": true, "off": true, "often": true, "on": true, "once": true, "one": true, "only": true, "onto": true,
	"or": true, "other": true, "others": true, "otherwise": true, "our": true, "ours": true, "ourselves": true, "out": true, "over": true, "own": true, "part": true, "per": true, "perhaps": true,
	"please": true, "put": true, "rather": true, "re": true, "same": true, "see": true, "seem": true, "seemed": true, "seeming": true, "seems": true, "serious": true, "several": true, "she": true,
	"should": true, "show": true, "side": true, "since": true, "sincere": true, "six": true, "sixty": true, "so": true, "some": true, "somehow": true, "someone": true, "something": true, "sometime": true,
	"sometimes": true, "somewhere": true, "still": true, "such": true, "take": true, "ten": true, "than": true, "that": true, "their": true, "them": true, "themselves": true,
	"then": true, "thence": true, "there": true, "thereafter": true, "thereby": true, "therefore": true, "therein": true, "thereupon": true, "these": true, "they": true, "thickv": true, "thin": true,
	"third": true, "this": true, "those": true, "though": true, "three": true, "through": true, "throughout": true, "thru": true, "thus": true, "to": true, "together": true, "too": true, "top": true,
	"toward": true, "towards": true, "twelve": true, "twenty": true, "two": true, "un": true, "under": true, "until": true, "up": true, "upon": true, "us": true, "very": true, "via": true, "was": true, "we": true,
	"well": true, "were": true, "what": true, "whatever": true, "when": true, "whence": true, "whenever": true, "where": true, "whereafter": true, "whereas": true, "whereby": true, "wherein": true,
	"whereupon": true, "wherever": true, "whether": true, "which": true, "while": true, "whither": true, "who": true, "whoever": true, "whole": true, "whom": true, "whose": true, "why": true, "will": true,
	"with": true, "within": true, "without": true, "would": true, "yet": true, "you": true, "your": true, "youre": true, "yours": true, "yourself": true, "yourselves": true, "www": true, "com": true, "http": true}
<|endoftext|>


<commit_before>package fileutil

import (
	"bytes"
	"io"
	"io/fs"
	"os"
	"strings"
)

var (
	// FS is the filesystem that Open, ReadFile and ReadDir will query.
	FS fs.FS = os.DirFS(".")
	// FixWindowsPaths will reset all file paths loaded to replace windows style slashes
	// with unix style slashes. This is important when using io/fs or embed, because the
	// path/filepath package will produce windows style paths on a windows system, but
	// these stdlib packages will reject all windows paths.
	FixWindowsPaths = true
	// OSFallback will fallback to loading via os.Open / io.ReadFile if loading otherwise fails.
	// This is necessary when reading system level fallback fonts. Fixed paths will not be applied
	// to this fallback route.
	OSFallback = true
)

// Open is a wrapper around os.Open that will also check BindataFn to access
// embedded data. The intended use is to use the an embedding library to create an
// Asset function that matches this signature.
func Open(file string) (io.ReadCloser, error) {
	fixedPath := fixWindowsPath(file)
	f, readErr := FS.Open(fixedPath)
	if readErr != nil && OSFallback {
		byt, err := os.ReadFile(file)
		if err != nil {
			return nil, err
		}
		return io.NopCloser(bytes.NewReader(byt)), nil
	}
	return f, readErr
}

// ReadFile replaces ioutil.ReadFile, trying to use the BindataFn if it exists.
func ReadFile(file string) ([]byte, error) {
	fixedPath := fixWindowsPath(file)
	data, readErr := fs.ReadFile(FS, fixedPath)
	if readErr != nil && OSFallback {
		return os.ReadFile(file)
	}
	return data, readErr
}

// ReadDir replaces ioutil.ReadDir, trying to use the BinaryDir if it exists.
func ReadDir(file string) ([]fs.DirEntry, error) {
	fixedPath := fixWindowsPath(file)
	return fs.ReadDir(FS, fixedPath)
}

func fixWindowsPath(file string) string {
	if !FixWindowsPaths {
		return file
	}
	file = strings.Replace(file, "\\", "/", -1)
	return file
}
<commit_msg>fileutil: update comments to reference FS variable<commit_after>package fileutil

import (
	"bytes"
	"io"
	"io/fs"
	"os"
	"strings"
)

var (
	// FS is the filesystem that Open, ReadFile and ReadDir will query.
	FS fs.FS = os.DirFS(".")
	// FixWindowsPaths will reset all file paths loaded to replace windows style slashes
	// with unix style slashes. This is important when using io/fs or embed, because the
	// path/filepath package will produce windows style paths on a windows system, but
	// these stdlib packages will reject all windows paths.
	FixWindowsPaths = true
	// OSFallback will fallback to loading via os.Open / io.ReadFile if loading otherwise fails.
	// This is necessary when reading system level fallback fonts. Fixed paths will not be applied
	// to this fallback route.
	OSFallback = true
)

// Open is a wrapper around os.Open that will also check FS to access
// embedded data. The intended use is to use the an embedding library to create an
// Asset function that matches this signature.
func Open(file string) (io.ReadCloser, error) {
	fixedPath := fixWindowsPath(file)
	f, readErr := FS.Open(fixedPath)
	if readErr != nil && OSFallback {
		byt, err := os.ReadFile(file)
		if err != nil {
			return nil, err
		}
		return io.NopCloser(bytes.NewReader(byt)), nil
	}
	return f, readErr
}

// ReadFile replaces ioutil.ReadFile, trying to use FS.
func ReadFile(file string) ([]byte, error) {
	fixedPath := fixWindowsPath(file)
	data, readErr := fs.ReadFile(FS, fixedPath)
	if readErr != nil && OSFallback {
		return os.ReadFile(file)
	}
	return data, readErr
}

// ReadDir replaces ioutil.ReadDir, trying to use FS.
func ReadDir(file string) ([]fs.DirEntry, error) {
	fixedPath := fixWindowsPath(file)
	return fs.ReadDir(FS, fixedPath)
}

func fixWindowsPath(file string) string {
	if !FixWindowsPaths {
		return file
	}
	file = strings.Replace(file, "\\", "/", -1)
	return file
}
<|endoftext|>


<commit_before>package gen

import (
	"encoding/json"
	"os"

	"github.com/gernest/valeria/gen"
	"github.com/gernest/valeria/vm"
	"github.com/robertkrimen/otto"
	"github.com/spf13/afero"
)

const (
	scriptsDir = "_scripts"
	initDri    = "init"
	planDir    = "plan"
	configFile = "config.json"
)

type BuildError struct {
	Stage   string `json:"stage"`
	Message string `json:"msg"`
}

func buildErr(stage, msg string) error {
	return &BuildError{Stage: stage, Message: msg}
}

func (b *BuildError) Error() string {
	o, err := json.Marshal(b)
	if err != nil {
		return err.Error()
	}
	return string(o)
}

type Generator struct {
	vm  *vm.VM
	sys *gen.System
	fs  afero.Fs
}

func (g *Generator) Build() error {
	return evaluate(g.init, g.config, g.plan, g.exec, g.down)
}
func (g *Generator) init() error {
	if g.sys == nil {
		g.sys = defalutSystem()
	}
	if g.vm == nil {
		g.vm = defaultVM(g.sys)
	}
	g.vm.Set("sys", func(call otto.FunctionCall) otto.Value {
		data, err := json.Marshal(g.sys)
		if err != nil {
			vm.Panic(err)
		}
		val, err := call.Otto.Call("JSON.parse", nil, string(data))
		if err != nil {
			vm.Panic(err)
		}
		return val
	})
	_, err := g.vm.Eval(entryScript())
	if err != nil {
		return buildErr("init", err.Error())
	}
	return nil
}

func defalutSystem() *gen.System {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return &gen.System{
		Boot: &gen.Boot{
			ConfigiFile: configFile,
			PlanFile:    "index.js",
		},
		WorkDir: pwd,
	}
}

func defaultVM(sys *gen.System) *vm.VM {
	return &vm.VM{otto.New()}
}
func (g *Generator) config() error {
	return nil
}
func (g *Generator) plan() error {
	return nil
}
func (g *Generator) exec() error {
	return nil
}
func (g *Generator) down() error {
	return nil
}

func evaluate(fn ...func() error) error {
	var err error
	for _, f := range fn {
		err = f()
		if err != nil {
			return err
		}
	}
	return err
}
<commit_msg>Fx typo<commit_after>package gen

import (
	"encoding/json"
	"os"

	"github.com/gernest/valeria/gen"
	"github.com/gernest/valeria/vm"
	"github.com/robertkrimen/otto"
	"github.com/spf13/afero"
)

const (
	scriptsDir = "_scripts"
	initDri    = "init"
	planDir    = "plan"
	configFile = "config.json"
)

type BuildError struct {
	Stage   string `json:"stage"`
	Message string `json:"msg"`
}

func buildErr(stage, msg string) error {
	return &BuildError{Stage: stage, Message: msg}
}

func (b *BuildError) Error() string {
	o, err := json.Marshal(b)
	if err != nil {
		return err.Error()
	}
	return string(o)
}

type Generator struct {
	vm  *vm.VM
	sys *gen.System
	fs  afero.Fs
}

func (g *Generator) Build() error {
	return evaluate(g.init, g.config, g.plan, g.exec, g.down)
}
func (g *Generator) init() error {
	if g.sys == nil {
		g.sys = defaultSystem()
	}
	if g.vm == nil {
		g.vm = defaultVM(g.sys)
	}
	g.vm.Set("sys", func(call otto.FunctionCall) otto.Value {
		data, err := json.Marshal(g.sys)
		if err != nil {
			vm.Panic(err)
		}
		val, err := call.Otto.Call("JSON.parse", nil, string(data))
		if err != nil {
			vm.Panic(err)
		}
		return val
	})
	_, err := g.vm.Eval(entryScript())
	if err != nil {
		return buildErr("init", err.Error())
	}
	return nil
}

func defaultSystem() *gen.System {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return &gen.System{
		Boot: &gen.Boot{
			ConfigiFile: configFile,
			PlanFile:    "index.js",
		},
		WorkDir: pwd,
	}
}

func defaultVM(sys *gen.System) *vm.VM {
	return &vm.VM{otto.New()}
}
func (g *Generator) config() error {
	return nil
}
func (g *Generator) plan() error {
	return nil
}
func (g *Generator) exec() error {
	return nil
}
func (g *Generator) down() error {
	return nil
}

func evaluate(fn ...func() error) error {
	var err error
	for _, f := range fn {
		err = f()
		if err != nil {
			return err
		}
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/simeji/jid"
)

const VERSION = "0.7.2"

func main() {
	content := os.Stdin

	var qm bool
	var help bool
	var version bool
	var mono bool
	qs := "."

	flag.BoolVar(&qm, "q", false, "Output query mode")
	flag.BoolVar(&help, "h", false, "print a help")
	flag.BoolVar(&help, "help", false, "print a help")
	flag.BoolVar(&version, "version", false, "print the version and exit")
	flag.BoolVar(&mono, "M", false, "monochrome output mode")
	flag.Parse()

	if help {
		fmt.Println(getHelpString())
		os.Exit(0)
	}

	if version {
		fmt.Println(fmt.Sprintf("jid version v%s", VERSION))
		os.Exit(0)
	}
	args := flag.Args()
	if len(args) > 0 {
		qs = args[0]
	}

	ea := &jid.EngineAttribute{
		DefaultQuery: qs,
		Monochrome:   mono,
	}

	e, err := jid.NewEngine(content, ea)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	os.Exit(run(e, qm))
}

func run(e jid.EngineInterface, qm bool) int {

	result := e.Run()
	if result.GetError() != nil {
		return 2
	}
	if qm {
		fmt.Printf("%s", result.GetQueryString())
	} else {
		fmt.Printf("%s", result.GetContent())
	}
	return 0
}

func getHelpString() string {
	return `

============ Load JSON from a file ==============

$ jid < file.json

============ With a JSON filter mode =============

TAB / CTRL-I
  Show available items and choice them

CTRL-W
  Delete from the cursor to the start of the word

CTRL-U
  Delete whole query

CTRL-F / Right Arrow
  Move cursor a character to the right

CTRL-B / Left Arrow
  Move cursor a character to the left

CTRL-A
  To the first character of the 'Filter'

CTRL-E
  To the end of the 'Filter'

CTRL-J
  Scroll json buffer 1 line downwards

CTRL-K
  Scroll json buffer 1 line upwards

CTRL-G
  Scroll json buffer to bottom

CTRL-T
  Scroll json buffer to top

CTRL-L
  Change view mode whole json or keys (only object)

ESC
  Hide a candidate box

`
}
<commit_msg>flags usage on -help<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/simeji/jid"
)

const VERSION = "0.7.2"

func main() {
	content := os.Stdin

	var qm bool
	var help bool
	var version bool
	var mono bool
	qs := "."

	flag.BoolVar(&qm, "q", false, "Output query mode")
	flag.BoolVar(&help, "h", false, "print a help")
	flag.BoolVar(&help, "help", false, "print a help")
	flag.BoolVar(&version, "version", false, "print the version and exit")
	flag.BoolVar(&mono, "M", false, "monochrome output mode")
	flag.Parse()

	if help {
		flag.Usage()
		fmt.Println(getHelpString())
		os.Exit(0)
	}

	if version {
		fmt.Println(fmt.Sprintf("jid version v%s", VERSION))
		os.Exit(0)
	}
	args := flag.Args()
	if len(args) > 0 {
		qs = args[0]
	}

	ea := &jid.EngineAttribute{
		DefaultQuery: qs,
		Monochrome:   mono,
	}

	e, err := jid.NewEngine(content, ea)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	os.Exit(run(e, qm))
}

func run(e jid.EngineInterface, qm bool) int {

	result := e.Run()
	if result.GetError() != nil {
		return 2
	}
	if qm {
		fmt.Printf("%s", result.GetQueryString())
	} else {
		fmt.Printf("%s", result.GetContent())
	}
	return 0
}

func getHelpString() string {
	return `

============ Load JSON from a file ==============

$ jid < file.json

============ With a JSON filter mode =============

TAB / CTRL-I
  Show available items and choice them

CTRL-W
  Delete from the cursor to the start of the word

CTRL-U
  Delete whole query

CTRL-F / Right Arrow
  Move cursor a character to the right

CTRL-B / Left Arrow
  Move cursor a character to the left

CTRL-A
  To the first character of the 'Filter'

CTRL-E
  To the end of the 'Filter'

CTRL-J
  Scroll json buffer 1 line downwards

CTRL-K
  Scroll json buffer 1 line upwards

CTRL-G
  Scroll json buffer to bottom

CTRL-T
  Scroll json buffer to top

CTRL-L
  Change view mode whole json or keys (only object)

ESC
  Hide a candidate box

`
}
<|endoftext|>


<commit_before>package lily

import (
	"bytes"
	"encoding/json"
	"fmt"
	"errors"
	"net/http"
	"time"
	"net/http/cookiejar"
	"strings"
	"net"
	"path/filepath"
	"os"
	"io"
)

func HTTPSetContentTypeJSON(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
}

func HTTPRespondStr(w http.ResponseWriter, code int, body string) {
	if len(body) == 0 {
		panic("body must be not empty")
	}
	w.WriteHeader(code)
	fmt.Fprint(w, body)
}

func HTTPRespondJSONObj(w http.ResponseWriter, code int, obj interface{}) {
	HTTPSetContentTypeJSON(w)
	w.WriteHeader(code)
	ErrPanic(json.NewEncoder(w).Encode(obj))
}

func HTTPRespondJSONParseError(w http.ResponseWriter) {
	HTTPRespond400(w, "bad_json", "Fail to parse JSON")
}

func HTTPSendRequest(method, url string, data []byte, timeout time.Duration, headers ...string) (*http.Response, error) {
	var err error
	var req *http.Request
	if data != nil {
		req, err = http.NewRequest(method, url, bytes.NewBuffer(data))
		ErrPanic(err)
	} else {
		req, err = http.NewRequest(method, url, nil)
		ErrPanic(err)
	}
	for i := 0; (i + 1) < len(headers); i += 2 {
		req.Header.Set(headers[i], headers[i+1])
	}
	jar, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Timeout: timeout,
		Jar:     jar,
	}
	return client.Do(req)
}

func HTTPSendRequestJSON(method, url string, obj interface{}, timeout time.Duration, headers ...string) (*http.Response, error) {
	var err error
	var data []byte
	if obj != nil {
		data, err = json.Marshal(obj)
		ErrPanic(err)
	}
	headers = append(headers, "Content-Type", "application/json")
	return HTTPSendRequest(method, url, data, timeout, headers...)
}

func HTTPSendJARRequest(jar *cookiejar.Jar, method, url string, data []byte, timeout time.Duration, headers ...string) (*http.Response, *cookiejar.Jar, error) {
	var err error
	var req *http.Request
	if data != nil {
		req, err = http.NewRequest(method, url, bytes.NewBuffer(data))
		ErrPanic(err)
	} else {
		req, err = http.NewRequest(method, url, nil)
		ErrPanic(err)
	}
	for i := 0; (i + 1) < len(headers); i += 2 {
		req.Header.Set(headers[i], headers[i+1])
	}
	if jar == nil {
		jar, err = cookiejar.New(nil)
		if err != nil {
			return nil, nil, err
		}
	}
	client := &http.Client{
		Timeout: timeout,
		Jar:     jar,
	}
	response, err := client.Do(req)
	return response, jar, err
}

func HTTPRetrieveRequestURL(r *http.Request) string {
	scheme := r.Header.Get("X-Forwarded-Proto")
	if scheme == "" {
		if r.TLS == nil {
			scheme = "http"
		} else {
			scheme = "https"
		}
	}
	return scheme + "://" + r.Host
}

func HTTPRetrieveRemoteIP(r *http.Request) (result string) {
	result = ""
	if parts := strings.Split(r.RemoteAddr, ":"); len(parts) == 2 {
		result = parts[0]
	}
	// If we have a forwarded-for header, take the address from there
	if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
		addrs := strings.Split(xff, ",")
		lastFwd := addrs[len(addrs)-1]
		if ip := net.ParseIP(lastFwd); ip != nil {
			result = ip.String()
		}
		// parse X-Real-Ip header
	} else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
		if ip := net.ParseIP(xri); ip != nil {
			result = ip.String()
		}
	}
	return
}

func HTTPUploadFileFromRequestForm(r *http.Request, key, dirPath, dir string, filename string) (string, error) {
	var err error

	finalDirPath := filepath.Join(dirPath, dir)

	err = os.MkdirAll(finalDirPath, os.ModePerm)
	if err != nil {
		return "", err
	}

	srcFile, header, err := r.FormFile(key)
	if err != nil {
		return "", err
	}
	defer srcFile.Close()

	fileExt := filepath.Ext(header.Filename)
	if fileExt == "" {
		return "", errors.New("bad_extension")
	}

	dstFile, err := TempFile(finalDirPath, filename + "_*" + fileExt)
	if err != nil {
		return "", err
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return "", err
	}

	newName, err := filepath.Rel(dirPath, dstFile.Name())
	if err != nil {
		return "", err
	}

	return newName, nil
}

func HTTPRespondError(w http.ResponseWriter, code int, err string, detail string, extras ...interface{}) {
	obj := map[string]interface{}{}
	obj["error"] = err
	obj["error_dsc"] = detail
	for i := 0; (i + 1) < len(extras); i += 2 {
		obj[extras[i].(string)] = extras[i+1]
	}
	HTTPRespondJSONObj(w, code, obj)
}

func HTTPRespond400(w http.ResponseWriter, err, detail string, extras ...interface{}) {
	HTTPRespondError(w, 400, err, detail, extras...)
}

func HTTPRespond401(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 401, "unauthorized", detail)
}

func HTTPRespond403(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 403, "permission_denied", detail)
}

func HTTPRespond404(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 404, "not_found", detail)
}
<commit_msg>fix temp<commit_after>package lily

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/cookiejar"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func HTTPSetContentTypeJSON(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
}

func HTTPRespondStr(w http.ResponseWriter, code int, body string) {
	if len(body) == 0 {
		panic("body must be not empty")
	}
	w.WriteHeader(code)
	fmt.Fprint(w, body)
}

func HTTPRespondJSONObj(w http.ResponseWriter, code int, obj interface{}) {
	HTTPSetContentTypeJSON(w)
	w.WriteHeader(code)
	ErrPanic(json.NewEncoder(w).Encode(obj))
}

func HTTPRespondJSONParseError(w http.ResponseWriter) {
	HTTPRespond400(w, "bad_json", "Fail to parse JSON")
}

func HTTPSendRequest(method, url string, data []byte, timeout time.Duration, headers ...string) (*http.Response, error) {
	var err error
	var req *http.Request
	if data != nil {
		req, err = http.NewRequest(method, url, bytes.NewBuffer(data))
		ErrPanic(err)
	} else {
		req, err = http.NewRequest(method, url, nil)
		ErrPanic(err)
	}
	for i := 0; (i + 1) < len(headers); i += 2 {
		req.Header.Set(headers[i], headers[i+1])
	}
	jar, err := cookiejar.New(nil)
	if err != nil {
		return nil, err
	}
	client := &http.Client{
		Timeout: timeout,
		Jar:     jar,
	}
	return client.Do(req)
}

func HTTPSendRequestJSON(method, url string, obj interface{}, timeout time.Duration, headers ...string) (*http.Response, error) {
	var err error
	var data []byte
	if obj != nil {
		data, err = json.Marshal(obj)
		ErrPanic(err)
	}
	headers = append(headers, "Content-Type", "application/json")
	return HTTPSendRequest(method, url, data, timeout, headers...)
}

func HTTPSendJARRequest(jar *cookiejar.Jar, method, url string, data []byte, timeout time.Duration, headers ...string) (*http.Response, *cookiejar.Jar, error) {
	var err error
	var req *http.Request
	if data != nil {
		req, err = http.NewRequest(method, url, bytes.NewBuffer(data))
		ErrPanic(err)
	} else {
		req, err = http.NewRequest(method, url, nil)
		ErrPanic(err)
	}
	for i := 0; (i + 1) < len(headers); i += 2 {
		req.Header.Set(headers[i], headers[i+1])
	}
	if jar == nil {
		jar, err = cookiejar.New(nil)
		if err != nil {
			return nil, nil, err
		}
	}
	client := &http.Client{
		Timeout: timeout,
		Jar:     jar,
	}
	response, err := client.Do(req)
	return response, jar, err
}

func HTTPRetrieveRequestURL(r *http.Request) string {
	scheme := r.Header.Get("X-Forwarded-Proto")
	if scheme == "" {
		if r.TLS == nil {
			scheme = "http"
		} else {
			scheme = "https"
		}
	}
	return scheme + "://" + r.Host
}

func HTTPRetrieveRemoteIP(r *http.Request) (result string) {
	result = ""
	if parts := strings.Split(r.RemoteAddr, ":"); len(parts) == 2 {
		result = parts[0]
	}
	// If we have a forwarded-for header, take the address from there
	if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
		addrs := strings.Split(xff, ",")
		lastFwd := addrs[len(addrs)-1]
		if ip := net.ParseIP(lastFwd); ip != nil {
			result = ip.String()
		}
		// parse X-Real-Ip header
	} else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
		if ip := net.ParseIP(xri); ip != nil {
			result = ip.String()
		}
	}
	return
}

func HTTPUploadFileFromRequestForm(r *http.Request, key, dirPath, dir string, filename string) (string, error) {
	var err error

	finalDirPath := filepath.Join(dirPath, dir)

	err = os.MkdirAll(finalDirPath, os.ModePerm)
	if err != nil {
		return "", err
	}

	srcFile, header, err := r.FormFile(key)
	if err != nil {
		return "", err
	}
	defer srcFile.Close()

	fileExt := filepath.Ext(header.Filename)
	if fileExt == "" {
		return "", errors.New("bad_extension")
	}

	dstFile, err := TempFile(finalDirPath, filename+"_*"+fileExt)
	if err != nil {
		return "", err
	}
	defer dstFile.Close()

	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return "", err
	}

	err = os.Chmod(dstFile.Name(), 0644)
	if err != nil {
		return "", err
	}

	newName, err := filepath.Rel(dirPath, dstFile.Name())
	if err != nil {
		return "", err
	}

	return newName, nil
}

func HTTPRespondError(w http.ResponseWriter, code int, err string, detail string, extras ...interface{}) {
	obj := map[string]interface{}{}
	obj["error"] = err
	obj["error_dsc"] = detail
	for i := 0; (i + 1) < len(extras); i += 2 {
		obj[extras[i].(string)] = extras[i+1]
	}
	HTTPRespondJSONObj(w, code, obj)
}

func HTTPRespond400(w http.ResponseWriter, err, detail string, extras ...interface{}) {
	HTTPRespondError(w, 400, err, detail, extras...)
}

func HTTPRespond401(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 401, "unauthorized", detail)
}

func HTTPRespond403(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 403, "permission_denied", detail)
}

func HTTPRespond404(w http.ResponseWriter, detail string) {
	HTTPRespondError(w, 404, "not_found", detail)
}
<|endoftext|>